Merge ^/head r340918 through r341763.
This commit is contained in:
commit
67350cb56a
@ -2215,6 +2215,8 @@ _basic_bootstrap_tools+=usr.bin/ldd
|
||||
_basic_bootstrap_tools+=usr.sbin/services_mkdb usr.sbin/pwd_mkdb
|
||||
# sysctl/chflags are required for installkernel:
|
||||
_basic_bootstrap_tools+=sbin/sysctl bin/chflags
|
||||
# mkfifo is used by sys/conf/newvers.sh
|
||||
_basic_bootstrap_tools+=usr.bin/mkfifo
|
||||
|
||||
.if ${MK_AMD} != "no"
|
||||
# unifdef is only used by usr.sbin/amd/libamu/Makefile
|
||||
@ -2689,8 +2691,10 @@ _prereq_libs+= gnu/lib/libssp/libssp_nonshared
|
||||
# gnu/lib/csu, gnu/lib/libgcc, lib/csu and lib/libc must be built before
|
||||
# all shared libraries for ELF.
|
||||
#
|
||||
_startup_libs= gnu/lib/csu
|
||||
_startup_libs+= lib/csu
|
||||
_startup_libs= lib/csu
|
||||
.if ${MK_BSD_CRTBEGIN} == "no"
|
||||
_startup_libs+= gnu/lib/csu
|
||||
.endif
|
||||
_startup_libs+= lib/libcompiler_rt
|
||||
_startup_libs+= lib/libc
|
||||
_startup_libs+= lib/libc_nonshared
|
||||
|
@ -203,6 +203,8 @@ OLD_LIBS+=usr/lib32/libcap_pwd.so.0
|
||||
OLD_LIBS+=usr/lib32/libcap_random.so.0
|
||||
OLD_LIBS+=usr/lib32/libcap_dns.so.0
|
||||
OLD_LIBS+=usr/lib32/libcap_syslog.so.0
|
||||
# 20181012: rename of ixlv(4) to iavf(4)
|
||||
OLD_FILES+=usr/share/man/man4/ixlv.4.gz
|
||||
# 20181009: OpenSSL 1.1.1
|
||||
OLD_FILES+=usr/include/openssl/des_old.h
|
||||
OLD_FILES+=usr/include/openssl/dso.h
|
||||
|
13
UPDATING
13
UPDATING
@ -31,6 +31,12 @@ 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".)
|
||||
|
||||
20181126:
|
||||
On amd64, arm64 and armv7 (architectures that install LLVM's ld.lld
|
||||
linker as /usr/bin/ld) GNU ld is no longer installed as ld.bfd, as
|
||||
it produces broken binaries when ifuncs are in use. Users needing
|
||||
GNU ld should install the binutils port or package.
|
||||
|
||||
20181123:
|
||||
The BSD crtbegin and crtend code has been enabled by default. It has
|
||||
had extensive testing on amd64, arm64, and i386. It can be disabled
|
||||
@ -77,6 +83,13 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 13.x IS SLOW:
|
||||
loading from X11 startup. These will become the defaults in 13-current
|
||||
shortly.
|
||||
|
||||
20181012:
|
||||
The ixlv(4) driver has been renamed to iavf(4). As a consequence,
|
||||
custom kernel and module loading configuration files must be updated
|
||||
accordingly. Moreover, interfaces previous presented as ixlvN to the
|
||||
system are now exposed as iavfN and network configuration files must
|
||||
be adjusted as necessary.
|
||||
|
||||
20181009:
|
||||
OpenSSL has been updated to version 1.1.1. This update included
|
||||
additional various API changes througout the base system. It is
|
||||
|
10
bin/dd/dd.c
10
bin/dd/dd.c
@ -511,7 +511,7 @@ void
|
||||
dd_out(int force)
|
||||
{
|
||||
u_char *outp;
|
||||
size_t cnt, i, n;
|
||||
size_t cnt, n;
|
||||
ssize_t nw;
|
||||
static int warned;
|
||||
int sparse;
|
||||
@ -544,12 +544,8 @@ dd_out(int force)
|
||||
do {
|
||||
sparse = 0;
|
||||
if (ddflags & C_SPARSE) {
|
||||
sparse = 1; /* Is buffer sparse? */
|
||||
for (i = 0; i < cnt; i++)
|
||||
if (outp[i] != 0) {
|
||||
sparse = 0;
|
||||
break;
|
||||
}
|
||||
/* Is buffer sparse? */
|
||||
sparse = BISZERO(outp, cnt);
|
||||
}
|
||||
if (sparse && !force) {
|
||||
pending += cnt;
|
||||
|
@ -103,3 +103,7 @@ typedef struct {
|
||||
#define C_PROGRESS 0x40000000
|
||||
|
||||
#define C_PARITY (C_PAREVEN | C_PARODD | C_PARNONE | C_PARSET)
|
||||
|
||||
#define BISZERO(p, s) ((s) > 0 && *((const char *)p) == 0 && !memcmp( \
|
||||
(const void *)(p), (const void *) \
|
||||
((const char *)p + 1), (s) - 1))
|
||||
|
@ -29,7 +29,7 @@
|
||||
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
.\" POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd June 5, 2017
|
||||
.Dd December 3, 2018
|
||||
.Dt PKILL 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -221,7 +221,7 @@ This option is valid only when given as the first argument to
|
||||
.Pp
|
||||
If any
|
||||
.Ar pattern
|
||||
operands are specified, they are used as regular expressions to match
|
||||
operands are specified, they are used as extended regular expressions to match
|
||||
the command name or full argument list of each process.
|
||||
If the
|
||||
.Fl f
|
||||
@ -241,6 +241,18 @@ or
|
||||
.Nm pkill
|
||||
process will never consider itself nor system processes (kernel threads) as
|
||||
a potential match.
|
||||
.Sh IMPLEMENTATION NOTES
|
||||
The Sun Solaris implementation utilised procfs to obtain process information.
|
||||
This implementation utilises
|
||||
.Xr kvm 3
|
||||
instead.
|
||||
On a live system,
|
||||
.Xr kvm 3
|
||||
uses
|
||||
.Va kern.proc
|
||||
MIB to obtain the list of processes, kernel memory through
|
||||
.Pa /dev/kmem
|
||||
is not accessed.
|
||||
.Sh EXIT STATUS
|
||||
The
|
||||
.Nm pgrep
|
||||
@ -277,6 +289,7 @@ is deprecated, and its use is discouraged in favor of
|
||||
.Xr flock 2 ,
|
||||
.Xr kill 2 ,
|
||||
.Xr sigaction 2 ,
|
||||
.Xr kvm 3 ,
|
||||
.Xr pidfile 3 ,
|
||||
.Xr re_format 7
|
||||
.\" Xr signal 7
|
||||
|
@ -623,10 +623,11 @@ static const char *
|
||||
subevalvar_misc(const char *p, struct nodelist **restrict argbackq,
|
||||
const char *var, int subtype, int startloc, int varflags)
|
||||
{
|
||||
const char *end;
|
||||
char *startp;
|
||||
int amount;
|
||||
|
||||
p = argstr(p, argbackq, EXP_TILDE, NULL);
|
||||
end = argstr(p, argbackq, EXP_TILDE, NULL);
|
||||
STACKSTRNUL(expdest);
|
||||
startp = stackblock() + startloc;
|
||||
|
||||
@ -635,7 +636,7 @@ subevalvar_misc(const char *p, struct nodelist **restrict argbackq,
|
||||
setvar(var, startp, 0);
|
||||
amount = startp - expdest;
|
||||
STADJUST(amount, expdest);
|
||||
return p;
|
||||
return end;
|
||||
|
||||
case VSQUESTION:
|
||||
if (*p != CTLENDVAR) {
|
||||
|
@ -359,12 +359,16 @@ popstring(void)
|
||||
void
|
||||
setinputfile(const char *fname, int push)
|
||||
{
|
||||
int e;
|
||||
int fd;
|
||||
int fd2;
|
||||
|
||||
INTOFF;
|
||||
if ((fd = open(fname, O_RDONLY | O_CLOEXEC)) < 0)
|
||||
error("cannot open %s: %s", fname, strerror(errno));
|
||||
if ((fd = open(fname, O_RDONLY | O_CLOEXEC)) < 0) {
|
||||
e = errno;
|
||||
errorwithstatus(e == ENOENT || e == ENOTDIR ? 127 : 126,
|
||||
"cannot open %s: %s", fname, strerror(e));
|
||||
}
|
||||
if (fd < 10) {
|
||||
fd2 = fcntl(fd, F_DUPFD_CLOEXEC, 10);
|
||||
close(fd);
|
||||
|
12
bin/sh/sh.1
12
bin/sh/sh.1
@ -32,7 +32,7 @@
|
||||
.\" from: @(#)sh.1 8.6 (Berkeley) 5/4/95
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd July 19, 2018
|
||||
.Dd December 8, 2018
|
||||
.Dt SH 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -2485,8 +2485,8 @@ lines, suitable for re-input to the shell.
|
||||
See the
|
||||
.Sx Functions
|
||||
subsection.
|
||||
.It Ic set Oo Fl /+abCEefIimnpTuVvx Oc Oo Fl /+o Ar longname Oc Oo
|
||||
.Fl c Ar string Oc Op Fl - Ar arg ...
|
||||
.It Ic set Oo Fl /+abCEefIimnpTuVvx Oc Oo Fl /+o Ar longname
|
||||
.Oc Op Fl - Ar arg ...
|
||||
The
|
||||
.Ic set
|
||||
command performs three different functions:
|
||||
@ -2819,7 +2819,11 @@ Shell database.
|
||||
Privileged shell profile.
|
||||
.El
|
||||
.Sh EXIT STATUS
|
||||
Errors that are detected by the shell, such as a syntax error, will
|
||||
If the
|
||||
.Ar script
|
||||
cannot be found, the exit status will be 127;
|
||||
if it cannot be opened for another reason, the exit status will be 126.
|
||||
Other errors that are detected by the shell, such as a syntax error, will
|
||||
cause the shell to exit with a non-zero exit status.
|
||||
If the shell is not an interactive shell, the execution of the shell
|
||||
file will be aborted.
|
||||
|
@ -30,6 +30,7 @@ ${PACKAGE}FILES+= redirection-error5.0
|
||||
${PACKAGE}FILES+= redirection-error6.0
|
||||
${PACKAGE}FILES+= redirection-error7.0
|
||||
${PACKAGE}FILES+= redirection-error8.0
|
||||
${PACKAGE}FILES+= script-error1.0
|
||||
${PACKAGE}FILES+= write-error1.0
|
||||
|
||||
.include <bsd.test.mk>
|
||||
|
5
bin/sh/tests/errors/script-error1.0
Normal file
5
bin/sh/tests/errors/script-error1.0
Normal file
@ -0,0 +1,5 @@
|
||||
# $FreeBSD$
|
||||
|
||||
{ stderr=$(${SH} /var/empty/nosuchscript 2>&1 >&3); } 3>&1
|
||||
r=$?
|
||||
[ -n "$stderr" ] && [ "$r" = 127 ]
|
@ -86,6 +86,7 @@ ${PACKAGE}FILES+= plus-minus7.0
|
||||
${PACKAGE}FILES+= plus-minus8.0
|
||||
${PACKAGE}FILES+= plus-minus9.0
|
||||
${PACKAGE}FILES+= question1.0
|
||||
${PACKAGE}FILES+= question2.0
|
||||
${PACKAGE}FILES+= readonly1.0
|
||||
${PACKAGE}FILES+= redir1.0
|
||||
${PACKAGE}FILES+= set-u1.0
|
||||
|
11
bin/sh/tests/expansion/question2.0
Normal file
11
bin/sh/tests/expansion/question2.0
Normal file
@ -0,0 +1,11 @@
|
||||
# $FreeBSD$
|
||||
|
||||
unset dummyvar
|
||||
msg=`(: ${dummyvar?}) 2>&1`
|
||||
r=$?
|
||||
[ "$r" != 0 ] && case $msg in
|
||||
*dummyvar?* | *?dummyvar*) : ;;
|
||||
*)
|
||||
printf 'Bad message: [%s]\n' "$msg"
|
||||
exit 1
|
||||
esac
|
@ -1,3 +1,14 @@
|
||||
2018-09-21 Simon J. Gerraty <sjg@bad.crufty.net>
|
||||
|
||||
* VERSION: 20180919
|
||||
Merge with NetBSD make, pick up
|
||||
o var.c: add :q
|
||||
o dir.c: cleanup caching of stats
|
||||
|
||||
2018-09-21 Simon J Gerraty <sjg@beast.crufty.net>
|
||||
|
||||
* Makefile.config.in: use += where it makes sense.
|
||||
|
||||
2018-05-12 Simon J. Gerraty <sjg@bad.crufty.net>
|
||||
|
||||
* VERSION: 20180512
|
||||
|
@ -163,6 +163,8 @@ unit-tests/varcmd.exp
|
||||
unit-tests/varcmd.mk
|
||||
unit-tests/varmisc.exp
|
||||
unit-tests/varmisc.mk
|
||||
unit-tests/varquote.exp
|
||||
unit-tests/varquote.mk
|
||||
unit-tests/varshell.exp
|
||||
unit-tests/varshell.mk
|
||||
util.c
|
||||
|
@ -1,6 +1,6 @@
|
||||
# things set by configure
|
||||
|
||||
_MAKE_VERSION=@_MAKE_VERSION@
|
||||
_MAKE_VERSION?=@_MAKE_VERSION@
|
||||
|
||||
prefix?= @prefix@
|
||||
srcdir= @srcdir@
|
||||
@ -11,9 +11,9 @@ DEFAULT_SYS_PATH?= @default_sys_path@
|
||||
|
||||
CPPFLAGS+= @CPPFLAGS@
|
||||
CFLAGS+= ${CPPFLAGS} @DEFS@
|
||||
LDFLAGS= @LDFLAGS@
|
||||
LIBOBJS= @LIBOBJS@
|
||||
LDADD= @LIBS@
|
||||
LDFLAGS+= @LDFLAGS@
|
||||
LIBOBJS+= @LIBOBJS@
|
||||
LDADD+= @LIBS@
|
||||
USE_META= @use_meta@
|
||||
FILEMON_H?= @filemon_h@
|
||||
BMAKE_PATH_MAX?= @bmake_path_max@
|
||||
|
@ -1,2 +1,2 @@
|
||||
# keep this compatible with sh and make
|
||||
_MAKE_VERSION=20180512
|
||||
_MAKE_VERSION=20180919
|
||||
|
@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: make.1,v 1.272 2018/04/02 04:26:17 dholland Exp $
|
||||
.\" $NetBSD: make.1,v 1.273 2018/05/27 01:14:51 christos Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1990, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
@ -29,7 +29,7 @@
|
||||
.\"
|
||||
.\" from: @(#)make.1 8.4 (Berkeley) 3/19/94
|
||||
.\"
|
||||
.Dd June 22, 2017
|
||||
.Dd May 26, 2018
|
||||
.Dt BMAKE 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -1227,8 +1227,15 @@ due uno quattro tre
|
||||
.Ed
|
||||
.It Cm \&:Q
|
||||
Quotes every shell meta-character in the variable, so that it can be passed
|
||||
safely to the shell.
|
||||
.It Cm \&:q
|
||||
Quotes every shell meta-character in the variable, and also doubles
|
||||
.Sq $
|
||||
characters so that it can be passed
|
||||
safely through recursive invocations of
|
||||
.Nm .
|
||||
This is equivalent to:
|
||||
.Sq \&:S/\e\&$/&&/g:Q .
|
||||
.It Cm \&:R
|
||||
Replaces each word in the variable with everything but its suffix.
|
||||
.It Cm \&:range[=count]
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: dir.c,v 1.71 2017/04/16 21:14:47 riastradh Exp $ */
|
||||
/* $NetBSD: dir.c,v 1.73 2018/07/12 18:03:31 christos Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
||||
@ -70,14 +70,14 @@
|
||||
*/
|
||||
|
||||
#ifndef MAKE_NATIVE
|
||||
static char rcsid[] = "$NetBSD: dir.c,v 1.71 2017/04/16 21:14:47 riastradh Exp $";
|
||||
static char rcsid[] = "$NetBSD: dir.c,v 1.73 2018/07/12 18:03:31 christos Exp $";
|
||||
#else
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)dir.c 8.2 (Berkeley) 1/2/94";
|
||||
#else
|
||||
__RCSID("$NetBSD: dir.c,v 1.71 2017/04/16 21:14:47 riastradh Exp $");
|
||||
__RCSID("$NetBSD: dir.c,v 1.73 2018/07/12 18:03:31 christos Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
#endif
|
||||
@ -268,15 +268,6 @@ struct cache_st {
|
||||
};
|
||||
|
||||
/* minimize changes below */
|
||||
static time_t
|
||||
Hash_GetTimeValue(Hash_Entry *entry)
|
||||
{
|
||||
struct cache_st *cst;
|
||||
|
||||
cst = entry->clientPtr;
|
||||
return cst->mtime;
|
||||
}
|
||||
|
||||
#define CST_LSTAT 1
|
||||
#define CST_UPDATE 2
|
||||
|
||||
@ -298,6 +289,10 @@ cached_stats(Hash_Table *htp, const char *pathname, struct stat *st, int flags)
|
||||
memset(st, 0, sizeof(*st));
|
||||
st->st_mtime = cst->mtime;
|
||||
st->st_mode = cst->mode;
|
||||
if (DEBUG(DIR)) {
|
||||
fprintf(debug_file, "Using cached time %s for %s\n",
|
||||
Targ_FmtTime(st->st_mtime), pathname);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -315,6 +310,10 @@ cached_stats(Hash_Table *htp, const char *pathname, struct stat *st, int flags)
|
||||
cst = entry->clientPtr;
|
||||
cst->mtime = st->st_mtime;
|
||||
cst->mode = st->st_mode;
|
||||
if (DEBUG(DIR)) {
|
||||
fprintf(debug_file, " Caching %s for %s\n",
|
||||
Targ_FmtTime(st->st_mtime), pathname);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -995,14 +994,6 @@ DirLookupSubdir(Path *p, const char *name)
|
||||
}
|
||||
|
||||
if (cached_stat(file, &stb) == 0) {
|
||||
/*
|
||||
* Save the modification time so if it's needed, we don't have
|
||||
* to fetch it again.
|
||||
*/
|
||||
if (DEBUG(DIR)) {
|
||||
fprintf(debug_file, " Caching %s for %s\n", Targ_FmtTime(stb.st_mtime),
|
||||
file);
|
||||
}
|
||||
nearmisses += 1;
|
||||
return (file);
|
||||
}
|
||||
@ -1134,7 +1125,6 @@ Dir_FindFile(const char *name, Lst path)
|
||||
Boolean hasLastDot = FALSE; /* true we should search dot last */
|
||||
Boolean hasSlash; /* true if 'name' contains a / */
|
||||
struct stat stb; /* Buffer for stat, if necessary */
|
||||
Hash_Entry *entry; /* Entry for mtimes table */
|
||||
const char *trailing_dot = ".";
|
||||
|
||||
/*
|
||||
@ -1395,24 +1385,14 @@ Dir_FindFile(const char *name, Lst path)
|
||||
}
|
||||
|
||||
bigmisses += 1;
|
||||
entry = Hash_FindEntry(&mtimes, name);
|
||||
if (entry != NULL) {
|
||||
if (DEBUG(DIR)) {
|
||||
fprintf(debug_file, " got it (in mtime cache)\n");
|
||||
}
|
||||
return(bmake_strdup(name));
|
||||
} else if (cached_stat(name, &stb) == 0) {
|
||||
if (DEBUG(DIR)) {
|
||||
fprintf(debug_file, " Caching %s for %s\n", Targ_FmtTime(stb.st_mtime),
|
||||
name);
|
||||
}
|
||||
if (cached_stat(name, &stb) == 0) {
|
||||
return (bmake_strdup(name));
|
||||
} else {
|
||||
if (DEBUG(DIR)) {
|
||||
fprintf(debug_file, " failed. Returning NULL\n");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (DEBUG(DIR)) {
|
||||
fprintf(debug_file, " failed. Returning NULL\n");
|
||||
}
|
||||
return NULL;
|
||||
#endif /* notdef */
|
||||
}
|
||||
|
||||
@ -1518,7 +1498,6 @@ Dir_MTime(GNode *gn, Boolean recheck)
|
||||
{
|
||||
char *fullName; /* the full pathname of name */
|
||||
struct stat stb; /* buffer for finding the mod time */
|
||||
Hash_Entry *entry;
|
||||
|
||||
if (gn->type & OP_ARCHV) {
|
||||
return Arch_MTime(gn);
|
||||
@ -1569,17 +1548,7 @@ Dir_MTime(GNode *gn, Boolean recheck)
|
||||
fullName = bmake_strdup(gn->name);
|
||||
}
|
||||
|
||||
if (!recheck)
|
||||
entry = Hash_FindEntry(&mtimes, fullName);
|
||||
else
|
||||
entry = NULL;
|
||||
if (entry != NULL) {
|
||||
stb.st_mtime = Hash_GetTimeValue(entry);
|
||||
if (DEBUG(DIR)) {
|
||||
fprintf(debug_file, "Using cached time %s for %s\n",
|
||||
Targ_FmtTime(stb.st_mtime), fullName);
|
||||
}
|
||||
} else if (cached_stats(&mtimes, fullName, &stb, recheck ? CST_UPDATE : 0) < 0) {
|
||||
if (cached_stats(&mtimes, fullName, &stb, recheck ? CST_UPDATE : 0) < 0) {
|
||||
if (gn->type & OP_MEMBER) {
|
||||
if (fullName != gn->path)
|
||||
free(fullName);
|
||||
|
@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: make.1,v 1.272 2018/04/02 04:26:17 dholland Exp $
|
||||
.\" $NetBSD: make.1,v 1.273 2018/05/27 01:14:51 christos Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1990, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
@ -29,7 +29,7 @@
|
||||
.\"
|
||||
.\" from: @(#)make.1 8.4 (Berkeley) 3/19/94
|
||||
.\"
|
||||
.Dd September 27, 2018
|
||||
.Dd December 5, 2018
|
||||
.Dt MAKE 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -1238,8 +1238,15 @@ due uno quattro tre
|
||||
.Ed
|
||||
.It Cm \&:Q
|
||||
Quotes every shell meta-character in the variable, so that it can be passed
|
||||
safely to the shell.
|
||||
.It Cm \&:q
|
||||
Quotes every shell meta-character in the variable, and also doubles
|
||||
.Sq $
|
||||
characters so that it can be passed
|
||||
safely through recursive invocations of
|
||||
.Nm .
|
||||
This is equivalent to:
|
||||
.Sq \&:S/\e\&$/&&/g:Q .
|
||||
.It Cm \&:R
|
||||
Replaces each word in the variable with everything but its suffix.
|
||||
.It Cm \&:range[=count]
|
||||
|
@ -1,3 +1,25 @@
|
||||
2018-09-19 Simon J Gerraty <sjg@beast.crufty.net>
|
||||
|
||||
* install-mk (MK_VERSION): 20180919
|
||||
|
||||
* dirdeps-options.mk: .undef cannot handle var that expands to
|
||||
more than one var.
|
||||
|
||||
2018-07-08 Simon J Gerraty <sjg@beast.crufty.net>
|
||||
|
||||
* meta.stage.mk: allow wildcards in STAGE_FILES.* etc.
|
||||
|
||||
2018-06-01 Simon J Gerraty <sjg@beast.crufty.net>
|
||||
|
||||
* meta.autodep.mk: export META_FILES to avoid command line limit
|
||||
* gendirdeps.mk: if we have lots of .meta files put them in
|
||||
an @list
|
||||
|
||||
2018-05-28 Simon J Gerraty <sjg@beast.crufty.net>
|
||||
|
||||
* dirdeps-options.mk: use local.dirdeps-options.mk
|
||||
not local.dirdeps-option.mk
|
||||
|
||||
2018-04-20 Simon J Gerraty <sjg@beast.crufty.net>
|
||||
|
||||
* install-mk (MK_VERSION): 20180420
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $Id: dirdeps-options.mk,v 1.5 2018/04/18 15:53:57 sjg Exp $
|
||||
# $Id: dirdeps-options.mk,v 1.9 2018/09/20 00:07:19 sjg Exp $
|
||||
#
|
||||
# @(#) Copyright (c) 2018, Simon J. Gerraty
|
||||
#
|
||||
@ -25,7 +25,7 @@
|
||||
# If a Makefile.depend.options file exists, it will be included by
|
||||
# dirdeps.mk and meta.autodep.mk
|
||||
#
|
||||
# We include local.dirdeps-option.mk which may also define DIRDEPS.*
|
||||
# We include local.dirdeps-options.mk which may also define DIRDEPS.*
|
||||
# for options.
|
||||
#
|
||||
# Thus a directory, that is affected by an option FOO would have
|
||||
@ -35,7 +35,7 @@
|
||||
# DIRDEPS.FOO.yes
|
||||
# DIRDEPS.FOO.no
|
||||
# to whatever applies for that dir, or it can rely on globals
|
||||
# set in local.dirdeps-option.mk
|
||||
# set in local.dirdeps-options.mk
|
||||
# Either way, we will .undef DIRDEPS.* when done.
|
||||
|
||||
# This should have been set by Makefile.depend.options
|
||||
@ -43,7 +43,7 @@
|
||||
DIRDEPS_OPTIONS ?=
|
||||
|
||||
# pickup any DIRDEPS.* we need
|
||||
.-include <local.dirdeps-option.mk>
|
||||
.-include <local.dirdeps-options.mk>
|
||||
|
||||
.if ${.MAKE.LEVEL} == 0
|
||||
# :U below avoids potential errors when we :=
|
||||
@ -52,7 +52,10 @@ DIRDEPS += ${DIRDEPS.$o.${MK_$o:U}:U}
|
||||
.endfor
|
||||
DIRDEPS := ${DIRDEPS:O:u}
|
||||
# avoid cross contamination
|
||||
.undef ${DIRDEPS_OPTIONS:tu:@o@DIRDEPS.$o.yes DIRDEPS.$o.no@}
|
||||
.for o in ${DIRDEPS_OPTIONS:tu}
|
||||
.undef DIRDEPS.$o.yes
|
||||
.undef DIRDEPS.$o.no
|
||||
.endfor
|
||||
.else
|
||||
# whether options are enabled or not,
|
||||
# we want to filter out the relevant DIRDEPS.*
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $Id: dirdeps.mk,v 1.95 2018/04/23 17:53:56 sjg Exp $
|
||||
# $Id: dirdeps.mk,v 1.96 2018/06/20 22:26:39 sjg Exp $
|
||||
|
||||
# Copyright (c) 2010-2013, Juniper Networks, Inc.
|
||||
# All rights reserved.
|
||||
@ -731,6 +731,8 @@ DIRDEPS =
|
||||
.info loading ${_m} for ${d:E}
|
||||
.endif
|
||||
.include <${_m}>
|
||||
.else
|
||||
.-include <local.dirdeps-missing.mk>
|
||||
.endif
|
||||
.endif
|
||||
.endif
|
||||
@ -746,7 +748,7 @@ DIRDEPS =
|
||||
DEP_RELDIR := ${RELDIR}
|
||||
_DEP_RELDIR := ${RELDIR}
|
||||
# Since we are/should be included by .MAKE.DEPENDFILE
|
||||
# is is a final opportunity to add/hook global rules.
|
||||
# This is a final opportunity to add/hook global rules.
|
||||
.-include <local.dirdeps-build.mk>
|
||||
|
||||
# pickup local dependencies
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $Id: gendirdeps.mk,v 1.38 2018/03/10 00:53:52 sjg Exp $
|
||||
# $Id: gendirdeps.mk,v 1.39 2018/06/08 01:25:31 sjg Exp $
|
||||
|
||||
# Copyright (c) 2010-2013, Juniper Networks, Inc.
|
||||
# All rights reserved.
|
||||
@ -171,11 +171,27 @@ GENDIRDEPS_SEDCMDS += \
|
||||
# we canonicalize them to keep things simple
|
||||
# if we are using a split-fs sandbox, it gets a little messier.
|
||||
_objtop := ${_OBJTOP:tA}
|
||||
|
||||
# some people put *.meta in META_XTRAS to make sure we get here
|
||||
_meta_files := ${META_FILES:N\*.meta:O:u}
|
||||
# assume a big list
|
||||
_meta_files_arg= @meta.list
|
||||
.if empty(_meta_files) && ${META_FILES:M\*.meta} != ""
|
||||
# XXX this should be considered a bad idea,
|
||||
# since we cannot ignore stale .meta
|
||||
x != cd ${_OBJDIR} && find . -name '*.meta' -print -o \( -type d ! -name . -prune \) | sed 's,^./,,' > meta.list; echo
|
||||
.elif ${_meta_files:[#]} > 500
|
||||
.export _meta_files
|
||||
x != echo; for m in $$_meta_files; do echo $$m; done > meta.list
|
||||
.else
|
||||
_meta_files_arg:= ${_meta_files}
|
||||
.endif
|
||||
|
||||
dir_list != cd ${_OBJDIR} && \
|
||||
${META2DEPS_CMD} MACHINE=${MACHINE} \
|
||||
SRCTOP=${SRCTOP} RELDIR=${RELDIR} CURDIR=${_CURDIR} \
|
||||
${META2DEPS_ARGS} \
|
||||
${META_FILES:O:u} | ${META2DEPS_FILTER} ${_skip_gendirdeps} \
|
||||
${_meta_files_arg} | ${META2DEPS_FILTER} ${_skip_gendirdeps} \
|
||||
sed ${GENDIRDEPS_SEDCMDS}
|
||||
|
||||
.if ${dir_list:M*ERROR\:*} != ""
|
||||
|
@ -55,7 +55,7 @@
|
||||
# Simon J. Gerraty <sjg@crufty.net>
|
||||
|
||||
# RCSid:
|
||||
# $Id: install-mk,v 1.156 2018/04/22 04:42:47 sjg Exp $
|
||||
# $Id: install-mk,v 1.160 2018/09/20 00:07:19 sjg Exp $
|
||||
#
|
||||
# @(#) Copyright (c) 1994 Simon J. Gerraty
|
||||
#
|
||||
@ -70,7 +70,7 @@
|
||||
# sjg@crufty.net
|
||||
#
|
||||
|
||||
MK_VERSION=20180420
|
||||
MK_VERSION=20180919
|
||||
OWNER=
|
||||
GROUP=
|
||||
MODE=444
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $Id: meta.autodep.mk,v 1.48 2018/04/15 06:30:04 sjg Exp $
|
||||
# $Id: meta.autodep.mk,v 1.50 2018/06/08 01:25:31 sjg Exp $
|
||||
|
||||
#
|
||||
# @(#) Copyright (c) 2010, Simon J. Gerraty
|
||||
@ -20,9 +20,11 @@ __${_this}__: .NOTMAIN
|
||||
|
||||
.-include <local.autodep.mk>
|
||||
|
||||
PICO?= .pico
|
||||
|
||||
.if defined(SRCS)
|
||||
# it would be nice to be able to query .SUFFIXES
|
||||
OBJ_EXTENSIONS+= .o .po .lo .So
|
||||
OBJ_EXTENSIONS+= .o .po .lo ${PICO}
|
||||
|
||||
# explicit dependencies help short-circuit .SUFFIX searches
|
||||
SRCS_DEP_FILTER+= N*.[hly]
|
||||
@ -178,7 +180,7 @@ DEPEND_SUFFIXES += .c .h .cpp .hpp .cxx .hxx .cc .hh
|
||||
@case "${.MAKE.META.FILES:T:M*.po.*}" in \
|
||||
*.po.*) mv $@.${.MAKE.PID} $@;; \
|
||||
*) { cat $@.${.MAKE.PID}; \
|
||||
sed 's,\.So:,.o:,;s,\.o:,.po:,' $@.${.MAKE.PID}; } | sort -u > $@; \
|
||||
sed 's,\${PICO}:,.o:,;s,\.o:,.po:,' $@.${.MAKE.PID}; } | sort -u > $@; \
|
||||
rm -f $@.${.MAKE.PID};; \
|
||||
esac
|
||||
.else
|
||||
@ -243,7 +245,7 @@ META_FILES = *.meta
|
||||
.elif ${OPTIMIZE_OBJECT_META_FILES:Uno:tl} == "no"
|
||||
META_FILES = ${.MAKE.META.FILES:T:N.depend*:O:u}
|
||||
.else
|
||||
# if we have 1000's of .o.meta, .So.meta etc we need only look at one set
|
||||
# if we have 1000's of .o.meta, ${PICO}.meta etc we need only look at one set
|
||||
# it is left as an exercise for the reader to work out what this does
|
||||
META_FILES = ${.MAKE.META.FILES:T:N.depend*:N*o.meta:O:u} \
|
||||
${.MAKE.META.FILES:T:M*.${.MAKE.META.FILES:M*o.meta:R:E:O:u:[1]}.meta:O:u}
|
||||
@ -260,6 +262,9 @@ META_FILES = ${.MAKE.META.FILES:T:N.depend*:N*o.meta:O:u} \
|
||||
.if !empty(GENDIRDEPS_FILTER)
|
||||
.export GENDIRDEPS_FILTER
|
||||
.endif
|
||||
# export to avoid blowing command line limit
|
||||
META_FILES := ${META_XTRAS:U:O:u} ${META_FILES:U:T:O:u:${META_FILE_FILTER:ts:}}
|
||||
.export META_FILES
|
||||
.endif
|
||||
|
||||
# we might have .../ in MAKESYSPATH
|
||||
@ -270,8 +275,7 @@ ${_DEPENDFILE}: ${_depend} ${.PARSEDIR}/gendirdeps.mk ${META2DEPS} $${.MAKE.MET
|
||||
SKIP_GENDIRDEPS='${SKIP_GENDIRDEPS:O:u}' \
|
||||
DPADD='${FORCE_DPADD:O:u}' ${_gendirdeps_mutex} \
|
||||
MAKESYSPATH=${_makesyspath} \
|
||||
${.MAKE} -f gendirdeps.mk RELDIR=${RELDIR} _DEPENDFILE=${_DEPENDFILE} \
|
||||
META_FILES='${META_XTRAS:O:u} ${META_FILES:T:O:u:${META_FILE_FILTER:ts:}}')
|
||||
${.MAKE} -f gendirdeps.mk RELDIR=${RELDIR} _DEPENDFILE=${_DEPENDFILE})
|
||||
@test -s $@ && touch $@; :
|
||||
.endif
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $Id: meta.stage.mk,v 1.55 2017/10/27 01:17:09 sjg Exp $
|
||||
# $Id: meta.stage.mk,v 1.56 2018/07/08 17:12:54 sjg Exp $
|
||||
#
|
||||
# @(#) Copyright (c) 2011-2017, Simon J. Gerraty
|
||||
#
|
||||
@ -141,7 +141,7 @@ _STAGE_AS_BASENAME_USE: .USE .dirdep ${.TARGET:T}
|
||||
|
||||
.if !empty(STAGE_INCSDIR)
|
||||
.if !empty(STAGE_INCS)
|
||||
stage_incs: ${STAGE_INCS}
|
||||
stage_incs: ${STAGE_INCS:N*\**}
|
||||
.endif
|
||||
.if target(stage_incs) || !empty(.ALLTARGETS:Mstage_includes)
|
||||
STAGE_TARGETS += stage_incs
|
||||
@ -156,7 +156,7 @@ stage_incs: .dirdep
|
||||
|
||||
.if !empty(STAGE_LIBDIR)
|
||||
.if !empty(STAGE_LIBS)
|
||||
stage_libs: ${STAGE_LIBS}
|
||||
stage_libs: ${STAGE_LIBS:N*\**}
|
||||
.endif
|
||||
.if target(stage_libs)
|
||||
STAGE_TARGETS += stage_libs
|
||||
@ -191,7 +191,7 @@ CLEANFILES += ${STAGE_SETS:@s@stage*$s@}
|
||||
# some makefiles need to populate multiple directories
|
||||
.for s in ${STAGE_SETS:O:u}
|
||||
.if !empty(STAGE_FILES.$s)
|
||||
stage_files.$s: ${STAGE_FILES.$s}
|
||||
stage_files.$s: ${STAGE_FILES.$s:N*\**}
|
||||
.endif
|
||||
.if target(stage_files.$s) || target(stage_files${s:S,^,.,:N._default})
|
||||
STAGE_TARGETS += stage_files
|
||||
@ -262,7 +262,7 @@ CLEANFILES += ${STAGE_AS_SETS:@s@stage*$s@}
|
||||
# both operations happen together
|
||||
.for s in ${STAGE_AS_SETS:O:u}
|
||||
.if !empty(STAGE_AS.$s)
|
||||
stage_as.$s: ${STAGE_AS.$s}
|
||||
stage_as.$s: ${STAGE_AS.$s:N*\**}
|
||||
.endif
|
||||
.if target(stage_as.$s)
|
||||
STAGE_TARGETS += stage_as
|
||||
@ -277,7 +277,7 @@ stage_as.$s: .dirdep
|
||||
.endif
|
||||
|
||||
.if !empty(STAGE_AS_AND_SYMLINK.$s)
|
||||
stage_as_and_symlink.$s: ${STAGE_AS_AND_SYMLINK.$s}
|
||||
stage_as_and_symlink.$s: ${STAGE_AS_AND_SYMLINK.$s:N*\**}
|
||||
.endif
|
||||
.if target(stage_as_and_symlink.$s)
|
||||
STAGE_TARGETS += stage_as_and_symlink
|
||||
|
@ -1,6 +1,6 @@
|
||||
# $Id: Makefile.in,v 1.48 2015/12/07 04:06:29 sjg Exp $
|
||||
# $Id: Makefile.in,v 1.49 2018/09/21 21:39:05 sjg Exp $
|
||||
#
|
||||
# $NetBSD: Makefile,v 1.52 2015/05/05 21:51:09 sjg Exp $
|
||||
# $NetBSD: Makefile,v 1.53 2018/05/24 00:25:44 christos Exp $
|
||||
#
|
||||
# Unit tests for make(1)
|
||||
# The main targets are:
|
||||
@ -54,6 +54,7 @@ TESTNAMES= \
|
||||
unexport-env \
|
||||
varcmd \
|
||||
varmisc \
|
||||
varquote \
|
||||
varshell
|
||||
|
||||
# these tests were broken by referting POSIX chanegs
|
||||
|
3
contrib/bmake/unit-tests/varquote.exp
Normal file
3
contrib/bmake/unit-tests/varquote.exp
Normal file
@ -0,0 +1,3 @@
|
||||
-fdebug-prefix-map=$NETBSDSRCDIR=/usr/src -fdebug-regex-map=/usr/src/(.*)/obj$=/usr/obj/\1
|
||||
-fdebug-prefix-map=$NETBSDSRCDIR=/usr/src -fdebug-regex-map=/usr/src/(.*)/obj$=/usr/obj/\1
|
||||
exit status 0
|
14
contrib/bmake/unit-tests/varquote.mk
Normal file
14
contrib/bmake/unit-tests/varquote.mk
Normal file
@ -0,0 +1,14 @@
|
||||
# $NetBSD: varquote.mk,v 1.2 2018/05/27 01:14:51 christos Exp $
|
||||
#
|
||||
# Test VAR:q modifier
|
||||
|
||||
.if !defined(REPROFLAGS)
|
||||
REPROFLAGS+= -fdebug-prefix-map=\$$NETBSDSRCDIR=/usr/src
|
||||
REPROFLAGS+= -fdebug-regex-map='/usr/src/(.*)/obj$$=/usr/obj/\1'
|
||||
all:
|
||||
@${MAKE} -f ${MAKEFILE} REPROFLAGS=${REPROFLAGS:S/\$/&&/g:Q}
|
||||
@${MAKE} -f ${MAKEFILE} REPROFLAGS=${REPROFLAGS:q}
|
||||
.else
|
||||
all:
|
||||
@echo ${REPROFLAGS}
|
||||
.endif
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: var.c,v 1.218 2018/02/18 00:52:42 sjg Exp $ */
|
||||
/* $NetBSD: var.c,v 1.220 2018/05/27 01:14:51 christos Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1988, 1989, 1990, 1993
|
||||
@ -69,14 +69,14 @@
|
||||
*/
|
||||
|
||||
#ifndef MAKE_NATIVE
|
||||
static char rcsid[] = "$NetBSD: var.c,v 1.218 2018/02/18 00:52:42 sjg Exp $";
|
||||
static char rcsid[] = "$NetBSD: var.c,v 1.220 2018/05/27 01:14:51 christos Exp $";
|
||||
#else
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94";
|
||||
#else
|
||||
__RCSID("$NetBSD: var.c,v 1.218 2018/02/18 00:52:42 sjg Exp $");
|
||||
__RCSID("$NetBSD: var.c,v 1.220 2018/05/27 01:14:51 christos Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
#endif
|
||||
@ -324,7 +324,7 @@ static Boolean VarLoopExpand(GNode *, Var_Parse_State *,
|
||||
static char *VarGetPattern(GNode *, Var_Parse_State *,
|
||||
int, const char **, int, int *, int *,
|
||||
VarPattern *);
|
||||
static char *VarQuote(char *);
|
||||
static char *VarQuote(char *, Boolean);
|
||||
static char *VarHash(char *);
|
||||
static char *VarModify(GNode *, Var_Parse_State *,
|
||||
const char *,
|
||||
@ -2315,6 +2315,7 @@ VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED,
|
||||
*-----------------------------------------------------------------------
|
||||
* VarQuote --
|
||||
* Quote shell meta-characters and space characters in the string
|
||||
* if quoteDollar is set, also quote and double any '$' characters.
|
||||
*
|
||||
* Results:
|
||||
* The quoted string
|
||||
@ -2325,7 +2326,7 @@ VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED,
|
||||
*-----------------------------------------------------------------------
|
||||
*/
|
||||
static char *
|
||||
VarQuote(char *str)
|
||||
VarQuote(char *str, Boolean quoteDollar)
|
||||
{
|
||||
|
||||
Buffer buf;
|
||||
@ -2346,6 +2347,8 @@ VarQuote(char *str)
|
||||
if (isspace((unsigned char)*str) || ismeta((unsigned char)*str))
|
||||
Buf_AddByte(&buf, '\\');
|
||||
Buf_AddByte(&buf, *str);
|
||||
if (quoteDollar && *str == '$')
|
||||
Buf_AddBytes(&buf, 2, "\\$");
|
||||
}
|
||||
|
||||
str = Buf_Destroy(&buf, FALSE);
|
||||
@ -3485,9 +3488,10 @@ ApplyModifiers(char *nstr, const char *tstr,
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case 'q':
|
||||
case 'Q':
|
||||
if (tstr[1] == endc || tstr[1] == ':') {
|
||||
newStr = VarQuote(nstr);
|
||||
newStr = VarQuote(nstr, modifier == 'q');
|
||||
cp = tstr + 1;
|
||||
termc = *cp;
|
||||
break;
|
||||
|
@ -482,14 +482,7 @@ ipf_fastroute(m, mpp, fin, fdp)
|
||||
m->mb_ifp = ifp;
|
||||
printpacket(fin->fin_out, m);
|
||||
|
||||
#if defined(__sgi) && (IRIX < 60500)
|
||||
(*ifp->if_output)(ifp, (void *)ip, NULL);
|
||||
# if TRU64 >= 1885
|
||||
(*ifp->if_output)(ifp, (void *)m, NULL, 0, 0);
|
||||
# else
|
||||
(*ifp->if_output)(ifp, (void *)m, NULL, 0);
|
||||
# endif
|
||||
#endif
|
||||
done:
|
||||
fin->fin_ifp = sifp;
|
||||
fin->fin_out = sout;
|
||||
|
@ -67,9 +67,9 @@ int send_ether(nfd, buf, len, gwip)
|
||||
bcopy((char *)buf, s + sizeof(*eh), len);
|
||||
if (gwip.s_addr == last_gw.s_addr)
|
||||
{
|
||||
bcopy(last_arp, (char *)A_A eh->ether_dhost, 6);
|
||||
bcopy(last_arp, (char *) &eh->ether_dhost, 6);
|
||||
}
|
||||
else if (arp((char *)&gwip, (char *)A_A eh->ether_dhost) == -1)
|
||||
else if (arp((char *)&gwip, (char *) &eh->ether_dhost) == -1)
|
||||
{
|
||||
perror("arp");
|
||||
return -2;
|
||||
@ -109,17 +109,17 @@ int send_ip(nfd, mtu, ip, gwip, frag)
|
||||
|
||||
eh = (ether_header_t *)ipbuf;
|
||||
|
||||
bzero((char *)A_A eh->ether_shost, sizeof(eh->ether_shost));
|
||||
bzero((char *) &eh->ether_shost, sizeof(eh->ether_shost));
|
||||
if (last_gw.s_addr && (gwip.s_addr == last_gw.s_addr))
|
||||
{
|
||||
bcopy(last_arp, (char *)A_A eh->ether_dhost, 6);
|
||||
bcopy(last_arp, (char *) &eh->ether_dhost, 6);
|
||||
}
|
||||
else if (arp((char *)&gwip, (char *)A_A eh->ether_dhost) == -1)
|
||||
else if (arp((char *)&gwip, (char *) &eh->ether_dhost) == -1)
|
||||
{
|
||||
perror("arp");
|
||||
return -2;
|
||||
}
|
||||
bcopy((char *)A_A eh->ether_dhost, last_arp, sizeof(last_arp));
|
||||
bcopy((char *) &eh->ether_dhost, last_arp, sizeof(last_arp));
|
||||
eh->ether_type = htons(ETHERTYPE_IP);
|
||||
|
||||
bcopy((char *)ip, (char *)&ipsv, sizeof(*ip));
|
||||
@ -136,11 +136,11 @@ int send_ip(nfd, mtu, ip, gwip, frag)
|
||||
}
|
||||
|
||||
if (ip->ip_src.s_addr != local_ip.s_addr) {
|
||||
(void) arp((char *)&ip->ip_src, (char *)A_A local_arp);
|
||||
bcopy(local_arp, (char *)A_A eh->ether_shost,sizeof(last_arp));
|
||||
(void) arp((char *)&ip->ip_src, (char *) &local_arp);
|
||||
bcopy(local_arp, (char *) &eh->ether_shost,sizeof(last_arp));
|
||||
local_ip = ip->ip_src;
|
||||
} else
|
||||
bcopy(local_arp, (char *)A_A eh->ether_shost, 6);
|
||||
bcopy(local_arp, (char *) &eh->ether_shost, 6);
|
||||
|
||||
if (!frag || (sizeof(*eh) + iplen < mtu))
|
||||
{
|
||||
|
@ -97,7 +97,7 @@ int ip_resend(dev, mtu, r, gwip, datain)
|
||||
return -2;
|
||||
}
|
||||
|
||||
bzero((char *)A_A eh->ether_shost, sizeof(eh->ether_shost));
|
||||
bzero((char *) &eh->ether_shost, sizeof(eh->ether_shost));
|
||||
if (gwip.s_addr && (arp((char *)&gwip, dhost) == -1))
|
||||
{
|
||||
perror("arp");
|
||||
@ -113,12 +113,12 @@ int ip_resend(dev, mtu, r, gwip, datain)
|
||||
eh->ether_type = htons((u_short)ETHERTYPE_IP);
|
||||
if (!gwip.s_addr) {
|
||||
if (arp((char *)&gwip,
|
||||
(char *)A_A eh->ether_dhost) == -1) {
|
||||
(char *) &eh->ether_dhost) == -1) {
|
||||
perror("arp");
|
||||
continue;
|
||||
}
|
||||
} else
|
||||
bcopy(dhost, (char *)A_A eh->ether_dhost,
|
||||
bcopy(dhost, (char *) &eh->ether_dhost,
|
||||
sizeof(dhost));
|
||||
if (!ip->ip_sum)
|
||||
ip->ip_sum = chksum((u_short *)ip,
|
||||
|
@ -1585,17 +1585,29 @@ next_field_w(const wchar_t **wp, const wchar_t **start,
|
||||
|
||||
/* Scan for the separator. */
|
||||
while (**wp != L'\0' && **wp != L',' && **wp != L':' &&
|
||||
**wp != L'\n') {
|
||||
**wp != L'\n' && **wp != L'#') {
|
||||
(*wp)++;
|
||||
}
|
||||
*sep = **wp;
|
||||
|
||||
/* Trim trailing whitespace to locate end of field. */
|
||||
*end = *wp - 1;
|
||||
while (**end == L' ' || **end == L'\t' || **end == L'\n') {
|
||||
(*end)--;
|
||||
/* Locate end of field, trim trailing whitespace if necessary */
|
||||
if (*wp == *start) {
|
||||
*end = *wp;
|
||||
} else {
|
||||
*end = *wp - 1;
|
||||
while (**end == L' ' || **end == L'\t' || **end == L'\n') {
|
||||
(*end)--;
|
||||
}
|
||||
(*end)++;
|
||||
}
|
||||
|
||||
/* Handle in-field comments */
|
||||
if (*sep == L'#') {
|
||||
while (**wp != L'\0' && **wp != L',' && **wp != L'\n') {
|
||||
(*wp)++;
|
||||
}
|
||||
*sep = **wp;
|
||||
}
|
||||
(*end)++;
|
||||
|
||||
/* Adjust scanner location. */
|
||||
if (**wp != L'\0')
|
||||
@ -1646,7 +1658,7 @@ archive_acl_from_text_l(struct archive_acl *acl, const char *text,
|
||||
ret = ARCHIVE_OK;
|
||||
types = 0;
|
||||
|
||||
while (text != NULL && *text != '\0') {
|
||||
while (text != NULL && *text != '\0') {
|
||||
/*
|
||||
* Parse the fields out of the next entry,
|
||||
* advance 'text' to start of next entry.
|
||||
@ -2057,23 +2069,30 @@ next_field(const char **p, const char **start,
|
||||
*start = *p;
|
||||
|
||||
/* Scan for the separator. */
|
||||
while (**p != '\0' && **p != ',' && **p != ':' && **p != '\n') {
|
||||
while (**p != '\0' && **p != ',' && **p != ':' && **p != '\n' &&
|
||||
**p != '#') {
|
||||
(*p)++;
|
||||
}
|
||||
*sep = **p;
|
||||
|
||||
/* If the field is only whitespace, bail out now. */
|
||||
if (**p == '\0') {
|
||||
/* Locate end of field, trim trailing whitespace if necessary */
|
||||
if (*p == *start) {
|
||||
*end = *p;
|
||||
return;
|
||||
} else {
|
||||
*end = *p - 1;
|
||||
while (**end == ' ' || **end == '\t' || **end == '\n') {
|
||||
(*end)--;
|
||||
}
|
||||
(*end)++;
|
||||
}
|
||||
|
||||
/* Trim trailing whitespace to locate end of field. */
|
||||
*end = *p - 1;
|
||||
while (**end == ' ' || **end == '\t' || **end == '\n') {
|
||||
(*end)--;
|
||||
/* Handle in-field comments */
|
||||
if (*sep == '#') {
|
||||
while (**p != '\0' && **p != ',' && **p != '\n') {
|
||||
(*p)++;
|
||||
}
|
||||
*sep = **p;
|
||||
}
|
||||
(*end)++;
|
||||
|
||||
/* Adjust scanner location. */
|
||||
if (**p != '\0')
|
||||
|
@ -1704,6 +1704,20 @@ _archive_write_disk_finish_entry(struct archive *_a)
|
||||
if (r2 < ret) ret = r2;
|
||||
}
|
||||
|
||||
/*
|
||||
* HYPOTHESIS:
|
||||
* If we're not root, we won't be setting any security
|
||||
* attributes that may be wiped by the set_mode() routine
|
||||
* below. We also can't set xattr on non-owner-writable files,
|
||||
* which may be the state after set_mode(). Perform
|
||||
* set_xattrs() first based on these constraints.
|
||||
*/
|
||||
if (a->user_uid != 0 &&
|
||||
(a->todo & TODO_XATTR)) {
|
||||
int r2 = set_xattrs(a);
|
||||
if (r2 < ret) ret = r2;
|
||||
}
|
||||
|
||||
/*
|
||||
* set_mode must precede ACLs on systems such as Solaris and
|
||||
* FreeBSD where setting the mode implicitly clears extended ACLs
|
||||
@ -1717,8 +1731,10 @@ _archive_write_disk_finish_entry(struct archive *_a)
|
||||
* Security-related extended attributes (such as
|
||||
* security.capability on Linux) have to be restored last,
|
||||
* since they're implicitly removed by other file changes.
|
||||
* We do this last only when root.
|
||||
*/
|
||||
if (a->todo & TODO_XATTR) {
|
||||
if (a->user_uid == 0 &&
|
||||
(a->todo & TODO_XATTR)) {
|
||||
int r2 = set_xattrs(a);
|
||||
if (r2 < ret) ret = r2;
|
||||
}
|
||||
@ -2223,6 +2239,15 @@ create_filesystem_object(struct archive_write_disk *a)
|
||||
*/
|
||||
mode = final_mode & 0777 & ~a->user_umask;
|
||||
|
||||
/*
|
||||
* Always create writable such that [f]setxattr() works if we're not
|
||||
* root.
|
||||
*/
|
||||
if (a->user_uid != 0 &&
|
||||
a->todo & (TODO_HFS_COMPRESSION | TODO_XATTR)) {
|
||||
mode |= 0200;
|
||||
}
|
||||
|
||||
switch (a->mode & AE_IFMT) {
|
||||
default:
|
||||
/* POSIX requires that we fall through here. */
|
||||
|
@ -49,7 +49,6 @@ DEFINE_TEST(test_extattr_freebsd)
|
||||
struct archive_entry *ae;
|
||||
ssize_t n;
|
||||
int fd;
|
||||
int extattr_privilege_bug = 0;
|
||||
|
||||
/*
|
||||
* First, do a quick manual set/read of an extended attribute
|
||||
@ -73,24 +72,6 @@ DEFINE_TEST(test_extattr_freebsd)
|
||||
assertEqualInt(4, n);
|
||||
close(fd);
|
||||
|
||||
/*
|
||||
* Repeat the above, but with file permissions set to 0000.
|
||||
* This should work (extattr_set_fd() should follow fd
|
||||
* permissions, not file permissions), but is known broken on
|
||||
* some versions of FreeBSD.
|
||||
*/
|
||||
fd = open("pretest2", O_RDWR | O_CREAT, 00000);
|
||||
failure("Could not create test file?!");
|
||||
if (!assert(fd >= 0))
|
||||
return;
|
||||
|
||||
n = extattr_set_fd(fd, EXTATTR_NAMESPACE_USER, "testattr", "1234", 4);
|
||||
if (n != 4) {
|
||||
skipping("Restoring xattr to an unwritable file seems to be broken on this platform");
|
||||
extattr_privilege_bug = 1;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
/* Create a write-to-disk object. */
|
||||
assert(NULL != (a = archive_write_disk_new()));
|
||||
archive_write_disk_set_options(a,
|
||||
@ -120,16 +101,12 @@ DEFINE_TEST(test_extattr_freebsd)
|
||||
archive_entry_free(ae);
|
||||
|
||||
/* Close the archive. */
|
||||
if (extattr_privilege_bug)
|
||||
/* If the bug is here, write_close will return warning. */
|
||||
assertEqualIntA(a, ARCHIVE_WARN, archive_write_close(a));
|
||||
else
|
||||
assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
|
||||
assertEqualInt(ARCHIVE_OK, archive_write_free(a));
|
||||
assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
|
||||
|
||||
/* Verify the data on disk. */
|
||||
assertEqualInt(0, stat("test0", &st));
|
||||
assertEqualInt(st.st_mtime, 123456);
|
||||
assertEqualInt(st.st_mode & 0777, 0755);
|
||||
/* Verify extattr */
|
||||
n = extattr_get_file("test0", EXTATTR_NAMESPACE_USER,
|
||||
"foo", buff, sizeof(buff));
|
||||
@ -141,17 +118,20 @@ DEFINE_TEST(test_extattr_freebsd)
|
||||
/* Verify the data on disk. */
|
||||
assertEqualInt(0, stat("test1", &st));
|
||||
assertEqualInt(st.st_mtime, 12345678);
|
||||
assertEqualInt(st.st_mode & 0777, 0);
|
||||
/*
|
||||
* If we are not root, we have to make test1 user readable
|
||||
* or extattr_get_file() will fail
|
||||
*/
|
||||
if (geteuid() != 0) {
|
||||
chmod("test1", S_IRUSR);
|
||||
}
|
||||
/* Verify extattr */
|
||||
n = extattr_get_file("test1", EXTATTR_NAMESPACE_USER,
|
||||
"bar", buff, sizeof(buff));
|
||||
if (extattr_privilege_bug) {
|
||||
/* If we have the bug, the extattr won't have been written. */
|
||||
assertEqualInt(n, -1);
|
||||
} else {
|
||||
if (assertEqualInt(n, 6)) {
|
||||
buff[n] = '\0';
|
||||
assertEqualString(buff, "123456");
|
||||
}
|
||||
if (assertEqualInt(n, 6)) {
|
||||
buff[n] = '\0';
|
||||
assertEqualString(buff, "123456");
|
||||
}
|
||||
|
||||
/* Use libarchive APIs to read the file back into an entry and
|
||||
|
@ -90,7 +90,7 @@ int verify_data(const uint8_t* data_ptr, int magic, int size) {
|
||||
|
||||
static
|
||||
int extract_one(struct archive* a, struct archive_entry* ae, uint32_t crc) {
|
||||
la_ssize_t fsize, read;
|
||||
la_ssize_t fsize, bytes_read;
|
||||
uint8_t* buf;
|
||||
int ret = 1;
|
||||
uint32_t computed_crc;
|
||||
@ -100,9 +100,9 @@ int extract_one(struct archive* a, struct archive_entry* ae, uint32_t crc) {
|
||||
if(buf == NULL)
|
||||
return 1;
|
||||
|
||||
read = archive_read_data(a, buf, fsize);
|
||||
if(read != fsize) {
|
||||
assertEqualInt(read, fsize);
|
||||
bytes_read = archive_read_data(a, buf, fsize);
|
||||
if(bytes_read != fsize) {
|
||||
assertEqualInt(bytes_read, fsize);
|
||||
goto fn_exit;
|
||||
}
|
||||
|
||||
|
@ -96,7 +96,7 @@ looks_utf8(const char *ibuf, size_t nbytes)
|
||||
if (i >= nbytes)
|
||||
goto done;
|
||||
|
||||
if (buf[i] & 0x40) /* 10xxxxxx */
|
||||
if ((buf[i] & 0xc0) != 0x80) /* 10xxxxxx */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -79,7 +79,7 @@ int ibv_read_sysfs_file(const char *dir, const char *file,
|
||||
char *buf, size_t size)
|
||||
{
|
||||
char *path, *s;
|
||||
int fd;
|
||||
int ret;
|
||||
size_t len;
|
||||
|
||||
if (asprintf(&path, "%s/%s", dir, file) < 0)
|
||||
@ -89,12 +89,13 @@ int ibv_read_sysfs_file(const char *dir, const char *file,
|
||||
if (*s == '/')
|
||||
*s = '.';
|
||||
|
||||
len = size;
|
||||
if (sysctlbyname(&path[1], buf, &len, NULL, 0) == -1)
|
||||
return -1;
|
||||
|
||||
len = size;
|
||||
ret = sysctlbyname(&path[1], buf, &len, NULL, 0);
|
||||
free(path);
|
||||
|
||||
if (ret == -1)
|
||||
return -1;
|
||||
|
||||
if (len > 0 && buf[len - 1] == '\n')
|
||||
buf[--len] = '\0';
|
||||
|
||||
|
@ -492,7 +492,7 @@ static ib_net64_t get_port_guid(IN osm_opensm_t * p_osm, uint64_t port_guid)
|
||||
fflush(stdout);
|
||||
if (scanf("%u", &choice) <= 0) {
|
||||
char junk[128];
|
||||
if (scanf("%s", junk) <= 0)
|
||||
if (scanf("%127s", junk) <= 0)
|
||||
printf("\nError: Cannot scan!\n");
|
||||
} else if (choice == 0)
|
||||
return 0;
|
||||
|
@ -264,6 +264,12 @@ trail_start(struct trail *trail, const char *filename, off_t offset)
|
||||
* 2. It is fully sent, but is not terminated, so new data can be
|
||||
* appended still, or
|
||||
* 3. It is fully sent but file name has changed.
|
||||
* There are two cases here:
|
||||
* 3a. Sender has crashed and the name has changed from
|
||||
* .not_terminated to .crash_recovery.
|
||||
* 3b. Sender was disconnected, no new data was added to the file,
|
||||
* but its name has changed from .not_terminated to terminated
|
||||
* name.
|
||||
*
|
||||
* Note that we are fine if our .not_terminated or .crash_recovery file
|
||||
* is smaller than the one on the receiver side, as it is possible that
|
||||
@ -275,7 +281,7 @@ trail_start(struct trail *trail, const char *filename, off_t offset)
|
||||
(offset >= sb.st_size &&
|
||||
trail_is_not_terminated(trail->tr_filename)) ||
|
||||
(offset >= sb.st_size && trail_is_not_terminated(filename) &&
|
||||
trail_is_crash_recovery(trail->tr_filename))) {
|
||||
!trail_is_not_terminated(trail->tr_filename))) {
|
||||
/* File was not fully send. Let's finish it. */
|
||||
if (lseek(fd, offset, SEEK_SET) == -1) {
|
||||
pjdlog_errno(LOG_ERR,
|
||||
|
@ -140,7 +140,7 @@ The license terms used for hostap.git files
|
||||
|
||||
Modified BSD license (no advertisement clause):
|
||||
|
||||
Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> and contributors
|
||||
Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi> and contributors
|
||||
All Rights Reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
@ -1,7 +1,7 @@
|
||||
wpa_supplicant and hostapd
|
||||
--------------------------
|
||||
|
||||
Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> and contributors
|
||||
Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi> and contributors
|
||||
All Rights Reserved.
|
||||
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
wpa_supplicant and hostapd
|
||||
--------------------------
|
||||
|
||||
Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> and contributors
|
||||
Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi> and contributors
|
||||
All Rights Reserved.
|
||||
|
||||
These programs are licensed under the BSD license (the one with
|
||||
|
@ -1,5 +1,60 @@
|
||||
ChangeLog for hostapd
|
||||
|
||||
2018-12-02 - v2.7
|
||||
* fixed WPA packet number reuse with replayed messages and key
|
||||
reinstallation
|
||||
[http://w1.fi/security/2017-1/] (CVE-2017-13082)
|
||||
* added support for FILS (IEEE 802.11ai) shared key authentication
|
||||
* added support for OWE (Opportunistic Wireless Encryption, RFC 8110;
|
||||
and transition mode defined by WFA)
|
||||
* added support for DPP (Wi-Fi Device Provisioning Protocol)
|
||||
* FT:
|
||||
- added local generation of PMK-R0/PMK-R1 for FT-PSK
|
||||
(ft_psk_generate_local=1)
|
||||
- replaced inter-AP protocol with a cleaner design that is more
|
||||
easily extensible; this breaks backward compatibility and requires
|
||||
all APs in the ESS to be updated at the same time to maintain FT
|
||||
functionality
|
||||
- added support for wildcard R0KH/R1KH
|
||||
- replaced r0_key_lifetime (minutes) parameter with
|
||||
ft_r0_key_lifetime (seconds)
|
||||
- fixed wpa_psk_file use for FT-PSK
|
||||
- fixed FT-SAE PMKID matching
|
||||
- added expiration to PMK-R0 and PMK-R1 cache
|
||||
- added IEEE VLAN support (including tagged VLANs)
|
||||
- added support for SHA384 based AKM
|
||||
* SAE
|
||||
- fixed some PMKSA caching cases with SAE
|
||||
- added support for configuring SAE password separately of the
|
||||
WPA2 PSK/passphrase
|
||||
- added option to require MFP for SAE associations
|
||||
(sae_require_pmf=1)
|
||||
- fixed PTK and EAPOL-Key integrity and key-wrap algorithm selection
|
||||
for SAE;
|
||||
note: this is not backwards compatible, i.e., both the AP and
|
||||
station side implementations will need to be update at the same
|
||||
time to maintain interoperability
|
||||
- added support for Password Identifier
|
||||
* hostapd_cli: added support for command history and completion
|
||||
* added support for requesting beacon report
|
||||
* large number of other fixes, cleanup, and extensions
|
||||
* added option to configure EAPOL-Key retry limits
|
||||
(wpa_group_update_count and wpa_pairwise_update_count)
|
||||
* removed all PeerKey functionality
|
||||
* fixed nl80211 AP mode configuration regression with Linux 4.15 and
|
||||
newer
|
||||
* added support for using wolfSSL cryptographic library
|
||||
* fixed some 20/40 MHz coexistence cases where the BSS could drop to
|
||||
20 MHz even when 40 MHz would be allowed
|
||||
* Hotspot 2.0
|
||||
- added support for setting Venue URL ANQP-element (venue_url)
|
||||
- added support for advertising Hotspot 2.0 operator icons
|
||||
- added support for Roaming Consortium Selection element
|
||||
- added support for Terms and Conditions
|
||||
- added support for OSEN connection in a shared RSN BSS
|
||||
* added support for using OpenSSL 1.1.1
|
||||
* added EAP-pwd server support for salted passwords
|
||||
|
||||
2016-10-02 - v2.6
|
||||
* fixed EAP-pwd last fragment validation
|
||||
[http://w1.fi/security/2015-7/] (CVE-2015-5314)
|
||||
|
@ -2,7 +2,7 @@ hostapd - user space IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP
|
||||
Authenticator and RADIUS authentication server
|
||||
================================================================
|
||||
|
||||
Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> and contributors
|
||||
Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi> and contributors
|
||||
All Rights Reserved.
|
||||
|
||||
This program is licensed under the BSD license (the one with
|
||||
@ -70,7 +70,7 @@ Requirements
|
||||
Current hardware/software requirements:
|
||||
- drivers:
|
||||
Host AP driver for Prism2/2.5/3.
|
||||
(http://hostap.epitest.fi/)
|
||||
(http://w1.fi/hostap-driver.html)
|
||||
Please note that station firmware version needs to be 1.7.0 or newer
|
||||
to work in WPA mode.
|
||||
|
||||
@ -81,8 +81,7 @@ Current hardware/software requirements:
|
||||
Any wired Ethernet driver for wired IEEE 802.1X authentication
|
||||
(experimental code)
|
||||
|
||||
FreeBSD -current (with some kernel mods that have not yet been
|
||||
committed when hostapd v0.3.0 was released)
|
||||
FreeBSD -current
|
||||
BSD net80211 layer (e.g., Atheros driver)
|
||||
|
||||
|
||||
@ -186,23 +185,13 @@ Authenticator and RADIUS encapsulation between the Authenticator and
|
||||
the Authentication Server. Other than this, the functionality is similar
|
||||
to the case with the co-located Authentication Server.
|
||||
|
||||
Authentication Server and Supplicant
|
||||
------------------------------------
|
||||
Authentication Server
|
||||
---------------------
|
||||
|
||||
Any RADIUS server supporting EAP should be usable as an IEEE 802.1X
|
||||
Authentication Server with hostapd Authenticator. FreeRADIUS
|
||||
(http://www.freeradius.org/) has been successfully tested with hostapd
|
||||
Authenticator and both Xsupplicant (http://www.open1x.org) and Windows
|
||||
XP Supplicants. EAP/TLS was used with Xsupplicant and
|
||||
EAP/MD5-Challenge with Windows XP.
|
||||
|
||||
http://www.missl.cs.umd.edu/wireless/eaptls/ has useful information
|
||||
about using EAP/TLS with FreeRADIUS and Xsupplicant (just replace
|
||||
Cisco access point with Host AP driver, hostapd daemon, and a Prism2
|
||||
card ;-). http://www.freeradius.org/doc/EAP-MD5.html has information
|
||||
about using EAP/MD5 with FreeRADIUS, including instructions for WinXP
|
||||
configuration. http://www.denobula.com/EAPTLS.pdf has a HOWTO on
|
||||
EAP/TLS use with WinXP Supplicant.
|
||||
Authenticator.
|
||||
|
||||
Automatic WEP key configuration
|
||||
-------------------------------
|
||||
@ -243,16 +232,15 @@ networks that require some kind of security. Task group I (Security)
|
||||
of IEEE 802.11 working group (http://www.ieee802.org/11/) has worked
|
||||
to address the flaws of the base standard and has in practice
|
||||
completed its work in May 2004. The IEEE 802.11i amendment to the IEEE
|
||||
802.11 standard was approved in June 2004 and this amendment is likely
|
||||
to be published in July 2004.
|
||||
802.11 standard was approved in June 2004 and this amendment was
|
||||
published in July 2004.
|
||||
|
||||
Wi-Fi Alliance (http://www.wi-fi.org/) used a draft version of the
|
||||
IEEE 802.11i work (draft 3.0) to define a subset of the security
|
||||
enhancements that can be implemented with existing wlan hardware. This
|
||||
is called Wi-Fi Protected Access<TM> (WPA). This has now become a
|
||||
mandatory component of interoperability testing and certification done
|
||||
by Wi-Fi Alliance. Wi-Fi provides information about WPA at its web
|
||||
site (http://www.wi-fi.org/OpenSection/protected_access.asp).
|
||||
by Wi-Fi Alliance.
|
||||
|
||||
IEEE 802.11 standard defined wired equivalent privacy (WEP) algorithm
|
||||
for protecting wireless networks. WEP uses RC4 with 40-bit keys,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -13,5 +13,10 @@ struct hostapd_config * hostapd_config_read(const char *fname);
|
||||
int hostapd_set_iface(struct hostapd_config *conf,
|
||||
struct hostapd_bss_config *bss, const char *field,
|
||||
char *value);
|
||||
int hostapd_acl_comp(const void *a, const void *b);
|
||||
int hostapd_add_acl_maclist(struct mac_acl_entry **acl, int *num,
|
||||
int vlan_id, const u8 *addr);
|
||||
void hostapd_remove_acl_mac(struct mac_acl_entry **acl, int *num,
|
||||
const u8 *addr);
|
||||
|
||||
#endif /* CONFIG_FILE_H */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -31,7 +31,7 @@ CONFIG_DRIVER_NL80211=y
|
||||
#CONFIG_LIBNL20=y
|
||||
|
||||
# Use libnl 3.2 libraries (if this is selected, CONFIG_LIBNL20 is ignored)
|
||||
#CONFIG_LIBNL32=y
|
||||
CONFIG_LIBNL32=y
|
||||
|
||||
|
||||
# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
|
||||
@ -50,9 +50,6 @@ CONFIG_IAPP=y
|
||||
# WPA2/IEEE 802.11i RSN pre-authentication
|
||||
CONFIG_RSN_PREAUTH=y
|
||||
|
||||
# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
|
||||
CONFIG_PEERKEY=y
|
||||
|
||||
# IEEE 802.11w (management frame protection)
|
||||
CONFIG_IEEE80211W=y
|
||||
|
||||
@ -157,6 +154,12 @@ CONFIG_IPV6=y
|
||||
# IEEE 802.11ac (Very High Throughput) support
|
||||
#CONFIG_IEEE80211AC=y
|
||||
|
||||
# IEEE 802.11ax HE support
|
||||
# Note: This is experimental and work in progress. The definitions are still
|
||||
# subject to change and this should not be expected to interoperate with the
|
||||
# final IEEE 802.11ax version.
|
||||
#CONFIG_IEEE80211AX=y
|
||||
|
||||
# Remove debugging code that is printing out debug messages to stdout.
|
||||
# This can be used to reduce the size of the hostapd considerably if debugging
|
||||
# code is not needed.
|
||||
@ -166,6 +169,9 @@ CONFIG_IPV6=y
|
||||
# Disabled by default.
|
||||
#CONFIG_DEBUG_FILE=y
|
||||
|
||||
# Send debug messages to syslog instead of stdout
|
||||
#CONFIG_DEBUG_SYSLOG=y
|
||||
|
||||
# Add support for sending all debug messages (regardless of debug verbosity)
|
||||
# to the Linux kernel tracing facility. This helps debug the entire stack by
|
||||
# making it easy to record everything happening from the driver up into the
|
||||
@ -256,6 +262,7 @@ CONFIG_IPV6=y
|
||||
# openssl = OpenSSL (default)
|
||||
# gnutls = GnuTLS
|
||||
# internal = Internal TLSv1 implementation (experimental)
|
||||
# linux = Linux kernel AF_ALG and internal TLSv1 implementation (experimental)
|
||||
# none = Empty template
|
||||
#CONFIG_TLS=openssl
|
||||
|
||||
@ -268,6 +275,10 @@ CONFIG_IPV6=y
|
||||
# can be enabled to enable use of stronger crypto algorithms.
|
||||
#CONFIG_TLSV12=y
|
||||
|
||||
# Select which ciphers to use by default with OpenSSL if the user does not
|
||||
# specify them.
|
||||
#CONFIG_TLS_DEFAULT_CIPHERS="DEFAULT:!EXP:!LOW"
|
||||
|
||||
# If CONFIG_TLS=internal is used, additional library and include paths are
|
||||
# needed for LibTomMath. Alternatively, an integrated, minimal version of
|
||||
# LibTomMath can be used. See beginning of libtommath.c for details on benefits
|
||||
@ -343,3 +354,22 @@ CONFIG_IPV6=y
|
||||
# a client, from which a signature can be produced which can identify the model
|
||||
# of client device like "Nexus 6P" or "iPhone 5s".
|
||||
#CONFIG_TAXONOMY=y
|
||||
|
||||
# Fast Initial Link Setup (FILS) (IEEE 802.11ai)
|
||||
# Note: This is an experimental and not yet complete implementation. This
|
||||
# should not be enabled for production use.
|
||||
#CONFIG_FILS=y
|
||||
# FILS shared key authentication with PFS
|
||||
#CONFIG_FILS_SK_PFS=y
|
||||
|
||||
# Include internal line edit mode in hostapd_cli. This can be used to provide
|
||||
# limited command line editing and history support.
|
||||
#CONFIG_WPA_CLI_EDIT=y
|
||||
|
||||
# Opportunistic Wireless Encryption (OWE)
|
||||
# Experimental implementation of draft-harkins-owe-07.txt
|
||||
#CONFIG_OWE=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
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator
|
||||
* Copyright (c) 2005-2007, 2012-2016, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2005-2007, 2012-2017, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -973,7 +973,7 @@ static void usage(void)
|
||||
{
|
||||
printf("HLR/AuC testing gateway for hostapd EAP-SIM/AKA "
|
||||
"database/authenticator\n"
|
||||
"Copyright (c) 2005-2016, Jouni Malinen <j@w1.fi>\n"
|
||||
"Copyright (c) 2005-2017, Jouni Malinen <j@w1.fi>\n"
|
||||
"\n"
|
||||
"usage:\n"
|
||||
"hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] "
|
||||
|
@ -98,8 +98,25 @@ ssid=test
|
||||
# Country code (ISO/IEC 3166-1). Used to set regulatory domain.
|
||||
# Set as needed to indicate country in which device is operating.
|
||||
# This can limit available channels and transmit power.
|
||||
# These two octets are used as the first two octets of the Country String
|
||||
# (dot11CountryString)
|
||||
#country_code=US
|
||||
|
||||
# The third octet of the Country String (dot11CountryString)
|
||||
# This parameter is used to set the third octet of the country string.
|
||||
#
|
||||
# All environments of the current frequency band and country (default)
|
||||
#country3=0x20
|
||||
# Outdoor environment only
|
||||
#country3=0x4f
|
||||
# Indoor environment only
|
||||
#country3=0x49
|
||||
# Noncountry entity (country_code=XX)
|
||||
#country3=0x58
|
||||
# IEEE 802.11 standard Annex E table indication: 0x01 .. 0x1f
|
||||
# Annex E, Table E-4 (Global operating classes)
|
||||
#country3=0x04
|
||||
|
||||
# Enable IEEE 802.11d. This advertises the country_code and the set of allowed
|
||||
# channels and transmit power levels based on the regulatory limits. The
|
||||
# country_code setting must be configured with the correct country for
|
||||
@ -182,6 +199,11 @@ channel=1
|
||||
#chanlist=100 104 108 112 116
|
||||
#chanlist=1 6 11-13
|
||||
|
||||
# Exclude DFS channels from ACS
|
||||
# This option can be used to exclude all DFS channels from the ACS channel list
|
||||
# in cases where the driver supports DFS channels.
|
||||
#acs_exclude_dfs=1
|
||||
|
||||
# Beacon interval in kus (1.024 ms) (default: 100; range 15..65535)
|
||||
beacon_int=100
|
||||
|
||||
@ -227,6 +249,19 @@ fragm_threshold=-1
|
||||
#basic_rates=10 20 55 110
|
||||
#basic_rates=60 120 240
|
||||
|
||||
# Beacon frame TX rate configuration
|
||||
# This sets the TX rate that is used to transmit Beacon frames. If this item is
|
||||
# not included, the driver default rate (likely lowest rate) is used.
|
||||
# Legacy (CCK/OFDM rates):
|
||||
# beacon_rate=<legacy rate in 100 kbps>
|
||||
# HT:
|
||||
# beacon_rate=ht:<HT MCS>
|
||||
# VHT:
|
||||
# beacon_rate=vht:<VHT MCS>
|
||||
#
|
||||
# For example, beacon_rate=10 for 1 Mbps or beacon_rate=60 for 6 Mbps (OFDM).
|
||||
#beacon_rate=10
|
||||
|
||||
# Short Preamble
|
||||
# This parameter can be used to enable optional use of short preamble for
|
||||
# frames sent at 2 Mbps, 5.5 Mbps, and 11 Mbps to improve network performance.
|
||||
@ -294,7 +329,7 @@ ignore_broadcast_ssid=0
|
||||
|
||||
# TX queue parameters (EDCF / bursting)
|
||||
# tx_queue_<queue name>_<param>
|
||||
# queues: data0, data1, data2, data3, after_beacon, beacon
|
||||
# queues: data0, data1, data2, data3
|
||||
# (data0 is the highest priority queue)
|
||||
# parameters:
|
||||
# aifs: AIFS (default 2)
|
||||
@ -476,12 +511,38 @@ wmm_ac_vo_acm=0
|
||||
# Beacon and Probe Response frames.
|
||||
#bss_load_update_period=50
|
||||
|
||||
# Channel utilization averaging period (in BUs)
|
||||
# This field is used to enable and configure channel utilization average
|
||||
# calculation with bss_load_update_period. This should be in multiples of
|
||||
# bss_load_update_period for more accurate calculation.
|
||||
#chan_util_avg_period=600
|
||||
|
||||
# Fixed BSS Load value for testing purposes
|
||||
# This field can be used to configure hostapd to add a fixed BSS Load element
|
||||
# into Beacon and Probe Response frames for testing purposes. The format is
|
||||
# <station count>:<channel utilization>:<available admission capacity>
|
||||
#bss_load_test=12:80:20000
|
||||
|
||||
# Multicast to unicast conversion
|
||||
# Request that the AP will do multicast-to-unicast conversion for ARP, IPv4, and
|
||||
# IPv6 frames (possibly within 802.1Q). If enabled, such frames are to be sent
|
||||
# to each station separately, with the DA replaced by their own MAC address
|
||||
# rather than the group address.
|
||||
#
|
||||
# Note that this may break certain expectations of the receiver, such as the
|
||||
# ability to drop unicast IP packets received within multicast L2 frames, or the
|
||||
# ability to not send ICMP destination unreachable messages for packets received
|
||||
# in L2 multicast (which is required, but the receiver can't tell the difference
|
||||
# if this new option is enabled).
|
||||
#
|
||||
# This also doesn't implement the 802.11 DMS (directed multicast service).
|
||||
#
|
||||
#multicast_to_unicast=0
|
||||
|
||||
# Send broadcast Deauthentication frame on AP start/stop
|
||||
# Default: 1 (enabled)
|
||||
#broadcast_deauth=1
|
||||
|
||||
##### IEEE 802.11n related configuration ######################################
|
||||
|
||||
# ieee80211n: Whether IEEE 802.11n (HT) is enabled
|
||||
@ -692,6 +753,47 @@ wmm_ac_vo_acm=0
|
||||
# setting use_sta_nsts=1.
|
||||
#use_sta_nsts=0
|
||||
|
||||
##### IEEE 802.11ax related configuration #####################################
|
||||
|
||||
#ieee80211ax: Whether IEEE 802.11ax (HE) is enabled
|
||||
# 0 = disabled (default)
|
||||
# 1 = enabled
|
||||
#ieee80211ax=1
|
||||
|
||||
#he_su_beamformer: HE single user beamformer support
|
||||
# 0 = not supported (default)
|
||||
# 1 = supported
|
||||
#he_su_beamformer=1
|
||||
|
||||
#he_su_beamformee: HE single user beamformee support
|
||||
# 0 = not supported (default)
|
||||
# 1 = supported
|
||||
#he_su_beamformee=1
|
||||
|
||||
#he_mu_beamformer: HE multiple user beamformer support
|
||||
# 0 = not supported (default)
|
||||
# 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_default_pe_duration: The duration of PE field in an HE PPDU in us
|
||||
# Possible values are 0 us (default), 4 us, 8 us, 12 us, and 16 us
|
||||
#he_default_pe_duration=0
|
||||
|
||||
#he_twt_required: Whether TWT is required
|
||||
# 0 = not required (default)
|
||||
# 1 = required
|
||||
#he_twt_required=0
|
||||
|
||||
#he_rts_threshold: Duration of STA transmission
|
||||
# 0 = not set (default)
|
||||
# unsigned integer = duration in units of 16 us
|
||||
#he_rts_threshold=0
|
||||
|
||||
##### IEEE 802.1X-2004 related configuration ##################################
|
||||
|
||||
# Require IEEE 802.1X authorization
|
||||
@ -835,7 +937,8 @@ eap_server=0
|
||||
# OpenSSL cipher string
|
||||
#
|
||||
# This is an OpenSSL specific configuration option for configuring the default
|
||||
# ciphers. If not set, "DEFAULT:!EXP:!LOW" is used as the default.
|
||||
# ciphers. If not set, the value configured at build time ("DEFAULT:!EXP:!LOW"
|
||||
# by default) is used.
|
||||
# See https://www.openssl.org/docs/apps/ciphers.html for OpenSSL documentation
|
||||
# on cipher suite configuration. This is applicable only if hostapd is built to
|
||||
# use OpenSSL.
|
||||
@ -1088,6 +1191,8 @@ own_ip_addr=127.0.0.1
|
||||
#radius_das_port=3799
|
||||
#
|
||||
# DAS client (the host that can send Disconnect/CoA requests) and shared secret
|
||||
# Format: <IP address> <shared secret>
|
||||
# IP address 0.0.0.0 can be used to allow requests from any address.
|
||||
#radius_das_client=192.168.1.123 shared secret here
|
||||
#
|
||||
# DAS Event-Timestamp time window in seconds
|
||||
@ -1134,7 +1239,10 @@ own_ip_addr=127.0.0.1
|
||||
# and/or WPA2 (full IEEE 802.11i/RSN):
|
||||
# bit0 = WPA
|
||||
# bit1 = IEEE 802.11i/RSN (WPA2) (dot11RSNAEnabled)
|
||||
#wpa=1
|
||||
# Note that WPA3 is also configured with bit1 since it uses RSN just like WPA2.
|
||||
# In other words, for WPA3, wpa=2 is used the configuration (and
|
||||
# wpa_key_mgmt=SAE for WPA3-Personal instead of wpa_key_mgmt=WPA-PSK).
|
||||
#wpa=2
|
||||
|
||||
# WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit
|
||||
# secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase
|
||||
@ -1163,31 +1271,73 @@ own_ip_addr=127.0.0.1
|
||||
# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
|
||||
# entries are separated with a space. WPA-PSK-SHA256 and WPA-EAP-SHA256 can be
|
||||
# added to enable SHA256-based stronger algorithms.
|
||||
# WPA-PSK = WPA-Personal / WPA2-Personal
|
||||
# WPA-PSK-SHA256 = WPA2-Personal using SHA256
|
||||
# WPA-EAP = WPA-Enterprise / WPA2-Enterprise
|
||||
# WPA-EAP-SHA256 = WPA2-Enterprise using SHA256
|
||||
# SAE = SAE (WPA3-Personal)
|
||||
# WPA-EAP-SUITE-B-192 = WPA3-Enterprise with 192-bit security/CNSA suite
|
||||
# FT-PSK = FT with passphrase/PSK
|
||||
# FT-EAP = FT with EAP
|
||||
# FT-EAP-SHA384 = FT with EAP using SHA384
|
||||
# FT-SAE = FT with SAE
|
||||
# FILS-SHA256 = Fast Initial Link Setup with SHA256
|
||||
# FILS-SHA384 = Fast Initial Link Setup with SHA384
|
||||
# FT-FILS-SHA256 = FT and Fast Initial Link Setup with SHA256
|
||||
# FT-FILS-SHA384 = FT and Fast Initial Link Setup with SHA384
|
||||
# OWE = Opportunistic Wireless Encryption (a.k.a. Enhanced Open)
|
||||
# DPP = Device Provisioning Protocol
|
||||
# OSEN = Hotspot 2.0 online signup with encryption
|
||||
# (dot11RSNAConfigAuthenticationSuitesTable)
|
||||
#wpa_key_mgmt=WPA-PSK WPA-EAP
|
||||
|
||||
# Set of accepted cipher suites (encryption algorithms) for pairwise keys
|
||||
# (unicast packets). This is a space separated list of algorithms:
|
||||
# CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0]
|
||||
# TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0]
|
||||
# CCMP = AES in Counter mode with CBC-MAC (CCMP-128)
|
||||
# TKIP = Temporal Key Integrity Protocol
|
||||
# CCMP-256 = AES in Counter mode with CBC-MAC with 256-bit key
|
||||
# GCMP = Galois/counter mode protocol (GCMP-128)
|
||||
# GCMP-256 = Galois/counter mode protocol with 256-bit key
|
||||
# Group cipher suite (encryption algorithm for broadcast and multicast frames)
|
||||
# is automatically selected based on this configuration. If only CCMP is
|
||||
# allowed as the pairwise cipher, group cipher will also be CCMP. Otherwise,
|
||||
# TKIP will be used as the group cipher.
|
||||
# TKIP will be used as the group cipher. The optional group_cipher parameter can
|
||||
# be used to override this automatic selection.
|
||||
#
|
||||
# (dot11RSNAConfigPairwiseCiphersTable)
|
||||
# Pairwise cipher for WPA (v1) (default: TKIP)
|
||||
#wpa_pairwise=TKIP CCMP
|
||||
# Pairwise cipher for RSN/WPA2 (default: use wpa_pairwise value)
|
||||
#rsn_pairwise=CCMP
|
||||
|
||||
# Optional override for automatic group cipher selection
|
||||
# This can be used to select a specific group cipher regardless of which
|
||||
# pairwise ciphers were enabled for WPA and RSN. It should be noted that
|
||||
# overriding the group cipher with an unexpected value can result in
|
||||
# interoperability issues and in general, this parameter is mainly used for
|
||||
# testing purposes.
|
||||
#group_cipher=CCMP
|
||||
|
||||
# Time interval for rekeying GTK (broadcast/multicast encryption keys) in
|
||||
# seconds. (dot11RSNAConfigGroupRekeyTime)
|
||||
#wpa_group_rekey=600
|
||||
# This defaults to 86400 seconds (once per day) when using CCMP/GCMP as the
|
||||
# group cipher and 600 seconds (once per 10 minutes) when using TKIP as the
|
||||
# group cipher.
|
||||
#wpa_group_rekey=86400
|
||||
|
||||
# Rekey GTK when any STA that possesses the current GTK is leaving the BSS.
|
||||
# (dot11RSNAConfigGroupRekeyStrict)
|
||||
#wpa_strict_rekey=1
|
||||
|
||||
# The number of times EAPOL-Key Message 1/2 in the RSN Group Key Handshake is
|
||||
#retried per GTK Handshake attempt. (dot11RSNAConfigGroupUpdateCount)
|
||||
# This value should only be increased when stations are constantly
|
||||
# deauthenticated during GTK rekeying with the log message
|
||||
# "group key handshake failed...".
|
||||
# You should consider to also increase wpa_pairwise_update_count then.
|
||||
# Range 1..4294967295; default: 4
|
||||
#wpa_group_update_count=4
|
||||
|
||||
# Time interval for rekeying GMK (master key used internally to generate GTKs
|
||||
# (in seconds).
|
||||
#wpa_gmk_rekey=86400
|
||||
@ -1196,6 +1346,36 @@ own_ip_addr=127.0.0.1
|
||||
# PTK to mitigate some attacks against TKIP deficiencies.
|
||||
#wpa_ptk_rekey=600
|
||||
|
||||
# The number of times EAPOL-Key Message 1/4 and Message 3/4 in the RSN 4-Way
|
||||
# Handshake are retried per 4-Way Handshake attempt.
|
||||
# (dot11RSNAConfigPairwiseUpdateCount)
|
||||
# Range 1..4294967295; default: 4
|
||||
#wpa_pairwise_update_count=4
|
||||
|
||||
# Workaround for key reinstallation attacks
|
||||
#
|
||||
# This parameter can be used to disable retransmission of EAPOL-Key frames that
|
||||
# are used to install keys (EAPOL-Key message 3/4 and group message 1/2). This
|
||||
# is similar to setting wpa_group_update_count=1 and
|
||||
# wpa_pairwise_update_count=1, but with no impact to message 1/4 and with
|
||||
# extended timeout on the response to avoid causing issues with stations that
|
||||
# may use aggressive power saving have very long time in replying to the
|
||||
# EAPOL-Key messages.
|
||||
#
|
||||
# This option can be used to work around key reinstallation attacks on the
|
||||
# station (supplicant) side in cases those station devices cannot be updated
|
||||
# for some reason. By removing the retransmissions the attacker cannot cause
|
||||
# key reinstallation with a delayed frame transmission. This is related to the
|
||||
# station side vulnerabilities CVE-2017-13077, CVE-2017-13078, CVE-2017-13079,
|
||||
# CVE-2017-13080, and CVE-2017-13081.
|
||||
#
|
||||
# This workaround might cause interoperability issues and reduced robustness of
|
||||
# key negotiation especially in environments with heavy traffic load due to the
|
||||
# number of attempts to perform the key exchange is reduced significantly. As
|
||||
# such, this workaround is disabled by default (unless overridden in build
|
||||
# configuration). To enable this, set the parameter to 1.
|
||||
#wpa_disable_eapol_key_retries=1
|
||||
|
||||
# Enable IEEE 802.11i/RSN/WPA2 pre-authentication. This is used to speed up
|
||||
# roaming be pre-authenticating IEEE 802.1X/EAP part of the full RSN
|
||||
# authentication and key handshake before actually associating with a new AP.
|
||||
@ -1211,12 +1391,6 @@ own_ip_addr=127.0.0.1
|
||||
# one.
|
||||
#rsn_preauth_interfaces=eth0
|
||||
|
||||
# peerkey: Whether PeerKey negotiation for direct links (IEEE 802.11e) is
|
||||
# allowed. This is only used with RSN/WPA2.
|
||||
# 0 = disabled (default)
|
||||
# 1 = enabled
|
||||
#peerkey=1
|
||||
|
||||
# ieee80211w: Whether management frame protection (MFP) is enabled
|
||||
# 0 = disabled (default)
|
||||
# 1 = optional
|
||||
@ -1259,11 +1433,44 @@ own_ip_addr=127.0.0.1
|
||||
# 1 = enabled
|
||||
#okc=1
|
||||
|
||||
# SAE password
|
||||
# This parameter can be used to set passwords for SAE. By default, the
|
||||
# wpa_passphrase value is used if this separate parameter is not used, but
|
||||
# wpa_passphrase follows the WPA-PSK constraints (8..63 characters) even though
|
||||
# SAE passwords do not have such constraints. If the BSS enabled both SAE and
|
||||
# WPA-PSK and both values are set, SAE uses the sae_password values and WPA-PSK
|
||||
# uses the wpa_passphrase value.
|
||||
#
|
||||
# Each sae_password entry is added to a list of available passwords. This
|
||||
# corresponds to the dot11RSNAConfigPasswordValueEntry. sae_password value
|
||||
# starts with the password (dot11RSNAConfigPasswordCredential). That value can
|
||||
# be followed by optional peer MAC address (dot11RSNAConfigPasswordPeerMac) and
|
||||
# by optional password identifier (dot11RSNAConfigPasswordIdentifier). If the
|
||||
# peer MAC address is not included or is set to the wildcard address
|
||||
# (ff:ff:ff:ff:ff:ff), the entry is available for any station to use. If a
|
||||
# specific peer MAC address is included, only a station with that MAC address
|
||||
# is allowed to use the entry. If the password identifier (with non-zero length)
|
||||
# is included, the entry is limited to be used only with that specified
|
||||
# identifier. The last matching (based on peer MAC address and identifier) entry
|
||||
# is used to select which password to use. Setting sae_password to an empty
|
||||
# string has a special meaning of removing all previously added entries.
|
||||
# sae_password uses the following encoding:
|
||||
#<password/credential>[|mac=<peer mac>][|id=<identifier>]
|
||||
# Examples:
|
||||
#sae_password=secret
|
||||
#sae_password=really secret|mac=ff:ff:ff:ff:ff:ff
|
||||
#sae_password=example secret|mac=02:03:04:05:06:07|id=pw identifier
|
||||
|
||||
# SAE threshold for anti-clogging mechanism (dot11RSNASAEAntiCloggingThreshold)
|
||||
# This parameter defines how many open SAE instances can be in progress at the
|
||||
# same time before the anti-clogging mechanism is taken into use.
|
||||
#sae_anti_clogging_threshold=5
|
||||
|
||||
# Maximum number of SAE synchronization errors (dot11RSNASAESync)
|
||||
# The offending SAe peer will be disconnected if more than this many
|
||||
# synchronization errors happen.
|
||||
#sae_sync=5
|
||||
|
||||
# Enabled SAE finite cyclic groups
|
||||
# SAE implementation are required to support group 19 (ECC group defined over a
|
||||
# 256-bit prime order field). All groups that are supported by the
|
||||
@ -1273,6 +1480,75 @@ own_ip_addr=127.0.0.1
|
||||
# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-9
|
||||
#sae_groups=19 20 21 25 26
|
||||
|
||||
# Require MFP for all associations using SAE
|
||||
# This parameter can be used to enforce negotiation of MFP for all associations
|
||||
# that negotiate use of SAE. This is used in cases where SAE-capable devices are
|
||||
# known to be MFP-capable and the BSS is configured with optional MFP
|
||||
# (ieee80211w=1) for legacy support. The non-SAE stations can connect without
|
||||
# MFP while SAE stations are required to negotiate MFP if sae_require_mfp=1.
|
||||
#sae_require_mfp=0
|
||||
|
||||
# FILS Cache Identifier (16-bit value in hexdump format)
|
||||
#fils_cache_id=0011
|
||||
|
||||
# FILS Realm Information
|
||||
# One or more FILS realms need to be configured when FILS is enabled. This list
|
||||
# of realms is used to define which realms (used in keyName-NAI by the client)
|
||||
# can be used with FILS shared key authentication for ERP.
|
||||
#fils_realm=example.com
|
||||
#fils_realm=example.org
|
||||
|
||||
# FILS DH Group for PFS
|
||||
# 0 = PFS disabled with FILS shared key authentication (default)
|
||||
# 1-65535 DH Group to use for FILS PFS
|
||||
#fils_dh_group=0
|
||||
|
||||
# OWE DH groups
|
||||
# OWE implementations are required to support group 19 (NIST P-256). All groups
|
||||
# that are supported by the implementation (e.g., groups 19, 20, and 21 when
|
||||
# using OpenSSL) are enabled by default. This configuration parameter can be
|
||||
# used to specify a limited set of allowed groups. The group values are listed
|
||||
# in the IANA registry:
|
||||
# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-10
|
||||
#owe_groups=19 20 21
|
||||
|
||||
# OWE transition mode configuration
|
||||
# Pointer to the matching open/OWE BSS
|
||||
#owe_transition_bssid=<bssid>
|
||||
# SSID in same format as ssid2 described above.
|
||||
#owe_transition_ssid=<SSID>
|
||||
# Alternatively, OWE transition mode BSSID/SSID can be configured with a
|
||||
# reference to a BSS operated by this hostapd process.
|
||||
#owe_transition_ifname=<ifname>
|
||||
|
||||
# DHCP server for FILS HLP
|
||||
# If configured, hostapd will act as a DHCP relay for all FILS HLP requests
|
||||
# that include a DHCPDISCOVER message and send them to the specific DHCP
|
||||
# server for processing. hostapd will then wait for a response from that server
|
||||
# before replying with (Re)Association Response frame that encapsulates this
|
||||
# DHCP response. own_ip_addr is used as the local address for the communication
|
||||
# with the DHCP server.
|
||||
#dhcp_server=127.0.0.1
|
||||
|
||||
# DHCP server UDP port
|
||||
# Default: 67
|
||||
#dhcp_server_port=67
|
||||
|
||||
# DHCP relay UDP port on the local device
|
||||
# Default: 67; 0 means not to bind any specific port
|
||||
#dhcp_relay_port=67
|
||||
|
||||
# DHCP rapid commit proxy
|
||||
# If set to 1, this enables hostapd to act as a DHCP rapid commit proxy to
|
||||
# allow the rapid commit options (two message DHCP exchange) to be used with a
|
||||
# server that supports only the four message DHCP exchange. This is disabled by
|
||||
# default (= 0) and can be enabled by setting this to 1.
|
||||
#dhcp_rapid_commit_proxy=0
|
||||
|
||||
# Wait time for FILS HLP (dot11HLPWaitTime) in TUs
|
||||
# default: 30 TUs (= 30.72 milliseconds)
|
||||
#fils_hlp_wait_time=30
|
||||
|
||||
##### IEEE 802.11r configuration ##############################################
|
||||
|
||||
# Mobility Domain identifier (dot11FTMobilityDomainID, MDID)
|
||||
@ -1285,9 +1561,16 @@ own_ip_addr=127.0.0.1
|
||||
# 1 to 48 octet identifier.
|
||||
# This is configured with nas_identifier (see RADIUS client section above).
|
||||
|
||||
# Default lifetime of the PMK-RO in minutes; range 1..65535
|
||||
# Default lifetime of the PMK-R0 in seconds; range 60..4294967295
|
||||
# (default: 14 days / 1209600 seconds; 0 = disable timeout)
|
||||
# (dot11FTR0KeyLifetime)
|
||||
#r0_key_lifetime=10000
|
||||
#ft_r0_key_lifetime=1209600
|
||||
|
||||
# Maximum lifetime for PMK-R1; applied only if not zero
|
||||
# PMK-R1 is removed at latest after this limit.
|
||||
# Removing any PMK-R1 for expiry can be disabled by setting this to -1.
|
||||
# (default: 0)
|
||||
#r1_max_key_lifetime=0
|
||||
|
||||
# PMK-R1 Key Holder identifier (dot11FTR1KeyHolderID)
|
||||
# 6-octet identifier as a hex string.
|
||||
@ -1299,22 +1582,52 @@ own_ip_addr=127.0.0.1
|
||||
#reassociation_deadline=1000
|
||||
|
||||
# List of R0KHs in the same Mobility Domain
|
||||
# format: <MAC address> <NAS Identifier> <128-bit key as hex string>
|
||||
# format: <MAC address> <NAS Identifier> <256-bit key as hex string>
|
||||
# This list is used to map R0KH-ID (NAS Identifier) to a destination MAC
|
||||
# address when requesting PMK-R1 key from the R0KH that the STA used during the
|
||||
# Initial Mobility Domain Association.
|
||||
#r0kh=02:01:02:03:04:05 r0kh-1.example.com 000102030405060708090a0b0c0d0e0f
|
||||
#r0kh=02:01:02:03:04:06 r0kh-2.example.com 00112233445566778899aabbccddeeff
|
||||
#r0kh=02:01:02:03:04:05 r0kh-1.example.com 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f
|
||||
#r0kh=02:01:02:03:04:06 r0kh-2.example.com 00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff
|
||||
# And so on.. One line per R0KH.
|
||||
# Wildcard entry:
|
||||
# Upon receiving a response from R0KH, it will be added to this list, so
|
||||
# subsequent requests won't be broadcast. If R0KH does not reply, it will be
|
||||
# blacklisted.
|
||||
#r0kh=ff:ff:ff:ff:ff:ff * 00112233445566778899aabbccddeeff
|
||||
|
||||
# List of R1KHs in the same Mobility Domain
|
||||
# format: <MAC address> <R1KH-ID> <128-bit key as hex string>
|
||||
# format: <MAC address> <R1KH-ID> <256-bit key as hex string>
|
||||
# This list is used to map R1KH-ID to a destination MAC address when sending
|
||||
# PMK-R1 key from the R0KH. This is also the list of authorized R1KHs in the MD
|
||||
# that can request PMK-R1 keys.
|
||||
#r1kh=02:01:02:03:04:05 02:11:22:33:44:55 000102030405060708090a0b0c0d0e0f
|
||||
#r1kh=02:01:02:03:04:06 02:11:22:33:44:66 00112233445566778899aabbccddeeff
|
||||
#r1kh=02:01:02:03:04:05 02:11:22:33:44:55 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f
|
||||
#r1kh=02:01:02:03:04:06 02:11:22:33:44:66 00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff
|
||||
# And so on.. One line per R1KH.
|
||||
# Wildcard entry:
|
||||
# Upon receiving a request from an R1KH not yet known, it will be added to this
|
||||
# list and thus will receive push notifications.
|
||||
#r1kh=00:00:00:00:00:00 00:00:00:00:00:00 00112233445566778899aabbccddeeff
|
||||
|
||||
# Timeout (seconds) for newly discovered R0KH/R1KH (see wildcard entries above)
|
||||
# Special values: 0 -> do not expire
|
||||
# Warning: do not cache implies no sequence number validation with wildcards
|
||||
#rkh_pos_timeout=86400 (default = 1 day)
|
||||
|
||||
# Timeout (milliseconds) for requesting PMK-R1 from R0KH using PULL request
|
||||
# and number of retries.
|
||||
#rkh_pull_timeout=1000 (default = 1 second)
|
||||
#rkh_pull_retries=4 (default)
|
||||
|
||||
# Timeout (seconds) for non replying R0KH (see wildcard entries above)
|
||||
# Special values: 0 -> do not cache
|
||||
# default: 60 seconds
|
||||
#rkh_neg_timeout=60
|
||||
|
||||
# Note: The R0KH/R1KH keys used to be 128-bit in length before the message
|
||||
# format was changed. That shorter key length is still supported for backwards
|
||||
# compatibility of the configuration files. If such a shorter key is used, a
|
||||
# 256-bit key is derived from it. For new deployments, configuring the 256-bit
|
||||
# key is recommended.
|
||||
|
||||
# Whether PMK-R1 push is enabled at R0KH
|
||||
# 0 = do not push PMK-R1 to all configured R1KHs (default)
|
||||
@ -1326,6 +1639,14 @@ own_ip_addr=127.0.0.1
|
||||
# 1 = FT-over-DS enabled (default)
|
||||
#ft_over_ds=1
|
||||
|
||||
# Whether to generate FT response locally for PSK networks
|
||||
# This avoids use of PMK-R1 push/pull from other APs with FT-PSK networks as
|
||||
# the required information (PSK and other session data) is already locally
|
||||
# available.
|
||||
# 0 = disabled (default)
|
||||
# 1 = enabled
|
||||
#ft_psk_generate_local=0
|
||||
|
||||
##### Neighbor table ##########################################################
|
||||
# Maximum number of entries kept in AP table (either for neigbor table or for
|
||||
# detecting Overlapping Legacy BSS Condition). The oldest entry will be
|
||||
@ -1596,6 +1917,18 @@ own_ip_addr=127.0.0.1
|
||||
# 1 = enabled (allow stations to use WNM-Sleep Mode)
|
||||
#wnm_sleep_mode=1
|
||||
|
||||
# WNM-Sleep Mode GTK/IGTK workaround
|
||||
# Normally, WNM-Sleep Mode exit with management frame protection negotiated
|
||||
# would result in the current GTK/IGTK getting added into the WNM-Sleep Mode
|
||||
# Response frame. Some station implementations may have a vulnerability that
|
||||
# results in GTK/IGTK reinstallation based on this frame being replayed. This
|
||||
# configuration parameter can be used to disable that behavior and use EAPOL-Key
|
||||
# frames for GTK/IGTK update instead. This would likely be only used with
|
||||
# wpa_disable_eapol_key_retries=1 that enables a workaround for similar issues
|
||||
# with EAPOL-Key. This is related to station side vulnerabilities CVE-2017-13087
|
||||
# and CVE-2017-13088. To enable this AP-side workaround, set the parameter to 1.
|
||||
#wnm_sleep_mode_no_keys=0
|
||||
|
||||
# BSS Transition Management
|
||||
# 0 = disabled (default)
|
||||
# 1 = enabled
|
||||
@ -1683,6 +2016,15 @@ own_ip_addr=127.0.0.1
|
||||
# (double quoted string, printf-escaped string)
|
||||
#venue_name=P"eng:Example\nvenue"
|
||||
|
||||
# Venue URL information
|
||||
# This parameter can be used to configure one or more Venue URL Duples to
|
||||
# provide additional information corresponding to Venue Name information.
|
||||
# Each entry has a Venue Number value separated by colon from the Venue URL
|
||||
# string. Venue Number indicates the corresponding venue_name entry (1 = 1st
|
||||
# venue_name, 2 = 2nd venue_name, and so on; 0 = no matching venue_name)
|
||||
#venue_url=1:http://www.example.com/info-eng
|
||||
#venue_url=2:http://www.example.com/info-fin
|
||||
|
||||
# Network Authentication Type
|
||||
# This parameter indicates what type of network authentication is used in the
|
||||
# network.
|
||||
@ -1853,7 +2195,27 @@ own_ip_addr=127.0.0.1
|
||||
# channels 36-48):
|
||||
#hs20_operating_class=5173
|
||||
|
||||
# OSU icons
|
||||
# Terms and Conditions information
|
||||
#
|
||||
# hs20_t_c_filename contains the Terms and Conditions filename that the AP
|
||||
# indicates in RADIUS Access-Request messages.
|
||||
#hs20_t_c_filename=terms-and-conditions
|
||||
#
|
||||
# hs20_t_c_timestamp contains the Terms and Conditions timestamp that the AP
|
||||
# indicates in RADIUS Access-Request messages. Usually, this contains the number
|
||||
# of seconds since January 1, 1970 00:00 UTC showing the time when the file was
|
||||
# last modified.
|
||||
#hs20_t_c_timestamp=1234567
|
||||
#
|
||||
# hs20_t_c_server_url contains a template for the Terms and Conditions server
|
||||
# URL. This template is used to generate the URL for a STA that needs to
|
||||
# acknowledge Terms and Conditions. Unlike the other hs20_t_c_* parameters, this
|
||||
# parameter is used on the authentication server, not the AP.
|
||||
# Macros:
|
||||
# @1@ = MAC address of the STA (colon separated hex octets)
|
||||
#hs20_t_c_server_url=https://example.com/t_and_c?addr=@1@&ap=123
|
||||
|
||||
# OSU and Operator icons
|
||||
# <Icon Width>:<Icon Height>:<Language code>:<Icon Type>:<Name>:<file path>
|
||||
#hs20_icon=32:32:eng:image/png:icon32:/tmp/icon32.png
|
||||
#hs20_icon=64:64:eng:image/png:icon64:/tmp/icon64.png
|
||||
@ -1865,12 +2227,15 @@ own_ip_addr=127.0.0.1
|
||||
# OSU Providers
|
||||
# One or more sets of following parameter. Each OSU provider is started by the
|
||||
# mandatory osu_server_uri item. The other parameters add information for the
|
||||
# last added OSU provider.
|
||||
# last added OSU provider. osu_nai specifies the OSU_NAI value for OSEN
|
||||
# authentication when using a standalone OSU BSS. osu_nai2 specifies the OSU_NAI
|
||||
# value for OSEN authentication when using a shared BSS (Single SSID) for OSU.
|
||||
#
|
||||
#osu_server_uri=https://example.com/osu/
|
||||
#osu_friendly_name=eng:Example operator
|
||||
#osu_friendly_name=fin:Esimerkkipalveluntarjoaja
|
||||
#osu_nai=anonymous@example.com
|
||||
#osu_nai2=anonymous@example.com
|
||||
#osu_method_list=1 0
|
||||
#osu_icon=icon32
|
||||
#osu_icon=icon64
|
||||
@ -1879,6 +2244,35 @@ own_ip_addr=127.0.0.1
|
||||
#
|
||||
#osu_server_uri=...
|
||||
|
||||
# Operator Icons
|
||||
# Operator icons are specified using references to the hs20_icon entries
|
||||
# (Name subfield). This information, if present, is advertsised in the
|
||||
# Operator Icon Metadata ANQO-element.
|
||||
#operator_icon=icon32
|
||||
#operator_icon=icon64
|
||||
|
||||
##### Multiband Operation (MBO) ###############################################
|
||||
#
|
||||
# MBO enabled
|
||||
# 0 = disabled (default)
|
||||
# 1 = enabled
|
||||
#mbo=1
|
||||
#
|
||||
# Cellular data connection preference
|
||||
# 0 = Excluded - AP does not want STA to use the cellular data connection
|
||||
# 1 = AP prefers the STA not to use cellular data connection
|
||||
# 255 = AP prefers the STA to use cellular data connection
|
||||
#mbo_cell_data_conn_pref=1
|
||||
|
||||
##### Optimized Connectivity Experience (OCE) #################################
|
||||
#
|
||||
# Enable OCE specific features (bitmap)
|
||||
# BIT(0) - Reserved
|
||||
# Set BIT(1) (= 2) to enable OCE in STA-CFON mode
|
||||
# Set BIT(2) (= 4) to enable OCE in AP mode
|
||||
# Default is 0 = OCE disabled
|
||||
#oce=0
|
||||
|
||||
##### Fast Session Transfer (FST) support #####################################
|
||||
#
|
||||
# The options in this section are only available when the build configuration
|
||||
@ -1916,6 +2310,9 @@ own_ip_addr=127.0.0.1
|
||||
# Enable neighbor report via radio measurements
|
||||
#rrm_neighbor_report=1
|
||||
|
||||
# Enable beacon report via radio measurements
|
||||
#rrm_beacon_report=1
|
||||
|
||||
# Publish fine timing measurement (FTM) responder functionality
|
||||
# This parameter only controls publishing via Extended Capabilities element.
|
||||
# Actual functionality is managed outside hostapd.
|
||||
@ -1925,6 +2322,12 @@ own_ip_addr=127.0.0.1
|
||||
# This parameter only controls publishing via Extended Capabilities element.
|
||||
# Actual functionality is managed outside hostapd.
|
||||
#ftm_initiator=0
|
||||
#
|
||||
# Stationary AP config indicates that the AP doesn't move hence location data
|
||||
# can be considered as always up to date. If configured, LCI data will be sent
|
||||
# as a radio measurement even if the request doesn't contain a max age element
|
||||
# that allows sending of such data. Default: 0.
|
||||
#stationary_ap=0
|
||||
|
||||
##### TESTING OPTIONS #########################################################
|
||||
#
|
||||
|
@ -3,7 +3,8 @@ CREATE TABLE users(
|
||||
methods TEXT,
|
||||
password TEXT,
|
||||
remediation TEXT,
|
||||
phase2 INTEGER
|
||||
phase2 INTEGER,
|
||||
t_c_timestamp INTEGER
|
||||
);
|
||||
|
||||
CREATE TABLE wildcards(
|
||||
@ -24,3 +25,18 @@ CREATE TABLE authlog(
|
||||
username TEXT,
|
||||
note TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE pending_tc(
|
||||
mac_addr TEXT PRIMARY KEY,
|
||||
identity TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE current_sessions(
|
||||
mac_addr TEXT PRIMARY KEY,
|
||||
identity TEXT,
|
||||
start_time TEXT,
|
||||
nas TEXT,
|
||||
hs20_t_c_filtering BOOLEAN,
|
||||
waiting_coa_ack BOOLEAN,
|
||||
coa_ack_received BOOLEAN
|
||||
);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* hostapd - command line interface for hostapd daemon
|
||||
* Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -21,7 +21,7 @@
|
||||
|
||||
static const char *const hostapd_cli_version =
|
||||
"hostapd_cli v" VERSION_STR "\n"
|
||||
"Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> and contributors";
|
||||
"Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi> and contributors";
|
||||
|
||||
static struct wpa_ctrl *ctrl_conn;
|
||||
static int hostapd_cli_quit = 0;
|
||||
@ -45,6 +45,8 @@ static DEFINE_DL_LIST(stations); /* struct cli_txt_entry */
|
||||
static void print_help(FILE *stream, const char *cmd);
|
||||
static char ** list_cmd_list(void);
|
||||
static void hostapd_cli_receive(int sock, void *eloop_ctx, void *sock_ctx);
|
||||
static void update_stations(struct wpa_ctrl *ctrl);
|
||||
static void cli_event(const char *str);
|
||||
|
||||
|
||||
static void usage(void)
|
||||
@ -147,13 +149,45 @@ static void hostapd_cli_close_connection(void)
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_reconnect(const char *ifname)
|
||||
{
|
||||
char *next_ctrl_ifname;
|
||||
|
||||
hostapd_cli_close_connection();
|
||||
|
||||
if (!ifname)
|
||||
return -1;
|
||||
|
||||
next_ctrl_ifname = os_strdup(ifname);
|
||||
os_free(ctrl_ifname);
|
||||
ctrl_ifname = next_ctrl_ifname;
|
||||
if (!ctrl_ifname)
|
||||
return -1;
|
||||
|
||||
ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
|
||||
if (!ctrl_conn)
|
||||
return -1;
|
||||
if (!interactive && !action_file)
|
||||
return 0;
|
||||
if (wpa_ctrl_attach(ctrl_conn) == 0) {
|
||||
hostapd_cli_attached = 1;
|
||||
register_event_handler(ctrl_conn);
|
||||
update_stations(ctrl_conn);
|
||||
} else {
|
||||
printf("Warning: Failed to attach to hostapd.\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_cli_msg_cb(char *msg, size_t len)
|
||||
{
|
||||
cli_event(msg);
|
||||
printf("%s\n", msg);
|
||||
}
|
||||
|
||||
|
||||
static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
|
||||
static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, const char *cmd, int print)
|
||||
{
|
||||
char buf[4096];
|
||||
size_t len;
|
||||
@ -181,7 +215,7 @@ static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
|
||||
}
|
||||
|
||||
|
||||
static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
|
||||
static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, const char *cmd)
|
||||
{
|
||||
return _wpa_ctrl_command(ctrl, cmd, 1);
|
||||
}
|
||||
@ -286,6 +320,21 @@ static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
}
|
||||
|
||||
|
||||
static char ** hostapd_complete_stations(const char *str, int pos)
|
||||
{
|
||||
int arg = get_cmd_arg_num(str, pos);
|
||||
char **res = NULL;
|
||||
|
||||
switch (arg) {
|
||||
case 1:
|
||||
res = cli_txt_list_array(&stations);
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
@ -318,21 +367,6 @@ static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
|
||||
}
|
||||
|
||||
|
||||
static char ** hostapd_complete_deauthenticate(const char *str, int pos)
|
||||
{
|
||||
int arg = get_cmd_arg_num(str, pos);
|
||||
char **res = NULL;
|
||||
|
||||
switch (arg) {
|
||||
case 1:
|
||||
res = cli_txt_list_array(&stations);
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
@ -351,21 +385,6 @@ static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
|
||||
}
|
||||
|
||||
|
||||
static char ** hostapd_complete_disassociate(const char *str, int pos)
|
||||
{
|
||||
int arg = get_cmd_arg_num(str, pos);
|
||||
char **res = NULL;
|
||||
|
||||
switch (arg) {
|
||||
case 1:
|
||||
res = cli_txt_list_array(&stations);
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_TAXONOMY
|
||||
static int hostapd_cli_cmd_signature(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
@ -701,8 +720,8 @@ static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc,
|
||||
}
|
||||
|
||||
|
||||
static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
|
||||
char *addr, size_t addr_len)
|
||||
static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, const char *cmd,
|
||||
char *addr, size_t addr_len, int print)
|
||||
{
|
||||
char buf[4096], *pos;
|
||||
size_t len;
|
||||
@ -726,7 +745,8 @@ static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
|
||||
buf[len] = '\0';
|
||||
if (memcmp(buf, "FAIL", 4) == 0)
|
||||
return -1;
|
||||
printf("%s", buf);
|
||||
if (print)
|
||||
printf("%s", buf);
|
||||
|
||||
pos = buf;
|
||||
while (*pos != '\0' && *pos != '\n')
|
||||
@ -742,16 +762,33 @@ static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
|
||||
{
|
||||
char addr[32], cmd[64];
|
||||
|
||||
if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
|
||||
if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 1))
|
||||
return 0;
|
||||
do {
|
||||
snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
|
||||
} while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
|
||||
} while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 1) == 0);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_list_sta(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
char addr[32], cmd[64];
|
||||
|
||||
if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 0))
|
||||
return 0;
|
||||
do {
|
||||
if (os_strcmp(addr, "") != 0)
|
||||
printf("%s\n", addr);
|
||||
os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
|
||||
} while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 0) == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
print_help(stdout, argc > 0 ? argv[0] : NULL);
|
||||
@ -888,6 +925,25 @@ static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
}
|
||||
|
||||
|
||||
static void update_stations(struct wpa_ctrl *ctrl)
|
||||
{
|
||||
char addr[32], cmd[64];
|
||||
|
||||
if (!ctrl || !interactive)
|
||||
return;
|
||||
|
||||
cli_txt_list_flush(&stations);
|
||||
|
||||
if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr), 0))
|
||||
return;
|
||||
do {
|
||||
if (os_strcmp(addr, "") != 0)
|
||||
cli_txt_list_add(&stations, addr);
|
||||
os_snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
|
||||
} while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr), 0) == 0);
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_cli_get_interfaces(struct wpa_ctrl *ctrl,
|
||||
struct dl_list *interfaces)
|
||||
{
|
||||
@ -940,23 +996,7 @@ static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
|
||||
hostapd_cli_list_interfaces(ctrl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
hostapd_cli_close_connection();
|
||||
os_free(ctrl_ifname);
|
||||
ctrl_ifname = os_strdup(argv[0]);
|
||||
if (ctrl_ifname == NULL)
|
||||
return -1;
|
||||
|
||||
if (hostapd_cli_open_connection(ctrl_ifname)) {
|
||||
printf("Connected to interface '%s.\n", ctrl_ifname);
|
||||
if (wpa_ctrl_attach(ctrl_conn) == 0) {
|
||||
hostapd_cli_attached = 1;
|
||||
register_event_handler(ctrl_conn);
|
||||
} else {
|
||||
printf("Warning: Failed to attach to "
|
||||
"hostapd.\n");
|
||||
}
|
||||
} else {
|
||||
if (hostapd_cli_reconnect(argv[0]) != 0) {
|
||||
printf("Could not connect to interface '%s' - re-trying\n",
|
||||
ctrl_ifname);
|
||||
}
|
||||
@ -984,7 +1024,7 @@ static char ** hostapd_complete_interface(const char *str, int pos)
|
||||
|
||||
static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
char cmd[256];
|
||||
char cmd[2048];
|
||||
int res;
|
||||
|
||||
if (argc != 2) {
|
||||
@ -1002,6 +1042,44 @@ static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
}
|
||||
|
||||
|
||||
static char ** hostapd_complete_set(const char *str, int pos)
|
||||
{
|
||||
int arg = get_cmd_arg_num(str, pos);
|
||||
const char *fields[] = {
|
||||
#ifdef CONFIG_WPS_TESTING
|
||||
"wps_version_number", "wps_testing_dummy_cred",
|
||||
"wps_corrupt_pkhash",
|
||||
#endif /* CONFIG_WPS_TESTING */
|
||||
#ifdef CONFIG_INTERWORKING
|
||||
"gas_frag_limit",
|
||||
#endif /* CONFIG_INTERWORKING */
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
"ext_mgmt_frame_handling", "ext_eapol_frame_io",
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
#ifdef CONFIG_MBO
|
||||
"mbo_assoc_disallow",
|
||||
#endif /* CONFIG_MBO */
|
||||
"deny_mac_file", "accept_mac_file",
|
||||
};
|
||||
int i, num_fields = ARRAY_SIZE(fields);
|
||||
|
||||
if (arg == 1) {
|
||||
char **res;
|
||||
|
||||
res = os_calloc(num_fields + 1, sizeof(char *));
|
||||
if (!res)
|
||||
return NULL;
|
||||
for (i = 0; i < num_fields; i++) {
|
||||
res[i] = os_strdup(fields[i]);
|
||||
if (!res[i])
|
||||
return res;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
char cmd[256];
|
||||
@ -1022,6 +1100,31 @@ static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
}
|
||||
|
||||
|
||||
static char ** hostapd_complete_get(const char *str, int pos)
|
||||
{
|
||||
int arg = get_cmd_arg_num(str, pos);
|
||||
const char *fields[] = {
|
||||
"version", "tls_library",
|
||||
};
|
||||
int i, num_fields = ARRAY_SIZE(fields);
|
||||
|
||||
if (arg == 1) {
|
||||
char **res;
|
||||
|
||||
res = os_calloc(num_fields + 1, sizeof(char *));
|
||||
if (!res)
|
||||
return NULL;
|
||||
for (i = 0; i < num_fields; i++) {
|
||||
res[i] = os_strdup(fields[i]);
|
||||
if (!res[i])
|
||||
return res;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_FST
|
||||
static int hostapd_cli_cmd_fst(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
@ -1185,14 +1288,14 @@ static int hostapd_cli_cmd_set_neighbor(struct wpa_ctrl *ctrl, int argc,
|
||||
char cmd[2048];
|
||||
int res;
|
||||
|
||||
if (argc < 3 || argc > 5) {
|
||||
printf("Invalid set_neighbor command: needs 3-5 arguments\n");
|
||||
if (argc < 3 || argc > 6) {
|
||||
printf("Invalid set_neighbor command: needs 3-6 arguments\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = os_snprintf(cmd, sizeof(cmd), "SET_NEIGHBOR %s %s %s %s %s",
|
||||
res = os_snprintf(cmd, sizeof(cmd), "SET_NEIGHBOR %s %s %s %s %s %s",
|
||||
argv[0], argv[1], argv[2], argc >= 4 ? argv[3] : "",
|
||||
argc == 5 ? argv[4] : "");
|
||||
argc >= 5 ? argv[4] : "", argc == 6 ? argv[5] : "");
|
||||
if (os_snprintf_error(sizeof(cmd), res)) {
|
||||
printf("Too long SET_NEIGHBOR command.\n");
|
||||
return -1;
|
||||
@ -1261,6 +1364,122 @@ static int hostapd_cli_cmd_driver_flags(struct wpa_ctrl *ctrl, int argc,
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_DPP
|
||||
|
||||
static int hostapd_cli_cmd_dpp_qr_code(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "DPP_QR_CODE", 1, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_dpp_bootstrap_gen(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_GEN", 1, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_dpp_bootstrap_remove(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_REMOVE", 1, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_dpp_bootstrap_get_uri(struct wpa_ctrl *ctrl,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_GET_URI", 1, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_dpp_bootstrap_info(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_INFO", 1, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_dpp_auth_init(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "DPP_AUTH_INIT", 1, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_dpp_listen(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "DPP_LISTEN", 1, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_dpp_stop_listen(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return wpa_ctrl_command(ctrl, "DPP_STOP_LISTEN");
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_dpp_configurator_add(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "DPP_CONFIGURATOR_ADD", 0, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_dpp_configurator_remove(struct wpa_ctrl *ctrl,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "DPP_CONFIGURATOR_REMOVE", 1, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_dpp_configurator_get_key(struct wpa_ctrl *ctrl,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "DPP_CONFIGURATOR_GET_KEY", 1, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_dpp_pkex_add(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "DPP_PKEX_ADD", 1, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_dpp_pkex_remove(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "DPP_PKEX_REMOVE", 1, argc, argv);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_accept_macacl(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "ACCEPT_ACL", 1, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_deny_macacl(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "DENY_ACL", 1, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_poll_sta(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return hostapd_cli_cmd(ctrl, "POLL_STA", 1, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
struct hostapd_cli_cmd {
|
||||
const char *cmd;
|
||||
int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
|
||||
@ -1273,26 +1492,30 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
|
||||
"= pings hostapd" },
|
||||
{ "mib", hostapd_cli_cmd_mib, NULL,
|
||||
"= get MIB variables (dot1x, dot11, radius)" },
|
||||
{ "relog", hostapd_cli_cmd_relog, NULL, NULL },
|
||||
{ "status", hostapd_cli_cmd_status, NULL, NULL },
|
||||
{ "sta", hostapd_cli_cmd_sta, NULL,
|
||||
{ "relog", hostapd_cli_cmd_relog, NULL,
|
||||
"= reload/truncate debug log output file" },
|
||||
{ "status", hostapd_cli_cmd_status, NULL,
|
||||
"= show interface status info" },
|
||||
{ "sta", hostapd_cli_cmd_sta, hostapd_complete_stations,
|
||||
"<addr> = get MIB variables for one station" },
|
||||
{ "all_sta", hostapd_cli_cmd_all_sta, NULL,
|
||||
"= get MIB variables for all stations" },
|
||||
{ "list_sta", hostapd_cli_cmd_list_sta, NULL,
|
||||
"= list all stations" },
|
||||
{ "new_sta", hostapd_cli_cmd_new_sta, NULL,
|
||||
"<addr> = add a new station" },
|
||||
{ "deauthenticate", hostapd_cli_cmd_deauthenticate,
|
||||
hostapd_complete_deauthenticate,
|
||||
hostapd_complete_stations,
|
||||
"<addr> = deauthenticate a station" },
|
||||
{ "disassociate", hostapd_cli_cmd_disassociate,
|
||||
hostapd_complete_disassociate,
|
||||
hostapd_complete_stations,
|
||||
"<addr> = disassociate a station" },
|
||||
#ifdef CONFIG_TAXONOMY
|
||||
{ "signature", hostapd_cli_cmd_signature, NULL,
|
||||
{ "signature", hostapd_cli_cmd_signature, hostapd_complete_stations,
|
||||
"<addr> = get taxonomy signature for a station" },
|
||||
#endif /* CONFIG_TAXONOMY */
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
{ "sa_query", hostapd_cli_cmd_sa_query, NULL,
|
||||
{ "sa_query", hostapd_cli_cmd_sa_query, hostapd_complete_stations,
|
||||
"<addr> = send SA Query to a station" },
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
#ifdef CONFIG_WPS
|
||||
@ -1321,9 +1544,12 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
|
||||
{ "wps_get_status", hostapd_cli_cmd_wps_get_status, NULL,
|
||||
"= show current WPS status" },
|
||||
#endif /* CONFIG_WPS */
|
||||
{ "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent, NULL, NULL },
|
||||
{ "ess_disassoc", hostapd_cli_cmd_ess_disassoc, NULL, NULL },
|
||||
{ "bss_tm_req", hostapd_cli_cmd_bss_tm_req, NULL, NULL },
|
||||
{ "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent, NULL,
|
||||
"= send Disassociation Imminent notification" },
|
||||
{ "ess_disassoc", hostapd_cli_cmd_ess_disassoc, NULL,
|
||||
"= send ESS Dissassociation Imminent notification" },
|
||||
{ "bss_tm_req", hostapd_cli_cmd_bss_tm_req, NULL,
|
||||
"= send BSS Transition Management Request" },
|
||||
{ "get_config", hostapd_cli_cmd_get_config, NULL,
|
||||
"= show current configuration" },
|
||||
{ "help", hostapd_cli_cmd_help, hostapd_cli_complete_help,
|
||||
@ -1331,35 +1557,100 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
|
||||
{ "interface", hostapd_cli_cmd_interface, hostapd_complete_interface,
|
||||
"[ifname] = show interfaces/select interface" },
|
||||
#ifdef CONFIG_FST
|
||||
{ "fst", hostapd_cli_cmd_fst, NULL, NULL },
|
||||
{ "fst", hostapd_cli_cmd_fst, NULL,
|
||||
"<params...> = send FST-MANAGER control interface command" },
|
||||
#endif /* CONFIG_FST */
|
||||
{ "raw", hostapd_cli_cmd_raw, NULL, NULL },
|
||||
{ "raw", hostapd_cli_cmd_raw, NULL,
|
||||
"<params..> = send unprocessed command" },
|
||||
{ "level", hostapd_cli_cmd_level, NULL,
|
||||
"<debug level> = change debug level" },
|
||||
{ "license", hostapd_cli_cmd_license, NULL,
|
||||
"= show full hostapd_cli license" },
|
||||
{ "quit", hostapd_cli_cmd_quit, NULL,
|
||||
"= exit hostapd_cli" },
|
||||
{ "set", hostapd_cli_cmd_set, NULL, NULL },
|
||||
{ "get", hostapd_cli_cmd_get, NULL, NULL },
|
||||
{ "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set, NULL, NULL },
|
||||
{ "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf, NULL, NULL },
|
||||
{ "chan_switch", hostapd_cli_cmd_chan_switch, NULL, NULL },
|
||||
{ "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif, NULL, NULL },
|
||||
{ "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req, NULL, NULL },
|
||||
{ "vendor", hostapd_cli_cmd_vendor, NULL, NULL },
|
||||
{ "enable", hostapd_cli_cmd_enable, NULL, NULL },
|
||||
{ "reload", hostapd_cli_cmd_reload, NULL, NULL },
|
||||
{ "disable", hostapd_cli_cmd_disable, NULL, NULL },
|
||||
{ "erp_flush", hostapd_cli_cmd_erp_flush, NULL, NULL },
|
||||
{ "log_level", hostapd_cli_cmd_log_level, NULL, NULL },
|
||||
{ "pmksa", hostapd_cli_cmd_pmksa, NULL, NULL },
|
||||
{ "pmksa_flush", hostapd_cli_cmd_pmksa_flush, NULL, NULL },
|
||||
{ "set_neighbor", hostapd_cli_cmd_set_neighbor, NULL, NULL },
|
||||
{ "remove_neighbor", hostapd_cli_cmd_remove_neighbor, NULL, NULL },
|
||||
{ "req_lci", hostapd_cli_cmd_req_lci, NULL, NULL },
|
||||
{ "req_range", hostapd_cli_cmd_req_range, NULL, NULL },
|
||||
{ "driver_flags", hostapd_cli_cmd_driver_flags, NULL, NULL },
|
||||
{ "set", hostapd_cli_cmd_set, hostapd_complete_set,
|
||||
"<name> <value> = set runtime variables" },
|
||||
{ "get", hostapd_cli_cmd_get, hostapd_complete_get,
|
||||
"<name> = get runtime info" },
|
||||
{ "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set, NULL,
|
||||
"<arg,arg,...> = set QoS Map set element" },
|
||||
{ "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf,
|
||||
hostapd_complete_stations,
|
||||
"<addr> = send QoS Map Configure frame" },
|
||||
{ "chan_switch", hostapd_cli_cmd_chan_switch, NULL,
|
||||
"<cs_count> <freq> [sec_channel_offset=] [center_freq1=]\n"
|
||||
" [center_freq2=] [bandwidth=] [blocktx] [ht|vht]\n"
|
||||
" = initiate channel switch announcement" },
|
||||
{ "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif, NULL,
|
||||
"<addr> <url>\n"
|
||||
" = send WNM-Notification Subscription Remediation Request" },
|
||||
{ "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req, NULL,
|
||||
"<addr> <code (0/1)> <Re-auth-Delay(sec)> [url]\n"
|
||||
" = send WNM-Notification imminent deauthentication indication" },
|
||||
{ "vendor", hostapd_cli_cmd_vendor, NULL,
|
||||
"<vendor id> <sub command id> [<hex formatted data>]\n"
|
||||
" = send vendor driver command" },
|
||||
{ "enable", hostapd_cli_cmd_enable, NULL,
|
||||
"= enable hostapd on current interface" },
|
||||
{ "reload", hostapd_cli_cmd_reload, NULL,
|
||||
"= reload configuration for current interface" },
|
||||
{ "disable", hostapd_cli_cmd_disable, NULL,
|
||||
"= disable hostapd on current interface" },
|
||||
{ "erp_flush", hostapd_cli_cmd_erp_flush, NULL,
|
||||
"= drop all ERP keys"},
|
||||
{ "log_level", hostapd_cli_cmd_log_level, NULL,
|
||||
"[level] = show/change log verbosity level" },
|
||||
{ "pmksa", hostapd_cli_cmd_pmksa, NULL,
|
||||
" = show PMKSA cache entries" },
|
||||
{ "pmksa_flush", hostapd_cli_cmd_pmksa_flush, NULL,
|
||||
" = flush PMKSA cache" },
|
||||
{ "set_neighbor", hostapd_cli_cmd_set_neighbor, NULL,
|
||||
"<addr> <ssid=> <nr=> [lci=] [civic=] [stat]\n"
|
||||
" = add AP to neighbor database" },
|
||||
{ "remove_neighbor", hostapd_cli_cmd_remove_neighbor, NULL,
|
||||
"<addr> <ssid=> = remove AP from neighbor database" },
|
||||
{ "req_lci", hostapd_cli_cmd_req_lci, hostapd_complete_stations,
|
||||
"<addr> = send LCI request to a station"},
|
||||
{ "req_range", hostapd_cli_cmd_req_range, NULL,
|
||||
" = send FTM range request"},
|
||||
{ "driver_flags", hostapd_cli_cmd_driver_flags, NULL,
|
||||
" = show supported driver flags"},
|
||||
#ifdef CONFIG_DPP
|
||||
{ "dpp_qr_code", hostapd_cli_cmd_dpp_qr_code, NULL,
|
||||
"report a scanned DPP URI from a QR Code" },
|
||||
{ "dpp_bootstrap_gen", hostapd_cli_cmd_dpp_bootstrap_gen, NULL,
|
||||
"type=<qrcode> [chan=..] [mac=..] [info=..] [curve=..] [key=..] = generate DPP bootstrap information" },
|
||||
{ "dpp_bootstrap_remove", hostapd_cli_cmd_dpp_bootstrap_remove, NULL,
|
||||
"*|<id> = remove DPP bootstrap information" },
|
||||
{ "dpp_bootstrap_get_uri", hostapd_cli_cmd_dpp_bootstrap_get_uri, NULL,
|
||||
"<id> = get DPP bootstrap URI" },
|
||||
{ "dpp_bootstrap_info", hostapd_cli_cmd_dpp_bootstrap_info, NULL,
|
||||
"<id> = show DPP bootstrap information" },
|
||||
{ "dpp_auth_init", hostapd_cli_cmd_dpp_auth_init, NULL,
|
||||
"peer=<id> [own=<id>] = initiate DPP bootstrapping" },
|
||||
{ "dpp_listen", hostapd_cli_cmd_dpp_listen, NULL,
|
||||
"<freq in MHz> = start DPP listen" },
|
||||
{ "dpp_stop_listen", hostapd_cli_cmd_dpp_stop_listen, NULL,
|
||||
"= stop DPP listen" },
|
||||
{ "dpp_configurator_add", hostapd_cli_cmd_dpp_configurator_add, NULL,
|
||||
"[curve=..] [key=..] = add DPP configurator" },
|
||||
{ "dpp_configurator_remove", hostapd_cli_cmd_dpp_configurator_remove,
|
||||
NULL,
|
||||
"*|<id> = remove DPP configurator" },
|
||||
{ "dpp_configurator_get_key", hostapd_cli_cmd_dpp_configurator_get_key,
|
||||
NULL,
|
||||
"<id> = Get DPP configurator's private key" },
|
||||
{ "dpp_pkex_add", hostapd_cli_cmd_dpp_pkex_add, NULL,
|
||||
"add PKEX code" },
|
||||
{ "dpp_pkex_remove", hostapd_cli_cmd_dpp_pkex_remove, NULL,
|
||||
"*|<id> = remove DPP pkex information" },
|
||||
#endif /* CONFIG_DPP */
|
||||
{ "accept_acl", hostapd_cli_cmd_accept_macacl, NULL,
|
||||
"=Add/Delete/Show/Clear accept MAC ACL" },
|
||||
{ "deny_acl", hostapd_cli_cmd_deny_macacl, NULL,
|
||||
"=Add/Delete/Show/Clear deny MAC ACL" },
|
||||
{ "poll_sta", hostapd_cli_cmd_poll_sta, hostapd_complete_stations,
|
||||
"<addr> = poll a STA to check connectivity with a QoS null frame" },
|
||||
{ NULL, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
@ -1471,7 +1762,7 @@ static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
|
||||
if (ctrl_conn == NULL)
|
||||
return;
|
||||
while (wpa_ctrl_pending(ctrl)) {
|
||||
char buf[256];
|
||||
char buf[4096];
|
||||
size_t len = sizeof(buf) - 1;
|
||||
if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
|
||||
buf[len] = '\0';
|
||||
@ -1504,19 +1795,8 @@ static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx)
|
||||
printf("Connection to hostapd lost - trying to reconnect\n");
|
||||
hostapd_cli_close_connection();
|
||||
}
|
||||
if (!ctrl_conn) {
|
||||
ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
|
||||
if (ctrl_conn) {
|
||||
printf("Connection to hostapd re-established\n");
|
||||
if (wpa_ctrl_attach(ctrl_conn) == 0) {
|
||||
hostapd_cli_attached = 1;
|
||||
register_event_handler(ctrl_conn);
|
||||
} else {
|
||||
printf("Warning: Failed to attach to "
|
||||
"hostapd.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!ctrl_conn && hostapd_cli_reconnect(ctrl_ifname) == 0)
|
||||
printf("Connection to hostapd re-established\n");
|
||||
if (ctrl_conn)
|
||||
hostapd_cli_recv_pending(ctrl_conn, 1, 0);
|
||||
eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
|
||||
@ -1611,17 +1891,34 @@ static char ** hostapd_cli_edit_completion_cb(void *ctx, const char *str,
|
||||
|
||||
static void hostapd_cli_interactive(void)
|
||||
{
|
||||
char *hfile = NULL;
|
||||
char *home;
|
||||
|
||||
printf("\nInteractive mode\n\n");
|
||||
|
||||
#ifdef CONFIG_HOSTAPD_CLI_HISTORY_DIR
|
||||
home = CONFIG_HOSTAPD_CLI_HISTORY_DIR;
|
||||
#else /* CONFIG_HOSTAPD_CLI_HISTORY_DIR */
|
||||
home = getenv("HOME");
|
||||
#endif /* CONFIG_HOSTAPD_CLI_HISTORY_DIR */
|
||||
if (home) {
|
||||
const char *fname = ".hostapd_cli_history";
|
||||
int hfile_len = os_strlen(home) + 1 + os_strlen(fname) + 1;
|
||||
hfile = os_malloc(hfile_len);
|
||||
if (hfile)
|
||||
os_snprintf(hfile, hfile_len, "%s/%s", home, fname);
|
||||
}
|
||||
|
||||
eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
|
||||
edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
|
||||
hostapd_cli_edit_completion_cb, NULL, NULL, NULL);
|
||||
hostapd_cli_edit_completion_cb, NULL, hfile, NULL);
|
||||
eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
|
||||
|
||||
eloop_run();
|
||||
|
||||
cli_txt_list_flush(&stations);
|
||||
edit_deinit(NULL, NULL);
|
||||
edit_deinit(hfile, NULL);
|
||||
os_free(hfile);
|
||||
eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
|
||||
}
|
||||
|
||||
@ -1748,7 +2045,7 @@ int main(int argc, char *argv[])
|
||||
closedir(dir);
|
||||
}
|
||||
}
|
||||
ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
|
||||
hostapd_cli_reconnect(ctrl_ifname);
|
||||
if (ctrl_conn) {
|
||||
if (warning_displayed)
|
||||
printf("Connection established.\n");
|
||||
@ -1769,17 +2066,8 @@ int main(int argc, char *argv[])
|
||||
continue;
|
||||
}
|
||||
|
||||
if (interactive || action_file) {
|
||||
if (wpa_ctrl_attach(ctrl_conn) == 0) {
|
||||
hostapd_cli_attached = 1;
|
||||
register_event_handler(ctrl_conn);
|
||||
} else {
|
||||
printf("Warning: Failed to attach to hostapd.\n");
|
||||
if (action_file)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (action_file && !hostapd_cli_attached)
|
||||
return -1;
|
||||
if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue())
|
||||
return -1;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* hostapd / main()
|
||||
* Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -24,6 +24,7 @@
|
||||
#include "ap/hostapd.h"
|
||||
#include "ap/ap_config.h"
|
||||
#include "ap/ap_drv_ops.h"
|
||||
#include "ap/dpp_hostapd.h"
|
||||
#include "fst/fst.h"
|
||||
#include "config_file.h"
|
||||
#include "eap_register.h"
|
||||
@ -108,6 +109,10 @@ static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
|
||||
module_str ? module_str : "",
|
||||
module_str ? ": " : "", txt);
|
||||
|
||||
#ifdef CONFIG_DEBUG_SYSLOG
|
||||
if (wpa_debug_syslog)
|
||||
conf_stdout = 0;
|
||||
#endif /* CONFIG_DEBUG_SYSLOG */
|
||||
if ((conf_stdout & module) && level >= conf_stdout_level) {
|
||||
wpa_debug_print_timestamp();
|
||||
wpa_printf(MSG_INFO, "%s", format);
|
||||
@ -248,7 +253,7 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
|
||||
*
|
||||
* This function is used to parse configuration file for a full interface (one
|
||||
* or more BSSes sharing the same radio) and allocate memory for the BSS
|
||||
* interfaces. No actiual driver operations are started.
|
||||
* interfaces. No actual driver operations are started.
|
||||
*/
|
||||
static struct hostapd_iface *
|
||||
hostapd_interface_init(struct hapd_interfaces *interfaces, const char *if_name,
|
||||
@ -451,7 +456,7 @@ static void show_version(void)
|
||||
"hostapd v" VERSION_STR "\n"
|
||||
"User space daemon for IEEE 802.11 AP management,\n"
|
||||
"IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
|
||||
"Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> "
|
||||
"Copyright (c) 2002-2018, Jouni Malinen <j@w1.fi> "
|
||||
"and contributors\n");
|
||||
}
|
||||
|
||||
@ -480,10 +485,13 @@ static void usage(void)
|
||||
" -f log output to debug file instead of stdout\n"
|
||||
#endif /* CONFIG_DEBUG_FILE */
|
||||
#ifdef CONFIG_DEBUG_LINUX_TRACING
|
||||
" -T = record to Linux tracing in addition to logging\n"
|
||||
" -T record to Linux tracing in addition to logging\n"
|
||||
" (records all messages regardless of debug verbosity)\n"
|
||||
#endif /* CONFIG_DEBUG_LINUX_TRACING */
|
||||
" -i list of interface names to use\n"
|
||||
#ifdef CONFIG_DEBUG_SYSLOG
|
||||
" -s log output to syslog instead of stdout\n"
|
||||
#endif /* CONFIG_DEBUG_SYSLOG */
|
||||
" -S start all the interfaces synchronously\n"
|
||||
" -t include timestamps in some debug messages\n"
|
||||
" -v show hostapd version\n");
|
||||
@ -549,14 +557,14 @@ static int hostapd_get_ctrl_iface_group(struct hapd_interfaces *interfaces,
|
||||
|
||||
static int hostapd_get_interface_names(char ***if_names,
|
||||
size_t *if_names_size,
|
||||
char *optarg)
|
||||
char *arg)
|
||||
{
|
||||
char *if_name, *tmp, **nnames;
|
||||
size_t i;
|
||||
|
||||
if (!optarg)
|
||||
if (!arg)
|
||||
return -1;
|
||||
if_name = strtok_r(optarg, ",", &tmp);
|
||||
if_name = strtok_r(arg, ",", &tmp);
|
||||
|
||||
while (if_name) {
|
||||
nnames = os_realloc_array(*if_names, 1 + *if_names_size,
|
||||
@ -659,9 +667,15 @@ int main(int argc, char *argv[])
|
||||
interfaces.global_iface_name = NULL;
|
||||
interfaces.global_ctrl_sock = -1;
|
||||
dl_list_init(&interfaces.global_ctrl_dst);
|
||||
#ifdef CONFIG_ETH_P_OUI
|
||||
dl_list_init(&interfaces.eth_p_oui);
|
||||
#endif /* CONFIG_ETH_P_OUI */
|
||||
#ifdef CONFIG_DPP
|
||||
hostapd_dpp_init_global(&interfaces);
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
for (;;) {
|
||||
c = getopt(argc, argv, "b:Bde:f:hi:KP:STtu:vg:G:");
|
||||
c = getopt(argc, argv, "b:Bde:f:hi:KP:sSTtu:vg:G:");
|
||||
if (c < 0)
|
||||
break;
|
||||
switch (c) {
|
||||
@ -718,6 +732,11 @@ int main(int argc, char *argv[])
|
||||
bss_config = tmp_bss;
|
||||
bss_config[num_bss_configs++] = optarg;
|
||||
break;
|
||||
#ifdef CONFIG_DEBUG_SYSLOG
|
||||
case 's':
|
||||
wpa_debug_syslog = 1;
|
||||
break;
|
||||
#endif /* CONFIG_DEBUG_SYSLOG */
|
||||
case 'S':
|
||||
start_ifaces_in_sync = 1;
|
||||
break;
|
||||
@ -746,6 +765,10 @@ int main(int argc, char *argv[])
|
||||
wpa_debug_open_file(log_file);
|
||||
else
|
||||
wpa_debug_setup_stdout();
|
||||
#ifdef CONFIG_DEBUG_SYSLOG
|
||||
if (wpa_debug_syslog)
|
||||
wpa_debug_open_syslog();
|
||||
#endif /* CONFIG_DEBUG_SYSLOG */
|
||||
#ifdef CONFIG_DEBUG_LINUX_TRACING
|
||||
if (enable_trace_dbg) {
|
||||
int tret = wpa_debug_open_linux_tracing();
|
||||
@ -877,11 +900,16 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
os_free(interfaces.iface);
|
||||
|
||||
#ifdef CONFIG_DPP
|
||||
hostapd_dpp_deinit_global(&interfaces);
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
if (interfaces.eloop_initialized)
|
||||
eloop_cancel_timeout(hostapd_periodic, &interfaces, NULL);
|
||||
hostapd_global_deinit(pid_file, interfaces.eloop_initialized);
|
||||
os_free(pid_file);
|
||||
|
||||
wpa_debug_close_syslog();
|
||||
if (log_file)
|
||||
wpa_debug_close_file();
|
||||
wpa_debug_close_linux_tracing();
|
||||
|
@ -666,7 +666,6 @@ int est_simple_enroll(struct hs20_osu_client *ctx, const char *url,
|
||||
char *buf, *resp, *req, *req2;
|
||||
size_t buflen, resp_len, len, pkcs7_len;
|
||||
unsigned char *pkcs7;
|
||||
FILE *f;
|
||||
char client_cert_buf[200];
|
||||
char client_key_buf[200];
|
||||
const char *client_cert = NULL, *client_key = NULL;
|
||||
@ -721,11 +720,6 @@ int est_simple_enroll(struct hs20_osu_client *ctx, const char *url,
|
||||
return -1;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "EST simpleenroll response: %s", resp);
|
||||
f = fopen("Cert/est-resp.raw", "w");
|
||||
if (f) {
|
||||
fwrite(resp, resp_len, 1, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
pkcs7 = base64_decode((unsigned char *) resp, resp_len, &pkcs7_len);
|
||||
if (pkcs7 == NULL) {
|
||||
|
@ -111,6 +111,12 @@ static xml_node_t * oma_dm_build_hdr(struct hs20_osu_client *ctx,
|
||||
xml_node_t *syncml, *synchdr;
|
||||
xml_namespace_t *ns;
|
||||
|
||||
if (!ctx->devid) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"DevId from devinfo.xml is not available - cannot use OMA DM");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
syncml = xml_node_create_root(ctx->xml, "SYNCML:SYNCML1.2", NULL, &ns,
|
||||
"SyncML");
|
||||
|
||||
|
@ -105,6 +105,35 @@ static int valid_fqdn(const char *fqdn)
|
||||
}
|
||||
|
||||
|
||||
static int android_update_permission(const char *path, mode_t mode)
|
||||
{
|
||||
#ifdef ANDROID
|
||||
/* we need to change file/folder permission for Android */
|
||||
|
||||
if (!path) {
|
||||
wpa_printf(MSG_ERROR, "file path null");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Allow processes running with Group ID as AID_WIFI,
|
||||
* to read files from SP, SP/<fqdn>, Cert and osu-info directories */
|
||||
if (chown(path, -1, AID_WIFI)) {
|
||||
wpa_printf(MSG_INFO, "CTRL: Could not chown directory: %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (chmod(path, mode) < 0) {
|
||||
wpa_printf(MSG_INFO, "CTRL: Could not chmod directory: %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
#endif /* ANDROID */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int osu_get_certificate(struct hs20_osu_client *ctx, xml_node_t *getcert)
|
||||
{
|
||||
xml_node_t *node;
|
||||
@ -169,6 +198,8 @@ int osu_get_certificate(struct hs20_osu_client *ctx, xml_node_t *getcert)
|
||||
}
|
||||
|
||||
mkdir("Cert", S_IRWXU);
|
||||
android_update_permission("Cert", S_IRWXU | S_IRWXG);
|
||||
|
||||
if (est_load_cacerts(ctx, url) < 0 ||
|
||||
est_build_csr(ctx, url) < 0 ||
|
||||
est_simple_enroll(ctx, url, user, pw) < 0)
|
||||
@ -262,7 +293,6 @@ static int process_est_cert(struct hs20_osu_client *ctx, xml_node_t *cert,
|
||||
|
||||
unlink("Cert/est-req.b64");
|
||||
unlink("Cert/est-req.pem");
|
||||
unlink("Cert/est-resp.raw");
|
||||
rmdir("Cert");
|
||||
|
||||
return 0;
|
||||
@ -406,7 +436,7 @@ static int cmd_dl_polupd_ca(struct hs20_osu_client *ctx, const char *pps_fname,
|
||||
if (node == NULL) {
|
||||
wpa_printf(MSG_INFO, "No Policy/PolicyUpdate/TrustRoot/CertURL found from PPS");
|
||||
xml_node_free(ctx->xml, pps);
|
||||
return -1;
|
||||
return -2;
|
||||
}
|
||||
|
||||
ret = download_cert(ctx, node, ca_fname);
|
||||
@ -433,7 +463,7 @@ static int cmd_dl_aaa_ca(struct hs20_osu_client *ctx, const char *pps_fname,
|
||||
if (node == NULL) {
|
||||
wpa_printf(MSG_INFO, "No AAAServerTrustRoot/CertURL found from PPS");
|
||||
xml_node_free(ctx->xml, pps);
|
||||
return -1;
|
||||
return -2;
|
||||
}
|
||||
|
||||
aaa = xml_node_first_child(ctx->xml, node);
|
||||
@ -455,7 +485,7 @@ static int download_trust_roots(struct hs20_osu_client *ctx,
|
||||
{
|
||||
char *dir, *pos;
|
||||
char fname[300];
|
||||
int ret;
|
||||
int ret, ret1;
|
||||
|
||||
dir = os_strdup(pps_fname);
|
||||
if (dir == NULL)
|
||||
@ -470,9 +500,13 @@ static int download_trust_roots(struct hs20_osu_client *ctx,
|
||||
snprintf(fname, sizeof(fname), "%s/ca.pem", dir);
|
||||
ret = cmd_dl_osu_ca(ctx, pps_fname, fname);
|
||||
snprintf(fname, sizeof(fname), "%s/polupd-ca.pem", dir);
|
||||
cmd_dl_polupd_ca(ctx, pps_fname, fname);
|
||||
ret1 = cmd_dl_polupd_ca(ctx, pps_fname, fname);
|
||||
if (ret == 0 && ret1 == -1)
|
||||
ret = -1;
|
||||
snprintf(fname, sizeof(fname), "%s/aaa-ca.pem", dir);
|
||||
cmd_dl_aaa_ca(ctx, pps_fname, fname);
|
||||
ret1 = cmd_dl_aaa_ca(ctx, pps_fname, fname);
|
||||
if (ret == 0 && ret1 == -1)
|
||||
ret = -1;
|
||||
|
||||
os_free(dir);
|
||||
|
||||
@ -578,20 +612,8 @@ int hs20_add_pps_mo(struct hs20_osu_client *ctx, const char *uri,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
/* Allow processes running with Group ID as AID_WIFI,
|
||||
* to read files from SP/<fqdn> directory */
|
||||
if (chown(fname, -1, AID_WIFI)) {
|
||||
wpa_printf(MSG_INFO, "CTRL: Could not chown directory: %s",
|
||||
strerror(errno));
|
||||
/* Try to continue anyway */
|
||||
}
|
||||
if (chmod(fname, S_IRWXU | S_IRGRP | S_IXGRP) < 0) {
|
||||
wpa_printf(MSG_INFO, "CTRL: Could not chmod directory: %s",
|
||||
strerror(errno));
|
||||
/* Try to continue anyway */
|
||||
}
|
||||
#endif /* ANDROID */
|
||||
android_update_permission("SP", S_IRWXU | S_IRGRP | S_IXGRP);
|
||||
android_update_permission(fname, S_IRWXU | S_IRGRP | S_IXGRP);
|
||||
|
||||
snprintf(fname, fname_len, "SP/%s/pps.xml", fqdn);
|
||||
|
||||
@ -1213,8 +1235,7 @@ static void set_pps_cred_home_sp_oi(struct hs20_osu_client *ctx, int id,
|
||||
homeoi) < 0)
|
||||
wpa_printf(MSG_INFO, "Failed to set cred required_roaming_consortium");
|
||||
} else {
|
||||
if (set_cred_quoted(ctx->ifname, id, "roaming_consortium",
|
||||
homeoi) < 0)
|
||||
if (set_cred(ctx->ifname, id, "roaming_consortium", homeoi) < 0)
|
||||
wpa_printf(MSG_INFO, "Failed to set cred roaming_consortium");
|
||||
}
|
||||
|
||||
@ -1289,7 +1310,9 @@ static void set_pps_cred_home_sp_roaming_consortium_oi(
|
||||
if (str == NULL)
|
||||
return;
|
||||
wpa_printf(MSG_INFO, "- HomeSP/RoamingConsortiumOI = %s", str);
|
||||
/* TODO: Set to wpa_supplicant */
|
||||
if (set_cred_quoted(ctx->ifname, id, "roaming_consortiums",
|
||||
str) < 0)
|
||||
wpa_printf(MSG_INFO, "Failed to set cred roaming_consortiums");
|
||||
xml_node_get_text_free(ctx->xml, str);
|
||||
}
|
||||
|
||||
@ -1442,10 +1465,92 @@ static void set_pps_cred_able_to_share(struct hs20_osu_client *ctx, int id,
|
||||
}
|
||||
|
||||
|
||||
static void set_pps_cred_eap_method_eap_type(struct hs20_osu_client *ctx,
|
||||
int id, xml_node_t *node)
|
||||
{
|
||||
char *str = xml_node_get_text(ctx->xml, node);
|
||||
int type;
|
||||
const char *eap_method = NULL;
|
||||
|
||||
if (!str)
|
||||
return;
|
||||
wpa_printf(MSG_INFO,
|
||||
"- Credential/UsernamePassword/EAPMethod/EAPType = %s", str);
|
||||
type = atoi(str);
|
||||
switch (type) {
|
||||
case EAP_TYPE_TLS:
|
||||
eap_method = "TLS";
|
||||
break;
|
||||
case EAP_TYPE_TTLS:
|
||||
eap_method = "TTLS";
|
||||
break;
|
||||
case EAP_TYPE_PEAP:
|
||||
eap_method = "PEAP";
|
||||
break;
|
||||
case EAP_TYPE_PWD:
|
||||
eap_method = "PWD";
|
||||
break;
|
||||
}
|
||||
xml_node_get_text_free(ctx->xml, str);
|
||||
if (!eap_method) {
|
||||
wpa_printf(MSG_INFO, "Unknown EAPType value");
|
||||
return;
|
||||
}
|
||||
|
||||
if (set_cred(ctx->ifname, id, "eap", eap_method) < 0)
|
||||
wpa_printf(MSG_INFO, "Failed to set cred eap");
|
||||
}
|
||||
|
||||
|
||||
static void set_pps_cred_eap_method_inner_method(struct hs20_osu_client *ctx,
|
||||
int id, xml_node_t *node)
|
||||
{
|
||||
char *str = xml_node_get_text(ctx->xml, node);
|
||||
const char *phase2 = NULL;
|
||||
|
||||
if (!str)
|
||||
return;
|
||||
wpa_printf(MSG_INFO,
|
||||
"- Credential/UsernamePassword/EAPMethod/InnerMethod = %s",
|
||||
str);
|
||||
if (os_strcmp(str, "PAP") == 0)
|
||||
phase2 = "auth=PAP";
|
||||
else if (os_strcmp(str, "CHAP") == 0)
|
||||
phase2 = "auth=CHAP";
|
||||
else if (os_strcmp(str, "MS-CHAP") == 0)
|
||||
phase2 = "auth=MSCHAP";
|
||||
else if (os_strcmp(str, "MS-CHAP-V2") == 0)
|
||||
phase2 = "auth=MSCHAPV2";
|
||||
xml_node_get_text_free(ctx->xml, str);
|
||||
if (!phase2) {
|
||||
wpa_printf(MSG_INFO, "Unknown InnerMethod value");
|
||||
return;
|
||||
}
|
||||
|
||||
if (set_cred_quoted(ctx->ifname, id, "phase2", phase2) < 0)
|
||||
wpa_printf(MSG_INFO, "Failed to set cred phase2");
|
||||
}
|
||||
|
||||
|
||||
static void set_pps_cred_eap_method(struct hs20_osu_client *ctx, int id,
|
||||
xml_node_t *node)
|
||||
{
|
||||
wpa_printf(MSG_INFO, "- Credential/UsernamePassword/EAPMethod - TODO");
|
||||
xml_node_t *child;
|
||||
const char *name;
|
||||
|
||||
wpa_printf(MSG_INFO, "- Credential/UsernamePassword/EAPMethod");
|
||||
|
||||
xml_node_for_each_child(ctx->xml, child, node) {
|
||||
xml_node_for_each_check(ctx->xml, child);
|
||||
name = xml_node_get_localname(ctx->xml, child);
|
||||
if (os_strcasecmp(name, "EAPType") == 0)
|
||||
set_pps_cred_eap_method_eap_type(ctx, id, child);
|
||||
else if (os_strcasecmp(name, "InnerMethod") == 0)
|
||||
set_pps_cred_eap_method_inner_method(ctx, id, child);
|
||||
else
|
||||
wpa_printf(MSG_INFO, "Unknown Credential/UsernamePassword/EAPMethod node '%s'",
|
||||
name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1884,7 +1989,9 @@ struct osu_data {
|
||||
char url[256];
|
||||
unsigned int methods;
|
||||
char osu_ssid[33];
|
||||
char osu_ssid2[33];
|
||||
char osu_nai[256];
|
||||
char osu_nai2[256];
|
||||
struct osu_lang_text friendly_name[MAX_OSU_VALS];
|
||||
size_t friendly_name_count;
|
||||
struct osu_lang_text serv_desc[MAX_OSU_VALS];
|
||||
@ -1943,12 +2050,24 @@ static struct osu_data * parse_osu_providers(const char *fname, size_t *count)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(buf, "osu_ssid2=", 10) == 0) {
|
||||
snprintf(last->osu_ssid2, sizeof(last->osu_ssid2),
|
||||
"%s", buf + 10);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (os_strncmp(buf, "osu_nai=", 8) == 0) {
|
||||
os_snprintf(last->osu_nai, sizeof(last->osu_nai),
|
||||
"%s", buf + 8);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (os_strncmp(buf, "osu_nai2=", 9) == 0) {
|
||||
os_snprintf(last->osu_nai2, sizeof(last->osu_nai2),
|
||||
"%s", buf + 9);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(buf, "friendly_name=", 14) == 0) {
|
||||
struct osu_lang_text *txt;
|
||||
if (last->friendly_name_count == MAX_OSU_VALS)
|
||||
@ -2024,9 +2143,9 @@ static struct osu_data * parse_osu_providers(const char *fname, size_t *count)
|
||||
|
||||
|
||||
static int osu_connect(struct hs20_osu_client *ctx, const char *bssid,
|
||||
const char *ssid, const char *url,
|
||||
const char *ssid, const char *ssid2, const char *url,
|
||||
unsigned int methods, int no_prod_assoc,
|
||||
const char *osu_nai)
|
||||
const char *osu_nai, const char *osu_nai2)
|
||||
{
|
||||
int id;
|
||||
const char *ifname = ctx->ifname;
|
||||
@ -2034,26 +2153,54 @@ static int osu_connect(struct hs20_osu_client *ctx, const char *bssid,
|
||||
struct wpa_ctrl *mon;
|
||||
int res;
|
||||
|
||||
if (ssid2 && ssid2[0] == '\0')
|
||||
ssid2 = NULL;
|
||||
|
||||
if (ctx->osu_ssid) {
|
||||
if (os_strcmp(ssid, ctx->osu_ssid) == 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Enforced OSU SSID matches ANQP info");
|
||||
ssid2 = NULL;
|
||||
} else if (ssid2 && os_strcmp(ssid2, ctx->osu_ssid) == 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Enforced OSU SSID matches RSN[OSEN] info");
|
||||
ssid = ssid2;
|
||||
} else {
|
||||
wpa_printf(MSG_INFO, "Enforced OSU SSID did not match");
|
||||
write_summary(ctx, "Enforced OSU SSID did not match");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
id = add_network(ifname);
|
||||
if (id < 0)
|
||||
return -1;
|
||||
if (set_network_quoted(ifname, id, "ssid", ssid) < 0)
|
||||
return -1;
|
||||
if (ssid2)
|
||||
osu_nai = osu_nai2;
|
||||
if (osu_nai && os_strlen(osu_nai) > 0) {
|
||||
char dir[255], fname[300];
|
||||
if (getcwd(dir, sizeof(dir)) == NULL)
|
||||
return -1;
|
||||
os_snprintf(fname, sizeof(fname), "%s/osu-ca.pem", dir);
|
||||
|
||||
if (ssid2 && set_network_quoted(ifname, id, "ssid", ssid2) < 0)
|
||||
return -1;
|
||||
|
||||
if (set_network(ifname, id, "proto", "OSEN") < 0 ||
|
||||
set_network(ifname, id, "key_mgmt", "OSEN") < 0 ||
|
||||
set_network(ifname, id, "pairwise", "CCMP") < 0 ||
|
||||
set_network(ifname, id, "group", "GTK_NOT_USED") < 0 ||
|
||||
set_network(ifname, id, "group", "GTK_NOT_USED CCMP") < 0 ||
|
||||
set_network(ifname, id, "eap", "WFA-UNAUTH-TLS") < 0 ||
|
||||
set_network(ifname, id, "ocsp", "2") < 0 ||
|
||||
set_network_quoted(ifname, id, "identity", osu_nai) < 0 ||
|
||||
set_network_quoted(ifname, id, "ca_cert", fname) < 0)
|
||||
return -1;
|
||||
} else if (ssid2) {
|
||||
wpa_printf(MSG_INFO, "No OSU_NAI set for RSN[OSEN]");
|
||||
write_summary(ctx, "No OSU_NAI set for RSN[OSEN]");
|
||||
return -1;
|
||||
} else {
|
||||
if (set_network(ifname, id, "key_mgmt", "NONE") < 0)
|
||||
return -1;
|
||||
@ -2134,7 +2281,7 @@ static int cmd_osu_select(struct hs20_osu_client *ctx, const char *dir,
|
||||
char fname[255];
|
||||
FILE *f;
|
||||
struct osu_data *osu = NULL, *last = NULL;
|
||||
size_t osu_count, i, j;
|
||||
size_t osu_count = 0, i, j;
|
||||
int ret;
|
||||
|
||||
write_summary(ctx, "OSU provider selection");
|
||||
@ -2229,8 +2376,12 @@ static int cmd_osu_select(struct hs20_osu_client *ctx, const char *dir,
|
||||
fprintf(f, "</table></a><br><small>BSSID: %s<br>\n"
|
||||
"SSID: %s<br>\n",
|
||||
last->bssid, last->osu_ssid);
|
||||
if (last->osu_ssid2[0])
|
||||
fprintf(f, "SSID2: %s<br>\n", last->osu_ssid2);
|
||||
if (last->osu_nai[0])
|
||||
fprintf(f, "NAI: %s<br>\n", last->osu_nai);
|
||||
if (last->osu_nai2[0])
|
||||
fprintf(f, "NAI2: %s<br>\n", last->osu_nai2);
|
||||
fprintf(f, "URL: %s<br>\n"
|
||||
"methods:%s%s<br>\n"
|
||||
"</small></p>\n",
|
||||
@ -2257,6 +2408,8 @@ static int cmd_osu_select(struct hs20_osu_client *ctx, const char *dir,
|
||||
ret = 0;
|
||||
wpa_printf(MSG_INFO, "BSSID: %s", last->bssid);
|
||||
wpa_printf(MSG_INFO, "SSID: %s", last->osu_ssid);
|
||||
if (last->osu_ssid2[0])
|
||||
wpa_printf(MSG_INFO, "SSID2: %s", last->osu_ssid2);
|
||||
wpa_printf(MSG_INFO, "URL: %s", last->url);
|
||||
write_summary(ctx, "Selected OSU provider id=%d BSSID=%s SSID=%s URL=%s",
|
||||
ret, last->bssid, last->osu_ssid, last->url);
|
||||
@ -2311,10 +2464,13 @@ static int cmd_osu_select(struct hs20_osu_client *ctx, const char *dir,
|
||||
"No supported OSU provisioning method");
|
||||
ret = -1;
|
||||
}
|
||||
} else if (connect)
|
||||
} else if (connect) {
|
||||
ret = osu_connect(ctx, last->bssid, last->osu_ssid,
|
||||
last->osu_ssid2,
|
||||
last->url, last->methods,
|
||||
no_prod_assoc, last->osu_nai);
|
||||
no_prod_assoc, last->osu_nai,
|
||||
last->osu_nai2);
|
||||
}
|
||||
} else
|
||||
ret = -1;
|
||||
|
||||
@ -2346,15 +2502,7 @@ static int cmd_signup(struct hs20_osu_client *ctx, int no_prod_assoc,
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
/* Allow processes running with Group ID as AID_WIFI
|
||||
* to read/write files from osu-info directory
|
||||
*/
|
||||
if (chown(fname, -1, AID_WIFI)) {
|
||||
wpa_printf(MSG_INFO, "Could not chown osu-info directory: %s",
|
||||
strerror(errno));
|
||||
}
|
||||
#endif /* ANDROID */
|
||||
android_update_permission(fname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
||||
|
||||
snprintf(buf, sizeof(buf), "SET osu_dir %s", fname);
|
||||
if (wpa_command(ifname, buf) < 0) {
|
||||
@ -2920,24 +3068,17 @@ static int init_ctx(struct hs20_osu_client *ctx)
|
||||
return -1;
|
||||
|
||||
devinfo = node_from_file(ctx->xml, "devinfo.xml");
|
||||
if (!devinfo) {
|
||||
wpa_printf(MSG_ERROR, "devinfo.xml not found");
|
||||
return -1;
|
||||
}
|
||||
if (devinfo) {
|
||||
devid = get_node(ctx->xml, devinfo, "DevId");
|
||||
if (devid) {
|
||||
char *tmp = xml_node_get_text(ctx->xml, devid);
|
||||
|
||||
devid = get_node(ctx->xml, devinfo, "DevId");
|
||||
if (devid) {
|
||||
char *tmp = xml_node_get_text(ctx->xml, devid);
|
||||
if (tmp) {
|
||||
ctx->devid = os_strdup(tmp);
|
||||
xml_node_get_text_free(ctx->xml, tmp);
|
||||
if (tmp) {
|
||||
ctx->devid = os_strdup(tmp);
|
||||
xml_node_get_text_free(ctx->xml, tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
xml_node_free(ctx->xml, devinfo);
|
||||
|
||||
if (ctx->devid == NULL) {
|
||||
wpa_printf(MSG_ERROR, "Could not fetch DevId from devinfo.xml");
|
||||
return -1;
|
||||
xml_node_free(ctx->xml, devinfo);
|
||||
}
|
||||
|
||||
ctx->http = http_init_ctx(ctx, ctx->xml);
|
||||
@ -3040,7 +3181,7 @@ int main(int argc, char *argv[])
|
||||
return -1;
|
||||
|
||||
for (;;) {
|
||||
c = getopt(argc, argv, "df:hKNO:qr:s:S:tw:x:");
|
||||
c = getopt(argc, argv, "df:hKNo:O:qr:s:S:tw:x:");
|
||||
if (c < 0)
|
||||
break;
|
||||
switch (c) {
|
||||
@ -3057,6 +3198,9 @@ int main(int argc, char *argv[])
|
||||
case 'N':
|
||||
no_prod_assoc = 1;
|
||||
break;
|
||||
case 'o':
|
||||
ctx.osu_ssid = optarg;
|
||||
break;
|
||||
case 'O':
|
||||
friendly_name = optarg;
|
||||
break;
|
||||
|
@ -47,6 +47,7 @@ struct hs20_osu_client {
|
||||
int client_cert_present;
|
||||
char **server_dnsname;
|
||||
size_t server_dnsname_count;
|
||||
const char *osu_ssid; /* Enforced OSU_SSID for testing purposes */
|
||||
#define WORKAROUND_OCSP_OPTIONAL 0x00000001
|
||||
unsigned long int workarounds;
|
||||
};
|
||||
|
@ -260,7 +260,7 @@ static void acs_clean_chan_surveys(struct hostapd_channel_data *chan)
|
||||
}
|
||||
|
||||
|
||||
static void acs_cleanup(struct hostapd_iface *iface)
|
||||
void acs_cleanup(struct hostapd_iface *iface)
|
||||
{
|
||||
int i;
|
||||
struct hostapd_channel_data *chan;
|
||||
@ -314,7 +314,7 @@ acs_survey_interference_factor(struct freq_survey *survey, s8 min_nf)
|
||||
|
||||
/* TODO: figure out the best multiplier for noise floor base */
|
||||
factor = pow(10, survey->nf / 5.0L) +
|
||||
(busy / total) *
|
||||
(total ? (busy / total) : 0) *
|
||||
pow(2, pow(10, (long double) survey->nf / 10.0L) -
|
||||
pow(10, (long double) min_nf / 10.0L));
|
||||
|
||||
@ -331,10 +331,8 @@ acs_survey_chan_interference_factor(struct hostapd_iface *iface,
|
||||
long double int_factor = 0;
|
||||
unsigned count = 0;
|
||||
|
||||
if (dl_list_empty(&chan->survey_list))
|
||||
return;
|
||||
|
||||
if (chan->flag & HOSTAPD_CHAN_DISABLED)
|
||||
if (dl_list_empty(&chan->survey_list) ||
|
||||
(chan->flag & HOSTAPD_CHAN_DISABLED))
|
||||
return;
|
||||
|
||||
chan->interference_factor = 0;
|
||||
@ -359,9 +357,8 @@ acs_survey_chan_interference_factor(struct hostapd_iface *iface,
|
||||
(unsigned long) survey->channel_time_rx);
|
||||
}
|
||||
|
||||
if (!count)
|
||||
return;
|
||||
chan->interference_factor /= count;
|
||||
if (count)
|
||||
chan->interference_factor /= count;
|
||||
}
|
||||
|
||||
|
||||
@ -450,13 +447,9 @@ static int acs_surveys_are_sufficient(struct hostapd_iface *iface)
|
||||
|
||||
for (i = 0; i < iface->current_mode->num_channels; i++) {
|
||||
chan = &iface->current_mode->channels[i];
|
||||
if (chan->flag & HOSTAPD_CHAN_DISABLED)
|
||||
continue;
|
||||
|
||||
if (!acs_survey_list_is_sufficient(chan))
|
||||
continue;
|
||||
|
||||
valid++;
|
||||
if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
|
||||
acs_survey_list_is_sufficient(chan))
|
||||
valid++;
|
||||
}
|
||||
|
||||
/* We need at least survey data for one channel */
|
||||
@ -466,13 +459,9 @@ static int acs_surveys_are_sufficient(struct hostapd_iface *iface)
|
||||
|
||||
static int acs_usable_chan(struct hostapd_channel_data *chan)
|
||||
{
|
||||
if (dl_list_empty(&chan->survey_list))
|
||||
return 0;
|
||||
if (chan->flag & HOSTAPD_CHAN_DISABLED)
|
||||
return 0;
|
||||
if (!acs_survey_list_is_sufficient(chan))
|
||||
return 0;
|
||||
return 1;
|
||||
return !dl_list_empty(&chan->survey_list) &&
|
||||
!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
|
||||
acs_survey_list_is_sufficient(chan);
|
||||
}
|
||||
|
||||
|
||||
@ -788,10 +777,7 @@ static int acs_study_survey_based(struct hostapd_iface *iface)
|
||||
|
||||
static int acs_study_options(struct hostapd_iface *iface)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = acs_study_survey_based(iface);
|
||||
if (err == 0)
|
||||
if (acs_study_survey_based(iface) == 0)
|
||||
return 0;
|
||||
|
||||
/* TODO: If no surveys are available/sufficient this is a good
|
||||
@ -920,14 +906,11 @@ static int acs_request_scan(struct hostapd_iface *iface)
|
||||
|
||||
enum hostapd_chan_status acs_init(struct hostapd_iface *iface)
|
||||
{
|
||||
int err;
|
||||
|
||||
wpa_printf(MSG_INFO, "ACS: Automatic channel selection started, this may take a bit");
|
||||
|
||||
if (iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) {
|
||||
wpa_printf(MSG_INFO, "ACS: Offloading to driver");
|
||||
err = hostapd_drv_do_acs(iface->bss[0]);
|
||||
if (err)
|
||||
if (hostapd_drv_do_acs(iface->bss[0]))
|
||||
return HOSTAPD_CHAN_INVALID;
|
||||
return HOSTAPD_CHAN_ACS;
|
||||
}
|
||||
@ -937,8 +920,7 @@ enum hostapd_chan_status acs_init(struct hostapd_iface *iface)
|
||||
|
||||
acs_cleanup(iface);
|
||||
|
||||
err = acs_request_scan(iface);
|
||||
if (err < 0)
|
||||
if (acs_request_scan(iface) < 0)
|
||||
return HOSTAPD_CHAN_INVALID;
|
||||
|
||||
hostapd_set_state(iface, HAPD_IFACE_ACS);
|
||||
|
@ -13,6 +13,7 @@
|
||||
#ifdef CONFIG_ACS
|
||||
|
||||
enum hostapd_chan_status acs_init(struct hostapd_iface *iface);
|
||||
void acs_cleanup(struct hostapd_iface *iface);
|
||||
|
||||
#else /* CONFIG_ACS */
|
||||
|
||||
@ -22,6 +23,10 @@ static inline enum hostapd_chan_status acs_init(struct hostapd_iface *iface)
|
||||
return HOSTAPD_CHAN_INVALID;
|
||||
}
|
||||
|
||||
static inline void acs_cleanup(struct hostapd_iface *iface)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_ACS */
|
||||
|
||||
#endif /* ACS_H */
|
||||
|
@ -10,9 +10,11 @@
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "crypto/sha1.h"
|
||||
#include "crypto/tls.h"
|
||||
#include "radius/radius_client.h"
|
||||
#include "common/ieee802_11_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"
|
||||
@ -36,6 +38,10 @@ static void hostapd_config_free_vlan(struct hostapd_bss_config *bss)
|
||||
}
|
||||
|
||||
|
||||
#ifndef DEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES
|
||||
#define DEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES 0
|
||||
#endif /* DEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES */
|
||||
|
||||
void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
|
||||
{
|
||||
dl_list_init(&bss->anqp_elem);
|
||||
@ -55,6 +61,10 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
|
||||
|
||||
bss->wpa_group_rekey = 600;
|
||||
bss->wpa_gmk_rekey = 86400;
|
||||
bss->wpa_group_update_count = 4;
|
||||
bss->wpa_pairwise_update_count = 4;
|
||||
bss->wpa_disable_eapol_key_retries =
|
||||
DEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES;
|
||||
bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
|
||||
bss->wpa_pairwise = WPA_CIPHER_TKIP;
|
||||
bss->wpa_group = WPA_CIPHER_TKIP;
|
||||
@ -88,13 +98,39 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
|
||||
/* Set to -1 as defaults depends on HT in setup */
|
||||
bss->wmm_enabled = -1;
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
bss->ft_over_ds = 1;
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
bss->rkh_pos_timeout = 86400;
|
||||
bss->rkh_neg_timeout = 60;
|
||||
bss->rkh_pull_timeout = 1000;
|
||||
bss->rkh_pull_retries = 4;
|
||||
bss->r0_key_lifetime = 1209600;
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
bss->radius_das_time_window = 300;
|
||||
|
||||
bss->sae_anti_clogging_threshold = 5;
|
||||
bss->sae_sync = 5;
|
||||
|
||||
bss->gas_frag_limit = 1400;
|
||||
|
||||
#ifdef CONFIG_FILS
|
||||
dl_list_init(&bss->fils_realms);
|
||||
bss->fils_hlp_wait_time = 30;
|
||||
bss->dhcp_server_port = DHCP_SERVER_PORT;
|
||||
bss->dhcp_relay_port = DHCP_SERVER_PORT;
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
bss->broadcast_deauth = 1;
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
bss->mbo_cell_data_conn_pref = -1;
|
||||
#endif /* CONFIG_MBO */
|
||||
|
||||
/* Disable TLS v1.3 by default for now to avoid interoperability issue.
|
||||
* This can be enabled by default once the implementation has been fully
|
||||
* completed and tested with other implementations. */
|
||||
bss->tls_flags = TLS_CONN_DISABLE_TLSv1_3;
|
||||
}
|
||||
|
||||
|
||||
@ -192,6 +228,11 @@ struct hostapd_config * hostapd_config_defaults(void)
|
||||
conf->acs_num_scans = 5;
|
||||
#endif /* CONFIG_ACS */
|
||||
|
||||
/* 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. */
|
||||
conf->country[2] = ' ';
|
||||
|
||||
return conf;
|
||||
}
|
||||
|
||||
@ -329,13 +370,7 @@ int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf)
|
||||
ssid->wpa_psk->group = 1;
|
||||
}
|
||||
|
||||
if (ssid->wpa_psk_file) {
|
||||
if (hostapd_config_read_wpa_psk(ssid->wpa_psk_file,
|
||||
&conf->ssid))
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return hostapd_config_read_wpa_psk(ssid->wpa_psk_file, &conf->ssid);
|
||||
}
|
||||
|
||||
|
||||
@ -380,10 +415,23 @@ void hostapd_config_free_eap_user(struct hostapd_eap_user *user)
|
||||
hostapd_config_free_radius_attr(user->accept_attr);
|
||||
os_free(user->identity);
|
||||
bin_clear_free(user->password, user->password_len);
|
||||
bin_clear_free(user->salt, user->salt_len);
|
||||
os_free(user);
|
||||
}
|
||||
|
||||
|
||||
void hostapd_config_free_eap_users(struct hostapd_eap_user *user)
|
||||
{
|
||||
struct hostapd_eap_user *prev_user;
|
||||
|
||||
while (user) {
|
||||
prev_user = user;
|
||||
user = user->next;
|
||||
hostapd_config_free_eap_user(prev_user);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_config_free_wep(struct hostapd_wep_keys *keys)
|
||||
{
|
||||
int i;
|
||||
@ -420,10 +468,38 @@ static void hostapd_config_free_anqp_elem(struct hostapd_bss_config *conf)
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_config_free_fils_realms(struct hostapd_bss_config *conf)
|
||||
{
|
||||
#ifdef CONFIG_FILS
|
||||
struct fils_realm *realm;
|
||||
|
||||
while ((realm = dl_list_first(&conf->fils_realms, struct fils_realm,
|
||||
list))) {
|
||||
dl_list_del(&realm->list);
|
||||
os_free(realm);
|
||||
}
|
||||
#endif /* CONFIG_FILS */
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_config_free_sae_passwords(struct hostapd_bss_config *conf)
|
||||
{
|
||||
struct sae_password_entry *pw, *tmp;
|
||||
|
||||
pw = conf->sae_passwords;
|
||||
conf->sae_passwords = NULL;
|
||||
while (pw) {
|
||||
tmp = pw;
|
||||
pw = pw->next;
|
||||
str_clear_free(tmp->password);
|
||||
os_free(tmp->identifier);
|
||||
os_free(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
{
|
||||
struct hostapd_eap_user *user, *prev_user;
|
||||
|
||||
if (conf == NULL)
|
||||
return;
|
||||
|
||||
@ -436,12 +512,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
os_free(conf->ssid.vlan_tagged_interface);
|
||||
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||
|
||||
user = conf->eap_user;
|
||||
while (user) {
|
||||
prev_user = user;
|
||||
user = user->next;
|
||||
hostapd_config_free_eap_user(prev_user);
|
||||
}
|
||||
hostapd_config_free_eap_users(conf->eap_user);
|
||||
os_free(conf->eap_user_sqlite);
|
||||
|
||||
os_free(conf->eap_req_id_text);
|
||||
@ -477,7 +548,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
hostapd_config_free_vlan(conf);
|
||||
os_free(conf->time_zone);
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
{
|
||||
struct ft_remote_r0kh *r0kh, *r0kh_prev;
|
||||
struct ft_remote_r1kh *r1kh, *r1kh_prev;
|
||||
@ -498,7 +569,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
os_free(r1kh_prev);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
#ifdef CONFIG_WPS
|
||||
os_free(conf->wps_pin_requests);
|
||||
@ -530,6 +601,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
|
||||
os_free(conf->roaming_consortium);
|
||||
os_free(conf->venue_name);
|
||||
os_free(conf->venue_url);
|
||||
os_free(conf->nai_realm_data);
|
||||
os_free(conf->network_auth_type);
|
||||
os_free(conf->anqp_3gpp_cell_net);
|
||||
@ -559,17 +631,30 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
os_free(p->icons[j]);
|
||||
os_free(p->icons);
|
||||
os_free(p->osu_nai);
|
||||
os_free(p->osu_nai2);
|
||||
os_free(p->service_desc);
|
||||
}
|
||||
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);
|
||||
}
|
||||
os_free(conf->subscr_remediation_url);
|
||||
os_free(conf->t_c_filename);
|
||||
os_free(conf->t_c_server_url);
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
wpabuf_free(conf->vendor_elements);
|
||||
wpabuf_free(conf->assocresp_elements);
|
||||
|
||||
os_free(conf->sae_groups);
|
||||
#ifdef CONFIG_OWE
|
||||
os_free(conf->owe_groups);
|
||||
#endif /* CONFIG_OWE */
|
||||
|
||||
os_free(conf->wowlan_triggers);
|
||||
|
||||
@ -577,11 +662,22 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
wpabuf_free(conf->own_ie_override);
|
||||
wpabuf_free(conf->sae_commit_override);
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
os_free(conf->no_probe_resp_if_seen_on);
|
||||
os_free(conf->no_auth_if_seen_on);
|
||||
|
||||
hostapd_config_free_fils_realms(conf);
|
||||
|
||||
#ifdef CONFIG_DPP
|
||||
os_free(conf->dpp_connector);
|
||||
wpabuf_free(conf->dpp_netaccesskey);
|
||||
wpabuf_free(conf->dpp_csign);
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
hostapd_config_free_sae_passwords(conf);
|
||||
|
||||
os_free(conf);
|
||||
}
|
||||
|
||||
@ -802,7 +898,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
if (full_config && wpa_key_mgmt_ft(bss->wpa_key_mgmt) &&
|
||||
(bss->nas_identifier == NULL ||
|
||||
os_strlen(bss->nas_identifier) < 1 ||
|
||||
@ -812,7 +908,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
|
||||
"string");
|
||||
return -1;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
if (full_config && conf->ieee80211n &&
|
||||
@ -848,6 +944,16 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
|
||||
wpa_printf(MSG_ERROR,
|
||||
"VHT (IEEE 802.11ac) with WEP is not allowed, disabling VHT capabilities");
|
||||
}
|
||||
|
||||
if (full_config && conf->ieee80211ac && bss->wpa &&
|
||||
!(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
|
||||
!(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
|
||||
WPA_CIPHER_CCMP_256 | WPA_CIPHER_GCMP_256)))
|
||||
{
|
||||
bss->disable_11ac = 1;
|
||||
wpa_printf(MSG_ERROR,
|
||||
"VHT (IEEE 802.11ac) with WPA/WPA2 requires CCMP/GCMP to be enabled, disabling VHT capabilities");
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
|
||||
#ifdef CONFIG_WPS
|
||||
@ -866,7 +972,9 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
|
||||
|
||||
if (full_config && bss->wps_state && bss->wpa &&
|
||||
(!(bss->wpa & 2) ||
|
||||
!(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)))) {
|
||||
!(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
|
||||
WPA_CIPHER_CCMP_256 |
|
||||
WPA_CIPHER_GCMP_256)))) {
|
||||
wpa_printf(MSG_INFO, "WPS: WPA/TKIP configuration without "
|
||||
"WPA2/CCMP/GCMP forced WPS to be disabled");
|
||||
bss->wps_state = 0;
|
||||
@ -976,8 +1084,15 @@ void hostapd_set_security_params(struct hostapd_bss_config *bss,
|
||||
|
||||
if ((bss->wpa & 2) && bss->rsn_pairwise == 0)
|
||||
bss->rsn_pairwise = bss->wpa_pairwise;
|
||||
bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa, bss->wpa_pairwise,
|
||||
bss->rsn_pairwise);
|
||||
if (bss->group_cipher)
|
||||
bss->wpa_group = bss->group_cipher;
|
||||
else
|
||||
bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa,
|
||||
bss->wpa_pairwise,
|
||||
bss->rsn_pairwise);
|
||||
if (!bss->wpa_group_rekey_set)
|
||||
bss->wpa_group_rekey = bss->wpa_group == WPA_CIPHER_TKIP ?
|
||||
600 : 86400;
|
||||
|
||||
if (full_config) {
|
||||
bss->radius->auth_server = bss->radius->auth_servers;
|
||||
|
@ -160,6 +160,8 @@ struct hostapd_eap_user {
|
||||
} methods[EAP_MAX_METHODS];
|
||||
u8 *password;
|
||||
size_t password_len;
|
||||
u8 *salt;
|
||||
size_t salt_len; /* non-zero when password is salted */
|
||||
int phase2;
|
||||
int force_version;
|
||||
unsigned int wildcard_prefix:1;
|
||||
@ -169,6 +171,7 @@ struct hostapd_eap_user {
|
||||
unsigned int macacl:1;
|
||||
int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */
|
||||
struct hostapd_radius_attr *accept_attr;
|
||||
u32 t_c_timestamp;
|
||||
};
|
||||
|
||||
struct hostapd_radius_attr {
|
||||
@ -201,6 +204,12 @@ struct hostapd_lang_string {
|
||||
u8 name[252];
|
||||
};
|
||||
|
||||
struct hostapd_venue_url {
|
||||
u8 venue_number;
|
||||
u8 url_len;
|
||||
u8 url[254];
|
||||
};
|
||||
|
||||
#define MAX_NAI_REALMS 10
|
||||
#define MAX_NAI_REALMLEN 255
|
||||
#define MAX_NAI_EAP_METHODS 5
|
||||
@ -224,6 +233,18 @@ struct anqp_element {
|
||||
struct wpabuf *payload;
|
||||
};
|
||||
|
||||
struct fils_realm {
|
||||
struct dl_list list;
|
||||
u8 hash[2];
|
||||
char realm[];
|
||||
};
|
||||
|
||||
struct sae_password_entry {
|
||||
struct sae_password_entry *next;
|
||||
char *password;
|
||||
char *identifier;
|
||||
u8 peer_addr[ETH_ALEN];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct hostapd_bss_config - Per-BSS configuration
|
||||
@ -242,7 +263,8 @@ struct hostapd_bss_config {
|
||||
int max_num_sta; /* maximum number of STAs in station table */
|
||||
|
||||
int dtim_period;
|
||||
int bss_load_update_period;
|
||||
unsigned int bss_load_update_period;
|
||||
unsigned int chan_util_avg_period;
|
||||
|
||||
int ieee802_1x; /* use IEEE 802.1X */
|
||||
int eapol_version;
|
||||
@ -287,7 +309,7 @@ struct hostapd_bss_config {
|
||||
char iapp_iface[IFNAMSIZ + 1]; /* interface used with IAPP broadcast
|
||||
* frames */
|
||||
|
||||
enum {
|
||||
enum macaddr_acl {
|
||||
ACCEPT_UNLESS_DENIED = 0,
|
||||
DENY_UNLESS_ACCEPTED = 1,
|
||||
USE_EXTERNAL_RADIUS_AUTH = 2
|
||||
@ -319,27 +341,37 @@ struct hostapd_bss_config {
|
||||
PSK_RADIUS_REQUIRED = 2
|
||||
} wpa_psk_radius;
|
||||
int wpa_pairwise;
|
||||
int group_cipher; /* wpa_group value override from configuation */
|
||||
int wpa_group;
|
||||
int wpa_group_rekey;
|
||||
int wpa_group_rekey_set;
|
||||
int wpa_strict_rekey;
|
||||
int wpa_gmk_rekey;
|
||||
int wpa_ptk_rekey;
|
||||
u32 wpa_group_update_count;
|
||||
u32 wpa_pairwise_update_count;
|
||||
int wpa_disable_eapol_key_retries;
|
||||
int rsn_pairwise;
|
||||
int rsn_preauth;
|
||||
char *rsn_preauth_interfaces;
|
||||
int peerkey;
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
/* IEEE 802.11r - Fast BSS Transition */
|
||||
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
|
||||
u8 r1_key_holder[FT_R1KH_ID_LEN];
|
||||
u32 r0_key_lifetime;
|
||||
u32 r0_key_lifetime; /* PMK-R0 lifetime seconds */
|
||||
int rkh_pos_timeout;
|
||||
int rkh_neg_timeout;
|
||||
int rkh_pull_timeout; /* ms */
|
||||
int rkh_pull_retries;
|
||||
u32 reassociation_deadline;
|
||||
struct ft_remote_r0kh *r0kh_list;
|
||||
struct ft_remote_r1kh *r1kh_list;
|
||||
int pmk_r1_push;
|
||||
int ft_over_ds;
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
int ft_psk_generate_local;
|
||||
int r1_max_key_lifetime;
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
char *ctrl_interface; /* directory for UNIX domain sockets */
|
||||
#ifndef CONFIG_NATIVE_WINDOWS
|
||||
@ -353,6 +385,7 @@ struct hostapd_bss_config {
|
||||
char *private_key_passwd;
|
||||
int check_crl;
|
||||
unsigned int tls_session_lifetime;
|
||||
unsigned int tls_flags;
|
||||
char *ocsp_stapling_response;
|
||||
char *ocsp_stapling_response_multi;
|
||||
char *dh_file;
|
||||
@ -464,6 +497,7 @@ struct hostapd_bss_config {
|
||||
int time_advertisement;
|
||||
char *time_zone;
|
||||
int wnm_sleep_mode;
|
||||
int wnm_sleep_mode_no_keys;
|
||||
int bss_transition;
|
||||
|
||||
/* IEEE 802.11u - Interworking */
|
||||
@ -486,6 +520,10 @@ struct hostapd_bss_config {
|
||||
unsigned int venue_name_count;
|
||||
struct hostapd_lang_string *venue_name;
|
||||
|
||||
/* Venue URL duples */
|
||||
unsigned int venue_url_count;
|
||||
struct hostapd_venue_url *venue_url;
|
||||
|
||||
/* IEEE 802.11u - Network Authentication Type */
|
||||
u8 *network_auth_type;
|
||||
size_t network_auth_type_len;
|
||||
@ -508,7 +546,7 @@ struct hostapd_bss_config {
|
||||
struct dl_list anqp_elem; /* list of struct anqp_element */
|
||||
|
||||
u16 gas_comeback_delay;
|
||||
int gas_frag_limit;
|
||||
size_t gas_frag_limit;
|
||||
int gas_address3;
|
||||
|
||||
u8 qos_map_set[16 + 2 * 21];
|
||||
@ -547,13 +585,20 @@ struct hostapd_bss_config {
|
||||
char **icons;
|
||||
size_t icons_count;
|
||||
char *osu_nai;
|
||||
char *osu_nai2;
|
||||
unsigned int service_desc_count;
|
||||
struct hostapd_lang_string *service_desc;
|
||||
} *hs20_osu_providers, *last_osu;
|
||||
size_t hs20_osu_providers_count;
|
||||
size_t hs20_osu_providers_nai_count;
|
||||
char **hs20_operator_icon;
|
||||
size_t hs20_operator_icon_count;
|
||||
unsigned int hs20_deauth_req_timeout;
|
||||
char *subscr_remediation_url;
|
||||
u8 subscr_remediation_method;
|
||||
char *t_c_filename;
|
||||
u32 t_c_timestamp;
|
||||
char *t_c_server_url;
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
u8 wps_rf_bands; /* RF bands for WPS (WPS_RF_*) */
|
||||
@ -566,7 +611,10 @@ struct hostapd_bss_config {
|
||||
struct wpabuf *assocresp_elements;
|
||||
|
||||
unsigned int sae_anti_clogging_threshold;
|
||||
unsigned int sae_sync;
|
||||
int sae_require_mfp;
|
||||
int *sae_groups;
|
||||
struct sae_password_entry *sae_passwords;
|
||||
|
||||
char *wowlan_triggers; /* Wake-on-WLAN triggers */
|
||||
|
||||
@ -574,6 +622,8 @@ struct hostapd_bss_config {
|
||||
u8 bss_load_test[5];
|
||||
u8 bss_load_test_set;
|
||||
struct wpabuf *own_ie_override;
|
||||
int sae_reflection_attack;
|
||||
struct wpabuf *sae_commit_override;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
#define MESH_ENABLED BIT(0)
|
||||
@ -591,12 +641,71 @@ struct hostapd_bss_config {
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
int mbo_enabled;
|
||||
/**
|
||||
* oce - Enable OCE in AP and/or STA-CFON mode
|
||||
* - BIT(0) is Reserved
|
||||
* - Set BIT(1) to enable OCE in STA-CFON mode
|
||||
* - Set BIT(2) to enable OCE in AP mode
|
||||
*/
|
||||
unsigned int oce;
|
||||
int mbo_cell_data_conn_pref;
|
||||
#endif /* CONFIG_MBO */
|
||||
|
||||
int ftm_responder;
|
||||
int ftm_initiator;
|
||||
|
||||
#ifdef CONFIG_FILS
|
||||
u8 fils_cache_id[FILS_CACHE_ID_LEN];
|
||||
int fils_cache_id_set;
|
||||
struct dl_list fils_realms; /* list of struct fils_realm */
|
||||
int fils_dh_group;
|
||||
struct hostapd_ip_addr dhcp_server;
|
||||
int dhcp_rapid_commit_proxy;
|
||||
unsigned int fils_hlp_wait_time;
|
||||
u16 dhcp_server_port;
|
||||
u16 dhcp_relay_port;
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
int multicast_to_unicast;
|
||||
|
||||
int broadcast_deauth;
|
||||
|
||||
#ifdef CONFIG_DPP
|
||||
char *dpp_connector;
|
||||
struct wpabuf *dpp_netaccesskey;
|
||||
unsigned int dpp_netaccesskey_expiry;
|
||||
struct wpabuf *dpp_csign;
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
#ifdef CONFIG_OWE
|
||||
macaddr owe_transition_bssid;
|
||||
u8 owe_transition_ssid[SSID_MAX_LEN];
|
||||
size_t owe_transition_ssid_len;
|
||||
char owe_transition_ifname[IFNAMSIZ + 1];
|
||||
int *owe_groups;
|
||||
#endif /* CONFIG_OWE */
|
||||
|
||||
int coloc_intf_reporting;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct he_phy_capabilities_info - HE PHY capabilities
|
||||
*/
|
||||
struct he_phy_capabilities_info {
|
||||
Boolean he_su_beamformer;
|
||||
Boolean he_su_beamformee;
|
||||
Boolean he_mu_beamformer;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct he_operation - HE operation
|
||||
*/
|
||||
struct he_operation {
|
||||
u8 he_bss_color;
|
||||
u8 he_default_pe_duration;
|
||||
u8 he_twt_required;
|
||||
u8 he_rts_threshold;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct hostapd_config - Per-radio interface configuration
|
||||
@ -612,6 +721,7 @@ struct hostapd_config {
|
||||
u8 channel;
|
||||
u8 acs;
|
||||
struct wpa_freq_range_list acs_ch_list;
|
||||
int acs_exclude_dfs;
|
||||
enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */
|
||||
enum {
|
||||
LONG_PREAMBLE = 0,
|
||||
@ -620,6 +730,8 @@ struct hostapd_config {
|
||||
|
||||
int *supported_rates;
|
||||
int *basic_rates;
|
||||
unsigned int beacon_rate;
|
||||
enum beacon_rate_type rate_type;
|
||||
|
||||
const struct wpa_driver_ops *driver;
|
||||
char *driver_params;
|
||||
@ -635,6 +747,9 @@ struct hostapd_config {
|
||||
* ' ' (ascii 32): all environments
|
||||
* 'O': Outdoor environemnt only
|
||||
* 'I': Indoor environment only
|
||||
* 'X': Used with noncountry entity ("XXX")
|
||||
* 0x00..0x31: identifying IEEE 802.11 standard
|
||||
* Annex E table (0x04 = global table)
|
||||
*/
|
||||
|
||||
int ieee80211d;
|
||||
@ -675,6 +790,7 @@ struct hostapd_config {
|
||||
u8 vht_oper_chwidth;
|
||||
u8 vht_oper_centr_freq_seg0_idx;
|
||||
u8 vht_oper_centr_freq_seg1_idx;
|
||||
u8 ht40_plus_minus_allowed;
|
||||
|
||||
/* Use driver-generated interface addresses when adding multiple BSSs */
|
||||
u8 use_driver_iface_addr;
|
||||
@ -707,6 +823,18 @@ struct hostapd_config {
|
||||
|
||||
struct wpabuf *lci;
|
||||
struct wpabuf *civic;
|
||||
int stationary_ap;
|
||||
|
||||
int ieee80211ax;
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
struct he_phy_capabilities_info he_phy_capab;
|
||||
struct he_operation he_op;
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
/* VHT enable/disable config from CHAN_SWITCH */
|
||||
#define CH_SWITCH_VHT_ENABLED BIT(0)
|
||||
#define CH_SWITCH_VHT_DISABLED BIT(1)
|
||||
unsigned int ch_switch_vht_config;
|
||||
};
|
||||
|
||||
|
||||
@ -714,6 +842,7 @@ 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_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);
|
||||
void hostapd_config_free_bss(struct hostapd_bss_config *conf);
|
||||
void hostapd_config_free(struct hostapd_config *conf);
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "ap_config.h"
|
||||
#include "p2p_hostapd.h"
|
||||
#include "hs20.h"
|
||||
#include "wpa_auth.h"
|
||||
#include "ap_drv_ops.h"
|
||||
|
||||
|
||||
@ -99,6 +100,13 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
|
||||
goto fail;
|
||||
#endif /* CONFIG_FST */
|
||||
|
||||
#ifdef CONFIG_FILS
|
||||
pos = hostapd_eid_fils_indic(hapd, buf, 0);
|
||||
if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
|
||||
add_buf_data(&proberesp, buf, pos - buf) < 0)
|
||||
goto fail;
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
if (add_buf(&beacon, hapd->wps_beacon_ie) < 0 ||
|
||||
add_buf(&proberesp, hapd->wps_probe_resp_ie) < 0)
|
||||
goto fail;
|
||||
@ -168,7 +176,8 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
if (hapd->conf->mbo_enabled) {
|
||||
if (hapd->conf->mbo_enabled ||
|
||||
OCE_STA_CFON_ENABLED(hapd) || OCE_AP_ENABLED(hapd)) {
|
||||
pos = hostapd_eid_mbo(hapd, buf, sizeof(buf));
|
||||
if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
|
||||
add_buf_data(&proberesp, buf, pos - buf) < 0 ||
|
||||
@ -177,6 +186,13 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
|
||||
}
|
||||
#endif /* CONFIG_MBO */
|
||||
|
||||
#ifdef CONFIG_OWE
|
||||
pos = hostapd_eid_owe_trans(hapd, buf, sizeof(buf));
|
||||
if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
|
||||
add_buf_data(&proberesp, buf, pos - buf) < 0)
|
||||
goto fail;
|
||||
#endif /* CONFIG_OWE */
|
||||
|
||||
add_buf(&beacon, hapd->conf->vendor_elements);
|
||||
add_buf(&proberesp, hapd->conf->vendor_elements);
|
||||
add_buf(&assocresp, hapd->conf->assocresp_elements);
|
||||
@ -340,10 +356,44 @@ int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr,
|
||||
int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr,
|
||||
u16 seq, u16 status, const u8 *ie, size_t len)
|
||||
{
|
||||
struct wpa_driver_sta_auth_params params;
|
||||
#ifdef CONFIG_FILS
|
||||
struct sta_info *sta;
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
if (hapd->driver == NULL || hapd->driver->sta_auth == NULL)
|
||||
return 0;
|
||||
return hapd->driver->sta_auth(hapd->drv_priv, hapd->own_addr, addr,
|
||||
seq, status, ie, len);
|
||||
|
||||
os_memset(¶ms, 0, sizeof(params));
|
||||
|
||||
#ifdef CONFIG_FILS
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (!sta) {
|
||||
wpa_printf(MSG_DEBUG, "Station " MACSTR
|
||||
" not found for sta_auth processing",
|
||||
MAC2STR(addr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
|
||||
sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
|
||||
sta->auth_alg == WLAN_AUTH_FILS_PK) {
|
||||
params.fils_auth = 1;
|
||||
wpa_auth_get_fils_aead_params(sta->wpa_sm, params.fils_anonce,
|
||||
params.fils_snonce,
|
||||
params.fils_kek,
|
||||
¶ms.fils_kek_len);
|
||||
}
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
params.own_addr = hapd->own_addr;
|
||||
params.addr = addr;
|
||||
params.seq = seq;
|
||||
params.status = status;
|
||||
params.ie = ie;
|
||||
params.len = len;
|
||||
|
||||
return hapd->driver->sta_auth(hapd->drv_priv, ¶ms);
|
||||
}
|
||||
|
||||
|
||||
@ -554,13 +604,13 @@ int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
|
||||
|
||||
struct hostapd_hw_modes *
|
||||
hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
|
||||
u16 *flags)
|
||||
u16 *flags, u8 *dfs_domain)
|
||||
{
|
||||
if (hapd->driver == NULL ||
|
||||
hapd->driver->get_hw_feature_data == NULL)
|
||||
return NULL;
|
||||
return hapd->driver->get_hw_feature_data(hapd->drv_priv, num_modes,
|
||||
flags);
|
||||
flags, dfs_domain);
|
||||
}
|
||||
|
||||
|
||||
@ -694,6 +744,15 @@ int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
|
||||
sta = ap_get_sta(hapd, dst);
|
||||
if (!sta || !(sta->flags & WLAN_STA_ASSOC))
|
||||
bssid = wildcard_bssid;
|
||||
} else if (is_broadcast_ether_addr(dst) &&
|
||||
len > 0 && data[0] == WLAN_ACTION_PUBLIC) {
|
||||
/*
|
||||
* The only current use case of Public Action frames with
|
||||
* broadcast destination address is DPP PKEX. That case is
|
||||
* directing all devices and not just the STAs within the BSS,
|
||||
* so have to use the wildcard BSSID value.
|
||||
*/
|
||||
bssid = wildcard_bssid;
|
||||
}
|
||||
return hapd->driver->send_action(hapd->drv_priv, freq, wait, dst,
|
||||
hapd->own_addr, bssid, data, len, 0);
|
||||
@ -774,7 +833,9 @@ static void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd,
|
||||
if ((acs_ch_list_all ||
|
||||
freq_range_list_includes(&hapd->iface->conf->acs_ch_list,
|
||||
chan->chan)) &&
|
||||
!(chan->flag & HOSTAPD_CHAN_DISABLED))
|
||||
!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
|
||||
!(hapd->iface->conf->acs_exclude_dfs &&
|
||||
(chan->flag & HOSTAPD_CHAN_RADAR)))
|
||||
int_array_add_unique(freq_list, chan->freq);
|
||||
}
|
||||
}
|
||||
@ -829,6 +890,9 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd)
|
||||
&hapd->iface->conf->acs_ch_list,
|
||||
chan->chan))
|
||||
continue;
|
||||
if (hapd->iface->conf->acs_exclude_dfs &&
|
||||
(chan->flag & HOSTAPD_CHAN_RADAR))
|
||||
continue;
|
||||
if (!(chan->flag & HOSTAPD_CHAN_DISABLED)) {
|
||||
channels[num_channels++] = chan->chan;
|
||||
int_array_add_unique(&freq_list, chan->freq);
|
||||
|
@ -72,7 +72,7 @@ int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
|
||||
int cw_min, int cw_max, int burst_time);
|
||||
struct hostapd_hw_modes *
|
||||
hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
|
||||
u16 *flags);
|
||||
u16 *flags, u8 *dfs_domain);
|
||||
int hostapd_driver_commit(struct hostapd_data *hapd);
|
||||
int hostapd_drv_none(struct hostapd_data *hapd);
|
||||
int hostapd_driver_scan(struct hostapd_data *hapd,
|
||||
@ -103,6 +103,14 @@ int hostapd_drv_send_action_addr3_ap(struct hostapd_data *hapd,
|
||||
unsigned int freq,
|
||||
unsigned int wait, const u8 *dst,
|
||||
const u8 *data, size_t len);
|
||||
static inline void
|
||||
hostapd_drv_send_action_cancel_wait(struct hostapd_data *hapd)
|
||||
{
|
||||
if (!hapd->driver || !hapd->driver->send_action_cancel_wait ||
|
||||
!hapd->drv_priv)
|
||||
return;
|
||||
hapd->driver->send_action_cancel_wait(hapd->drv_priv);
|
||||
}
|
||||
int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr,
|
||||
u16 auth_alg);
|
||||
int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr,
|
||||
@ -274,8 +282,9 @@ static inline const char * hostapd_drv_get_radio_name(struct hostapd_data *hapd)
|
||||
static inline int hostapd_drv_switch_channel(struct hostapd_data *hapd,
|
||||
struct csa_settings *settings)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->switch_channel == NULL)
|
||||
return -ENOTSUP;
|
||||
if (hapd->driver == NULL || hapd->driver->switch_channel == NULL ||
|
||||
hapd->drv_priv == NULL)
|
||||
return -1;
|
||||
|
||||
return hapd->driver->switch_channel(hapd->drv_priv, settings);
|
||||
}
|
||||
|
@ -57,7 +57,11 @@ void mlme_authenticate_indication(struct hostapd_data *hapd,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"MLME-AUTHENTICATE.indication(" MACSTR ", %s)",
|
||||
MAC2STR(sta->addr), mlme_auth_alg_str(sta->auth_alg));
|
||||
if (sta->auth_alg != WLAN_AUTH_FT && !(sta->flags & WLAN_STA_MFP))
|
||||
if (sta->auth_alg != WLAN_AUTH_FT &&
|
||||
sta->auth_alg != WLAN_AUTH_FILS_SK &&
|
||||
sta->auth_alg != WLAN_AUTH_FILS_SK_PFS &&
|
||||
sta->auth_alg != WLAN_AUTH_FILS_PK &&
|
||||
!(sta->flags & WLAN_STA_MFP))
|
||||
mlme_deletekeys_request(hapd, sta);
|
||||
ap_sta_clear_disconnect_timeouts(hapd, sta);
|
||||
}
|
||||
@ -105,7 +109,10 @@ void mlme_associate_indication(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"MLME-ASSOCIATE.indication(" MACSTR ")",
|
||||
MAC2STR(sta->addr));
|
||||
if (sta->auth_alg != WLAN_AUTH_FT)
|
||||
if (sta->auth_alg != WLAN_AUTH_FT &&
|
||||
sta->auth_alg != WLAN_AUTH_FILS_SK &&
|
||||
sta->auth_alg != WLAN_AUTH_FILS_SK_PFS &&
|
||||
sta->auth_alg != WLAN_AUTH_FILS_PK)
|
||||
mlme_deletekeys_request(hapd, sta);
|
||||
ap_sta_clear_disconnect_timeouts(hapd, sta);
|
||||
}
|
||||
@ -130,7 +137,10 @@ void mlme_reassociate_indication(struct hostapd_data *hapd,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"MLME-REASSOCIATE.indication(" MACSTR ")",
|
||||
MAC2STR(sta->addr));
|
||||
if (sta->auth_alg != WLAN_AUTH_FT)
|
||||
if (sta->auth_alg != WLAN_AUTH_FT &&
|
||||
sta->auth_alg != WLAN_AUTH_FILS_SK &&
|
||||
sta->auth_alg != WLAN_AUTH_FILS_SK_PFS &&
|
||||
sta->auth_alg != WLAN_AUTH_FILS_PK)
|
||||
mlme_deletekeys_request(hapd, sta);
|
||||
ap_sta_clear_disconnect_timeouts(hapd, sta);
|
||||
}
|
||||
|
@ -71,19 +71,26 @@ static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity,
|
||||
}
|
||||
|
||||
if (eap_user->password) {
|
||||
user->password = os_malloc(eap_user->password_len);
|
||||
user->password = os_memdup(eap_user->password,
|
||||
eap_user->password_len);
|
||||
if (user->password == NULL)
|
||||
goto out;
|
||||
os_memcpy(user->password, eap_user->password,
|
||||
eap_user->password_len);
|
||||
user->password_len = eap_user->password_len;
|
||||
user->password_hash = eap_user->password_hash;
|
||||
if (eap_user->salt && eap_user->salt_len) {
|
||||
user->salt = os_memdup(eap_user->salt,
|
||||
eap_user->salt_len);
|
||||
if (!user->salt)
|
||||
goto out;
|
||||
user->salt_len = eap_user->salt_len;
|
||||
}
|
||||
}
|
||||
user->force_version = eap_user->force_version;
|
||||
user->macacl = eap_user->macacl;
|
||||
user->ttls_auth = eap_user->ttls_auth;
|
||||
user->remediation = eap_user->remediation;
|
||||
user->accept_attr = eap_user->accept_attr;
|
||||
user->t_c_timestamp = eap_user->t_c_timestamp;
|
||||
rv = 0;
|
||||
|
||||
out:
|
||||
@ -129,10 +136,12 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
|
||||
#ifdef CONFIG_HS20
|
||||
srv.subscr_remediation_url = conf->subscr_remediation_url;
|
||||
srv.subscr_remediation_method = conf->subscr_remediation_method;
|
||||
srv.t_c_server_url = conf->t_c_server_url;
|
||||
#endif /* CONFIG_HS20 */
|
||||
srv.erp = conf->eap_server_erp;
|
||||
srv.erp_domain = conf->erp_domain;
|
||||
srv.tls_session_lifetime = conf->tls_session_lifetime;
|
||||
srv.tls_flags = conf->tls_flags;
|
||||
|
||||
hapd->radius_srv = radius_server_init(&srv);
|
||||
if (hapd->radius_srv == NULL) {
|
||||
@ -146,6 +155,40 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
|
||||
#endif /* RADIUS_SERVER */
|
||||
|
||||
|
||||
#ifdef EAP_TLS_FUNCS
|
||||
static void authsrv_tls_event(void *ctx, enum tls_event ev,
|
||||
union tls_event_data *data)
|
||||
{
|
||||
switch (ev) {
|
||||
case TLS_CERT_CHAIN_SUCCESS:
|
||||
wpa_printf(MSG_DEBUG, "authsrv: remote certificate verification success");
|
||||
break;
|
||||
case TLS_CERT_CHAIN_FAILURE:
|
||||
wpa_printf(MSG_INFO, "authsrv: certificate chain failure: reason=%d depth=%d subject='%s' err='%s'",
|
||||
data->cert_fail.reason,
|
||||
data->cert_fail.depth,
|
||||
data->cert_fail.subject,
|
||||
data->cert_fail.reason_txt);
|
||||
break;
|
||||
case TLS_PEER_CERTIFICATE:
|
||||
wpa_printf(MSG_DEBUG, "authsrv: peer certificate: depth=%d serial_num=%s subject=%s",
|
||||
data->peer_cert.depth,
|
||||
data->peer_cert.serial_num ? data->peer_cert.serial_num : "N/A",
|
||||
data->peer_cert.subject);
|
||||
break;
|
||||
case TLS_ALERT:
|
||||
if (data->alert.is_local)
|
||||
wpa_printf(MSG_DEBUG, "authsrv: local TLS alert: %s",
|
||||
data->alert.description);
|
||||
else
|
||||
wpa_printf(MSG_DEBUG, "authsrv: remote TLS alert: %s",
|
||||
data->alert.description);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* EAP_TLS_FUNCS */
|
||||
|
||||
|
||||
int authsrv_init(struct hostapd_data *hapd)
|
||||
{
|
||||
#ifdef EAP_TLS_FUNCS
|
||||
@ -157,6 +200,9 @@ int authsrv_init(struct hostapd_data *hapd)
|
||||
|
||||
os_memset(&conf, 0, sizeof(conf));
|
||||
conf.tls_session_lifetime = hapd->conf->tls_session_lifetime;
|
||||
conf.tls_flags = hapd->conf->tls_flags;
|
||||
conf.event_cb = authsrv_tls_event;
|
||||
conf.cb_ctx = hapd;
|
||||
hapd->ssl_ctx = tls_init(&conf);
|
||||
if (hapd->ssl_ctx == NULL) {
|
||||
wpa_printf(MSG_ERROR, "Failed to initialize TLS");
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/ieee802_11_common.h"
|
||||
#include "common/hw_features_common.h"
|
||||
#include "common/wpa_ctrl.h"
|
||||
#include "wps/wps_defs.h"
|
||||
#include "p2p/p2p.h"
|
||||
#include "hostapd.h"
|
||||
@ -30,6 +31,7 @@
|
||||
#include "hs20.h"
|
||||
#include "dfs.h"
|
||||
#include "taxonomy.h"
|
||||
#include "ieee802_11_auth.h"
|
||||
|
||||
|
||||
#ifdef NEED_AP_MLME
|
||||
@ -392,7 +394,15 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
|
||||
2 + sizeof(struct ieee80211_vht_operation);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (hapd->iconf->ieee80211ax) {
|
||||
buflen += 3 + sizeof(struct ieee80211_he_capabilities) +
|
||||
3 + sizeof(struct ieee80211_he_operation);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
buflen += hostapd_mbo_ie_len(hapd);
|
||||
buflen += hostapd_eid_owe_trans_len(hapd);
|
||||
|
||||
resp = os_zalloc(buflen);
|
||||
if (resp == NULL)
|
||||
@ -443,8 +453,9 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
|
||||
/* Extended supported rates */
|
||||
pos = hostapd_eid_ext_supp_rates(hapd, pos);
|
||||
|
||||
/* RSN, MDIE, WPA */
|
||||
pos = hostapd_eid_wpa(hapd, pos, epos - pos);
|
||||
/* RSN, MDIE */
|
||||
if (hapd->conf->wpa != WPA_PROTO_WPA)
|
||||
pos = hostapd_eid_wpa(hapd, pos, epos - pos);
|
||||
|
||||
pos = hostapd_eid_bss_load(hapd, pos, epos - pos);
|
||||
|
||||
@ -491,10 +502,26 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
|
||||
pos = hostapd_eid_txpower_envelope(hapd, pos);
|
||||
pos = hostapd_eid_wb_chsw_wrapper(hapd, pos);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
|
||||
pos = hostapd_eid_fils_indic(hapd, pos, 0);
|
||||
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (hapd->iconf->ieee80211ax) {
|
||||
pos = hostapd_eid_he_capab(hapd, pos);
|
||||
pos = hostapd_eid_he_operation(hapd, pos);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
#ifdef CONFIG_IEEE80211AC
|
||||
if (hapd->conf->vendor_vht)
|
||||
pos = hostapd_eid_vendor_vht(hapd, pos);
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
|
||||
/* WPA */
|
||||
if (hapd->conf->wpa == WPA_PROTO_WPA)
|
||||
pos = hostapd_eid_wpa(hapd, pos, epos - pos);
|
||||
|
||||
/* Wi-Fi Alliance WMM */
|
||||
pos = hostapd_eid_wmm(hapd, pos);
|
||||
|
||||
@ -526,6 +553,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
pos = hostapd_eid_mbo(hapd, pos, (u8 *) resp + buflen - pos);
|
||||
pos = hostapd_eid_owe_trans(hapd, pos, (u8 *) resp + buflen - pos);
|
||||
|
||||
if (hapd->conf->vendor_elements) {
|
||||
os_memcpy(pos, wpabuf_head(hapd->conf->vendor_elements),
|
||||
@ -618,7 +646,7 @@ static struct hostapd_sta_info * sta_track_get(struct hostapd_iface *iface,
|
||||
}
|
||||
|
||||
|
||||
void sta_track_add(struct hostapd_iface *iface, const u8 *addr)
|
||||
void sta_track_add(struct hostapd_iface *iface, const u8 *addr, int ssi_signal)
|
||||
{
|
||||
struct hostapd_sta_info *info;
|
||||
|
||||
@ -628,6 +656,7 @@ void sta_track_add(struct hostapd_iface *iface, const u8 *addr)
|
||||
dl_list_del(&info->list);
|
||||
dl_list_add_tail(&iface->sta_seen, &info->list);
|
||||
os_get_reltime(&info->last_seen);
|
||||
info->ssi_signal = ssi_signal;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -637,6 +666,7 @@ void sta_track_add(struct hostapd_iface *iface, const u8 *addr)
|
||||
return;
|
||||
os_memcpy(info->addr, addr, ETH_ALEN);
|
||||
os_get_reltime(&info->last_seen);
|
||||
info->ssi_signal = ssi_signal;
|
||||
|
||||
if (iface->num_sta_seen >= iface->conf->track_sta_max_num) {
|
||||
/* Expire oldest entry to make room for a new one */
|
||||
@ -707,14 +737,30 @@ void handle_probe_req(struct hostapd_data *hapd,
|
||||
int ret;
|
||||
u16 csa_offs[2];
|
||||
size_t csa_offs_len;
|
||||
u32 session_timeout, acct_interim_interval;
|
||||
struct vlan_description vlan_id;
|
||||
struct hostapd_sta_wpa_psk_short *psk = NULL;
|
||||
char *identity = NULL;
|
||||
char *radius_cui = NULL;
|
||||
|
||||
if (len < IEEE80211_HDRLEN)
|
||||
return;
|
||||
ie = ((const u8 *) mgmt) + IEEE80211_HDRLEN;
|
||||
if (hapd->iconf->track_sta_max_num)
|
||||
sta_track_add(hapd->iface, mgmt->sa);
|
||||
sta_track_add(hapd->iface, mgmt->sa, ssi_signal);
|
||||
ie_len = len - IEEE80211_HDRLEN;
|
||||
|
||||
ret = ieee802_11_allowed_address(hapd, mgmt->sa, (const u8 *) mgmt, len,
|
||||
&session_timeout,
|
||||
&acct_interim_interval, &vlan_id,
|
||||
&psk, &identity, &radius_cui, 1);
|
||||
if (ret == HOSTAPD_ACL_REJECT) {
|
||||
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
|
||||
"Ignore Probe Request frame from " MACSTR
|
||||
" due to ACL reject ", MAC2STR(mgmt->sa));
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++)
|
||||
if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
|
||||
mgmt->sa, mgmt->da, mgmt->bssid,
|
||||
@ -909,6 +955,9 @@ void handle_probe_req(struct hostapd_data *hapd,
|
||||
}
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, RX_PROBE_REQUEST "sa=" MACSTR
|
||||
" signal=%d", MAC2STR(mgmt->sa), ssi_signal);
|
||||
|
||||
resp = hostapd_gen_probe_resp(hapd, mgmt, elems.p2p != NULL,
|
||||
&resp_len);
|
||||
if (resp == NULL)
|
||||
@ -1033,7 +1082,15 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (hapd->iconf->ieee80211ax) {
|
||||
tail_len += 3 + sizeof(struct ieee80211_he_capabilities) +
|
||||
3 + sizeof(struct ieee80211_he_operation);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
tail_len += hostapd_mbo_ie_len(hapd);
|
||||
tail_len += hostapd_eid_owe_trans_len(hapd);
|
||||
|
||||
tailpos = tail = os_malloc(tail_len);
|
||||
if (head == NULL || tail == NULL) {
|
||||
@ -1100,9 +1157,11 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
/* Extended supported rates */
|
||||
tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos);
|
||||
|
||||
/* RSN, MDIE, WPA */
|
||||
tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE -
|
||||
tailpos);
|
||||
/* RSN, MDIE */
|
||||
if (hapd->conf->wpa != WPA_PROTO_WPA)
|
||||
tailpos = hostapd_eid_wpa(hapd, tailpos,
|
||||
tail + BEACON_TAIL_BUF_SIZE -
|
||||
tailpos);
|
||||
|
||||
tailpos = hostapd_eid_rm_enabled_capab(hapd, tailpos,
|
||||
tail + BEACON_TAIL_BUF_SIZE -
|
||||
@ -1155,10 +1214,28 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
tailpos = hostapd_eid_txpower_envelope(hapd, tailpos);
|
||||
tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
|
||||
tailpos = hostapd_eid_fils_indic(hapd, tailpos, 0);
|
||||
|
||||
#ifdef CONFIG_IEEE80211AX
|
||||
if (hapd->iconf->ieee80211ax) {
|
||||
tailpos = hostapd_eid_he_capab(hapd, tailpos);
|
||||
tailpos = hostapd_eid_he_operation(hapd, tailpos);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AX */
|
||||
|
||||
#ifdef CONFIG_IEEE80211AC
|
||||
if (hapd->conf->vendor_vht)
|
||||
tailpos = hostapd_eid_vendor_vht(hapd, tailpos);
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
|
||||
/* WPA */
|
||||
if (hapd->conf->wpa == WPA_PROTO_WPA)
|
||||
tailpos = hostapd_eid_wpa(hapd, tailpos,
|
||||
tail + BEACON_TAIL_BUF_SIZE -
|
||||
tailpos);
|
||||
|
||||
/* Wi-Fi Alliance WMM */
|
||||
tailpos = hostapd_eid_wmm(hapd, tailpos);
|
||||
|
||||
@ -1189,6 +1266,8 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
tailpos = hostapd_eid_mbo(hapd, tailpos, tail + tail_len - tailpos);
|
||||
tailpos = hostapd_eid_owe_trans(hapd, tailpos,
|
||||
tail + tail_len - tailpos);
|
||||
|
||||
if (hapd->conf->vendor_elements) {
|
||||
os_memcpy(tailpos, wpabuf_head(hapd->conf->vendor_elements),
|
||||
@ -1211,6 +1290,8 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
params->dtim_period = hapd->conf->dtim_period;
|
||||
params->beacon_int = hapd->iconf->beacon_int;
|
||||
params->basic_rates = hapd->iface->basic_rates;
|
||||
params->beacon_rate = hapd->iconf->beacon_rate;
|
||||
params->rate_type = hapd->iconf->rate_type;
|
||||
params->ssid = hapd->conf->ssid.ssid;
|
||||
params->ssid_len = hapd->conf->ssid.ssid_len;
|
||||
if ((hapd->conf->wpa & (WPA_PROTO_WPA | WPA_PROTO_RSN)) ==
|
||||
@ -1274,6 +1355,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
params->osen = 1;
|
||||
}
|
||||
#endif /* CONFIG_HS20 */
|
||||
params->multicast_to_unicast = hapd->conf->multicast_to_unicast;
|
||||
params->pbss = hapd->conf->pbss;
|
||||
return 0;
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ int ieee802_11_update_beacons(struct hostapd_iface *iface);
|
||||
int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
struct wpa_driver_ap_params *params);
|
||||
void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params);
|
||||
void sta_track_add(struct hostapd_iface *iface, const u8 *addr);
|
||||
void sta_track_add(struct hostapd_iface *iface, const u8 *addr, int ssi_signal);
|
||||
void sta_track_del(struct hostapd_sta_info *info);
|
||||
void sta_track_expire(struct hostapd_iface *iface, int force);
|
||||
struct hostapd_data *
|
||||
|
@ -16,11 +16,35 @@
|
||||
#include "beacon.h"
|
||||
|
||||
|
||||
static int get_bss_load_update_timeout(struct hostapd_data *hapd,
|
||||
unsigned int *sec, unsigned int *usec)
|
||||
{
|
||||
unsigned int update_period = hapd->conf->bss_load_update_period;
|
||||
unsigned int beacon_int = hapd->iconf->beacon_int;
|
||||
unsigned int update_timeout;
|
||||
|
||||
if (!update_period || !beacon_int) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"BSS Load: Invalid BSS load update configuration (period=%u beacon_int=%u)",
|
||||
update_period, beacon_int);
|
||||
return -1;
|
||||
}
|
||||
|
||||
update_timeout = update_period * beacon_int;
|
||||
|
||||
*sec = ((update_timeout / 1000) * 1024) / 1000;
|
||||
*usec = (update_timeout % 1000) * 1024;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void update_channel_utilization(void *eloop_data, void *user_data)
|
||||
{
|
||||
struct hostapd_data *hapd = eloop_data;
|
||||
unsigned int sec, usec;
|
||||
int err;
|
||||
struct hostapd_iface *iface = hapd->iface;
|
||||
|
||||
if (!(hapd->beacon_set_done && hapd->started))
|
||||
return;
|
||||
@ -33,8 +57,24 @@ static void update_channel_utilization(void *eloop_data, void *user_data)
|
||||
|
||||
ieee802_11_set_beacon(hapd);
|
||||
|
||||
sec = ((hapd->bss_load_update_timeout / 1000) * 1024) / 1000;
|
||||
usec = (hapd->bss_load_update_timeout % 1000) * 1024;
|
||||
if (get_bss_load_update_timeout(hapd, &sec, &usec) < 0)
|
||||
return;
|
||||
|
||||
if (hapd->conf->chan_util_avg_period) {
|
||||
iface->chan_util_samples_sum += iface->channel_utilization;
|
||||
iface->chan_util_num_sample_periods +=
|
||||
hapd->conf->bss_load_update_period;
|
||||
if (iface->chan_util_num_sample_periods >=
|
||||
hapd->conf->chan_util_avg_period) {
|
||||
iface->chan_util_average =
|
||||
iface->chan_util_samples_sum /
|
||||
(iface->chan_util_num_sample_periods /
|
||||
hapd->conf->bss_load_update_period);
|
||||
iface->chan_util_samples_sum = 0;
|
||||
iface->chan_util_num_sample_periods = 0;
|
||||
}
|
||||
}
|
||||
|
||||
eloop_register_timeout(sec, usec, update_channel_utilization, hapd,
|
||||
NULL);
|
||||
}
|
||||
@ -42,17 +82,11 @@ static void update_channel_utilization(void *eloop_data, void *user_data)
|
||||
|
||||
int bss_load_update_init(struct hostapd_data *hapd)
|
||||
{
|
||||
struct hostapd_bss_config *conf = hapd->conf;
|
||||
struct hostapd_config *iconf = hapd->iconf;
|
||||
unsigned int sec, usec;
|
||||
|
||||
if (!conf->bss_load_update_period || !iconf->beacon_int)
|
||||
if (get_bss_load_update_timeout(hapd, &sec, &usec) < 0)
|
||||
return -1;
|
||||
|
||||
hapd->bss_load_update_timeout = conf->bss_load_update_period *
|
||||
iconf->beacon_int;
|
||||
sec = ((hapd->bss_load_update_timeout / 1000) * 1024) / 1000;
|
||||
usec = (hapd->bss_load_update_timeout % 1000) * 1024;
|
||||
eloop_register_timeout(sec, usec, update_channel_utilization, hapd,
|
||||
NULL);
|
||||
return 0;
|
||||
|
@ -26,23 +26,141 @@
|
||||
#include "taxonomy.h"
|
||||
|
||||
|
||||
static size_t hostapd_write_ht_mcs_bitmask(char *buf, size_t buflen,
|
||||
size_t curr_len, const u8 *mcs_set)
|
||||
{
|
||||
int ret;
|
||||
size_t len = curr_len;
|
||||
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
"ht_mcs_bitmask=");
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
|
||||
/* 77 first bits (+ 3 reserved bits) */
|
||||
len += wpa_snprintf_hex(buf + len, buflen - len, mcs_set, 10);
|
||||
|
||||
ret = os_snprintf(buf + len, buflen - len, "\n");
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return curr_len;
|
||||
len += ret;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_get_sta_tx_rx(struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
char *buf, size_t buflen)
|
||||
{
|
||||
struct hostap_sta_driver_data data;
|
||||
int ret;
|
||||
int len = 0;
|
||||
|
||||
if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
|
||||
return 0;
|
||||
|
||||
ret = os_snprintf(buf, buflen, "rx_packets=%lu\ntx_packets=%lu\n"
|
||||
"rx_bytes=%llu\ntx_bytes=%llu\ninactive_msec=%lu\n",
|
||||
"rx_bytes=%llu\ntx_bytes=%llu\ninactive_msec=%lu\n"
|
||||
"signal=%d\n",
|
||||
data.rx_packets, data.tx_packets,
|
||||
data.rx_bytes, data.tx_bytes, data.inactive_msec);
|
||||
data.rx_bytes, data.tx_bytes, data.inactive_msec,
|
||||
data.signal);
|
||||
if (os_snprintf_error(buflen, ret))
|
||||
return 0;
|
||||
return ret;
|
||||
len += ret;
|
||||
|
||||
ret = os_snprintf(buf + len, buflen - len, "rx_rate_info=%lu",
|
||||
data.current_rx_rate);
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
if (data.flags & STA_DRV_DATA_RX_MCS) {
|
||||
ret = os_snprintf(buf + len, buflen - len, " mcs %u",
|
||||
data.rx_mcs);
|
||||
if (!os_snprintf_error(buflen - len, ret))
|
||||
len += ret;
|
||||
}
|
||||
if (data.flags & STA_DRV_DATA_RX_VHT_MCS) {
|
||||
ret = os_snprintf(buf + len, buflen - len, " vhtmcs %u",
|
||||
data.rx_vhtmcs);
|
||||
if (!os_snprintf_error(buflen - len, ret))
|
||||
len += ret;
|
||||
}
|
||||
if (data.flags & STA_DRV_DATA_RX_VHT_NSS) {
|
||||
ret = os_snprintf(buf + len, buflen - len, " vhtnss %u",
|
||||
data.rx_vht_nss);
|
||||
if (!os_snprintf_error(buflen - len, ret))
|
||||
len += ret;
|
||||
}
|
||||
if (data.flags & STA_DRV_DATA_RX_SHORT_GI) {
|
||||
ret = os_snprintf(buf + len, buflen - len, " shortGI");
|
||||
if (!os_snprintf_error(buflen - len, ret))
|
||||
len += ret;
|
||||
}
|
||||
ret = os_snprintf(buf + len, buflen - len, "\n");
|
||||
if (!os_snprintf_error(buflen - len, ret))
|
||||
len += ret;
|
||||
|
||||
ret = os_snprintf(buf + len, buflen - len, "tx_rate_info=%lu",
|
||||
data.current_tx_rate);
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
if (data.flags & STA_DRV_DATA_TX_MCS) {
|
||||
ret = os_snprintf(buf + len, buflen - len, " mcs %u",
|
||||
data.tx_mcs);
|
||||
if (!os_snprintf_error(buflen - len, ret))
|
||||
len += ret;
|
||||
}
|
||||
if (data.flags & STA_DRV_DATA_TX_VHT_MCS) {
|
||||
ret = os_snprintf(buf + len, buflen - len, " vhtmcs %u",
|
||||
data.tx_vhtmcs);
|
||||
if (!os_snprintf_error(buflen - len, ret))
|
||||
len += ret;
|
||||
}
|
||||
if (data.flags & STA_DRV_DATA_TX_VHT_NSS) {
|
||||
ret = os_snprintf(buf + len, buflen - len, " vhtnss %u",
|
||||
data.tx_vht_nss);
|
||||
if (!os_snprintf_error(buflen - len, ret))
|
||||
len += ret;
|
||||
}
|
||||
if (data.flags & STA_DRV_DATA_TX_SHORT_GI) {
|
||||
ret = os_snprintf(buf + len, buflen - len, " shortGI");
|
||||
if (!os_snprintf_error(buflen - len, ret))
|
||||
len += ret;
|
||||
}
|
||||
ret = os_snprintf(buf + len, buflen - len, "\n");
|
||||
if (!os_snprintf_error(buflen - len, ret))
|
||||
len += ret;
|
||||
|
||||
if ((sta->flags & WLAN_STA_VHT) && sta->vht_capabilities) {
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
"rx_vht_mcs_map=%04x\n"
|
||||
"tx_vht_mcs_map=%04x\n",
|
||||
le_to_host16(sta->vht_capabilities->
|
||||
vht_supported_mcs_set.rx_map),
|
||||
le_to_host16(sta->vht_capabilities->
|
||||
vht_supported_mcs_set.tx_map));
|
||||
if (!os_snprintf_error(buflen - len, ret))
|
||||
len += ret;
|
||||
}
|
||||
|
||||
if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) {
|
||||
len = hostapd_write_ht_mcs_bitmask(buf, buflen, len,
|
||||
sta->ht_capabilities->
|
||||
supported_mcs_set);
|
||||
}
|
||||
|
||||
if (data.flags & STA_DRV_DATA_LAST_ACK_RSSI) {
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
"last_ack_signal=%d\n", data.last_ack_rssi);
|
||||
if (!os_snprintf_error(buflen - len, ret))
|
||||
len += ret;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
@ -176,6 +294,53 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
|
||||
len += os_snprintf(buf + len, buflen - len, "\n");
|
||||
}
|
||||
|
||||
if (sta->power_capab) {
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
"min_txpower=%d\n"
|
||||
"max_txpower=%d\n",
|
||||
sta->min_tx_power, sta->max_tx_power);
|
||||
if (!os_snprintf_error(buflen - len, ret))
|
||||
len += ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211AC
|
||||
if ((sta->flags & WLAN_STA_VHT) && sta->vht_capabilities) {
|
||||
res = os_snprintf(buf + len, buflen - len,
|
||||
"vht_caps_info=0x%08x\n",
|
||||
le_to_host32(sta->vht_capabilities->
|
||||
vht_capabilities_info));
|
||||
if (!os_snprintf_error(buflen - len, res))
|
||||
len += res;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) {
|
||||
res = os_snprintf(buf + len, buflen - len,
|
||||
"ht_caps_info=0x%04x\n",
|
||||
le_to_host16(sta->ht_capabilities->
|
||||
ht_capabilities_info));
|
||||
if (!os_snprintf_error(buflen - len, res))
|
||||
len += res;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
|
||||
if (sta->ext_capability &&
|
||||
buflen - len > (unsigned) (11 + 2 * sta->ext_capability[0])) {
|
||||
len += os_snprintf(buf + len, buflen - len, "ext_capab=");
|
||||
len += wpa_snprintf_hex(buf + len, buflen - len,
|
||||
sta->ext_capability + 1,
|
||||
sta->ext_capability[0]);
|
||||
len += os_snprintf(buf + len, buflen - len, "\n");
|
||||
}
|
||||
|
||||
if (sta->flags & WLAN_STA_WDS && sta->ifname_wds) {
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
"wds_sta_ifname=%s\n", sta->ifname_wds);
|
||||
if (!os_snprintf_error(buflen - len, ret))
|
||||
len += ret;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
@ -477,7 +642,8 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
|
||||
size_t buflen)
|
||||
{
|
||||
struct hostapd_iface *iface = hapd->iface;
|
||||
int len = 0, ret;
|
||||
struct hostapd_hw_modes *mode = iface->current_mode;
|
||||
int len = 0, ret, j;
|
||||
size_t i;
|
||||
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
@ -537,13 +703,17 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
|
||||
"channel=%u\n"
|
||||
"secondary_channel=%d\n"
|
||||
"ieee80211n=%d\n"
|
||||
"ieee80211ac=%d\n",
|
||||
"ieee80211ac=%d\n"
|
||||
"beacon_int=%u\n"
|
||||
"dtim_period=%d\n",
|
||||
iface->conf->channel,
|
||||
iface->conf->ieee80211n && !hapd->conf->disable_11n ?
|
||||
iface->conf->secondary_channel : 0,
|
||||
iface->conf->ieee80211n && !hapd->conf->disable_11n,
|
||||
iface->conf->ieee80211ac &&
|
||||
!hapd->conf->disable_11ac);
|
||||
!hapd->conf->disable_11ac,
|
||||
iface->conf->beacon_int,
|
||||
hapd->conf->dtim_period);
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
@ -551,15 +721,76 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
"vht_oper_chwidth=%d\n"
|
||||
"vht_oper_centr_freq_seg0_idx=%d\n"
|
||||
"vht_oper_centr_freq_seg1_idx=%d\n",
|
||||
"vht_oper_centr_freq_seg1_idx=%d\n"
|
||||
"vht_caps_info=%08x\n",
|
||||
iface->conf->vht_oper_chwidth,
|
||||
iface->conf->vht_oper_centr_freq_seg0_idx,
|
||||
iface->conf->vht_oper_centr_freq_seg1_idx);
|
||||
iface->conf->vht_oper_centr_freq_seg1_idx,
|
||||
iface->conf->vht_capab);
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
}
|
||||
|
||||
if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac && mode) {
|
||||
u16 rxmap = WPA_GET_LE16(&mode->vht_mcs_set[0]);
|
||||
u16 txmap = WPA_GET_LE16(&mode->vht_mcs_set[4]);
|
||||
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
"rx_vht_mcs_map=%04x\n"
|
||||
"tx_vht_mcs_map=%04x\n",
|
||||
rxmap, txmap);
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
}
|
||||
|
||||
if (iface->conf->ieee80211n && !hapd->conf->disable_11n) {
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
"ht_caps_info=%04x\n",
|
||||
hapd->iconf->ht_capab);
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
}
|
||||
|
||||
if (iface->conf->ieee80211n && !hapd->conf->disable_11n && mode) {
|
||||
len = hostapd_write_ht_mcs_bitmask(buf, buflen, len,
|
||||
mode->mcs_set);
|
||||
}
|
||||
|
||||
if (iface->current_rates && iface->num_rates) {
|
||||
ret = os_snprintf(buf + len, buflen - len, "supported_rates=");
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
|
||||
for (j = 0; j < iface->num_rates; j++) {
|
||||
ret = os_snprintf(buf + len, buflen - len, "%s%02x",
|
||||
j > 0 ? " " : "",
|
||||
iface->current_rates[j].rate / 5);
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
}
|
||||
ret = os_snprintf(buf + len, buflen - len, "\n");
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
}
|
||||
|
||||
for (j = 0; mode && j < mode->num_channels; j++) {
|
||||
if (mode->channels[j].freq == iface->freq) {
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
"max_txpower=%u\n",
|
||||
mode->channels[j].max_tx_power);
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < iface->num_bss; i++) {
|
||||
struct hostapd_data *bss = iface->bss[i];
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
@ -578,6 +809,15 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
|
||||
len += ret;
|
||||
}
|
||||
|
||||
if (hapd->conf->chan_util_avg_period) {
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
"chan_util_avg=%u\n",
|
||||
iface->chan_util_average);
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
@ -639,3 +879,108 @@ void hostapd_ctrl_iface_pmksa_flush(struct hostapd_data *hapd)
|
||||
{
|
||||
wpa_auth_pmksa_flush(hapd->wpa_auth);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_ctrl_iface_pmksa_add(struct hostapd_data *hapd, char *cmd)
|
||||
{
|
||||
u8 spa[ETH_ALEN];
|
||||
u8 pmkid[PMKID_LEN];
|
||||
u8 pmk[PMK_LEN_MAX];
|
||||
size_t pmk_len;
|
||||
char *pos, *pos2;
|
||||
int akmp = 0, expiration = 0;
|
||||
|
||||
/*
|
||||
* Entry format:
|
||||
* <STA addr> <PMKID> <PMK> <expiration in seconds> <akmp>
|
||||
*/
|
||||
|
||||
if (hwaddr_aton(cmd, spa))
|
||||
return -1;
|
||||
|
||||
pos = os_strchr(cmd, ' ');
|
||||
if (!pos)
|
||||
return -1;
|
||||
pos++;
|
||||
|
||||
if (hexstr2bin(pos, pmkid, PMKID_LEN) < 0)
|
||||
return -1;
|
||||
|
||||
pos = os_strchr(pos, ' ');
|
||||
if (!pos)
|
||||
return -1;
|
||||
pos++;
|
||||
|
||||
pos2 = os_strchr(pos, ' ');
|
||||
if (!pos2)
|
||||
return -1;
|
||||
pmk_len = (pos2 - pos) / 2;
|
||||
if (pmk_len < PMK_LEN || pmk_len > PMK_LEN_MAX ||
|
||||
hexstr2bin(pos, pmk, pmk_len) < 0)
|
||||
return -1;
|
||||
|
||||
pos = pos2 + 1;
|
||||
|
||||
if (sscanf(pos, "%d %d", &expiration, &akmp) != 2)
|
||||
return -1;
|
||||
|
||||
return wpa_auth_pmksa_add2(hapd->wpa_auth, spa, pmk, pmk_len,
|
||||
pmkid, expiration, akmp);
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
|
||||
#ifdef CONFIG_MESH
|
||||
|
||||
int hostapd_ctrl_iface_pmksa_list_mesh(struct hostapd_data *hapd,
|
||||
const u8 *addr, char *buf, size_t len)
|
||||
{
|
||||
return wpa_auth_pmksa_list_mesh(hapd->wpa_auth, addr, buf, len);
|
||||
}
|
||||
|
||||
|
||||
void * hostapd_ctrl_iface_pmksa_create_entry(const u8 *aa, char *cmd)
|
||||
{
|
||||
u8 spa[ETH_ALEN];
|
||||
u8 pmkid[PMKID_LEN];
|
||||
u8 pmk[PMK_LEN_MAX];
|
||||
char *pos;
|
||||
int expiration;
|
||||
|
||||
/*
|
||||
* Entry format:
|
||||
* <BSSID> <PMKID> <PMK> <expiration in seconds>
|
||||
*/
|
||||
|
||||
if (hwaddr_aton(cmd, spa))
|
||||
return NULL;
|
||||
|
||||
pos = os_strchr(cmd, ' ');
|
||||
if (!pos)
|
||||
return NULL;
|
||||
pos++;
|
||||
|
||||
if (hexstr2bin(pos, pmkid, PMKID_LEN) < 0)
|
||||
return NULL;
|
||||
|
||||
pos = os_strchr(pos, ' ');
|
||||
if (!pos)
|
||||
return NULL;
|
||||
pos++;
|
||||
|
||||
if (hexstr2bin(pos, pmk, PMK_LEN) < 0)
|
||||
return NULL;
|
||||
|
||||
pos = os_strchr(pos, ' ');
|
||||
if (!pos)
|
||||
return NULL;
|
||||
pos++;
|
||||
|
||||
if (sscanf(pos, "%d", &expiration) != 1)
|
||||
return NULL;
|
||||
|
||||
return wpa_auth_pmksa_create_entry(aa, spa, pmk, pmkid, expiration);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MESH */
|
||||
#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
|
||||
|
@ -32,5 +32,9 @@ int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd);
|
||||
int hostapd_ctrl_iface_pmksa_list(struct hostapd_data *hapd, char *buf,
|
||||
size_t len);
|
||||
void hostapd_ctrl_iface_pmksa_flush(struct hostapd_data *hapd);
|
||||
int hostapd_ctrl_iface_pmksa_add(struct hostapd_data *hapd, char *cmd);
|
||||
int hostapd_ctrl_iface_pmksa_list_mesh(struct hostapd_data *hapd,
|
||||
const u8 *addr, char *buf, size_t len);
|
||||
void * hostapd_ctrl_iface_pmksa_create_entry(const u8 *aa, char *cmd);
|
||||
|
||||
#endif /* CTRL_IFACE_AP_H */
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* DFS - Dynamic Frequency Selection
|
||||
* Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2013-2015, Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2013-2017, Qualcomm Atheros, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -747,6 +747,23 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_config_dfs_chan_available(struct hostapd_iface *iface)
|
||||
{
|
||||
int n_chans, n_chans1, start_chan_idx, start_chan_idx1;
|
||||
|
||||
/* Get the start (first) channel for current configuration */
|
||||
start_chan_idx = dfs_get_start_chan_idx(iface, &start_chan_idx1);
|
||||
if (start_chan_idx < 0)
|
||||
return 0;
|
||||
|
||||
/* Get the number of used channels, depending on width */
|
||||
n_chans = dfs_get_used_n_chans(iface, &n_chans1);
|
||||
|
||||
/* Check if all channels are DFS available */
|
||||
return dfs_check_chans_available(iface, start_chan_idx, n_chans);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
|
||||
int ht_enabled, int chan_offset, int chan_width,
|
||||
int cf1, int cf2)
|
||||
@ -767,8 +784,21 @@ int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
|
||||
set_dfs_state(iface, freq, ht_enabled, chan_offset,
|
||||
chan_width, cf1, cf2,
|
||||
HOSTAPD_CHAN_DFS_AVAILABLE);
|
||||
iface->cac_started = 0;
|
||||
hostapd_setup_interface_complete(iface, 0);
|
||||
/*
|
||||
* Just mark the channel available when CAC completion
|
||||
* event is received in enabled state. CAC result could
|
||||
* have been propagated from another radio having the
|
||||
* same regulatory configuration. When CAC completion is
|
||||
* received during non-HAPD_IFACE_ENABLED state, make
|
||||
* sure the configured channel is available because this
|
||||
* CAC completion event could have been propagated from
|
||||
* another radio.
|
||||
*/
|
||||
if (iface->state != HAPD_IFACE_ENABLED &&
|
||||
hostapd_config_dfs_chan_available(iface)) {
|
||||
hostapd_setup_interface_complete(iface, 0);
|
||||
iface->cac_started = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -776,6 +806,25 @@ int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
|
||||
}
|
||||
|
||||
|
||||
int hostapd_dfs_pre_cac_expired(struct hostapd_iface *iface, int freq,
|
||||
int ht_enabled, int chan_offset, int chan_width,
|
||||
int cf1, int cf2)
|
||||
{
|
||||
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_PRE_CAC_EXPIRED
|
||||
"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
|
||||
freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
|
||||
|
||||
/* Proceed only if DFS is not offloaded to the driver */
|
||||
if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
|
||||
return 0;
|
||||
|
||||
set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
|
||||
cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
|
||||
{
|
||||
struct hostapd_channel_data *channel;
|
||||
@ -840,6 +889,13 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
|
||||
if (iface->cac_started)
|
||||
return hostapd_dfs_start_channel_switch_cac(iface);
|
||||
|
||||
/*
|
||||
* Allow selection of DFS channel in ETSI to comply with
|
||||
* uniform spreading.
|
||||
*/
|
||||
if (iface->dfs_domain == HOSTAPD_DFS_REGION_ETSI)
|
||||
skip_radar = 0;
|
||||
|
||||
/* Perform channel switch/CSA */
|
||||
channel = dfs_get_valid_channel(iface, &secondary_channel,
|
||||
&vht_oper_centr_freq_seg0_idx,
|
||||
@ -1055,7 +1111,8 @@ int hostapd_handle_dfs_offload(struct hostapd_iface *iface)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ieee80211_is_dfs(iface->freq)) {
|
||||
if (ieee80211_is_dfs(iface->freq, iface->hw_features,
|
||||
iface->num_hw_features)) {
|
||||
wpa_printf(MSG_DEBUG, "%s: freq %d MHz requires DFS",
|
||||
__func__, iface->freq);
|
||||
return 0;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* DFS - Dynamic Frequency Selection
|
||||
* Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2013, Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2013-2017, Qualcomm Atheros, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -14,6 +14,9 @@ int hostapd_handle_dfs(struct hostapd_iface *iface);
|
||||
int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
|
||||
int ht_enabled, int chan_offset, int chan_width,
|
||||
int cf1, int cf2);
|
||||
int hostapd_dfs_pre_cac_expired(struct hostapd_iface *iface, int freq,
|
||||
int ht_enabled, int chan_offset, int chan_width,
|
||||
int cf1, int cf2);
|
||||
int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
|
||||
int ht_enabled,
|
||||
int chan_offset, int chan_width,
|
||||
|
@ -7,10 +7,9 @@
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/udp.h>
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "common/dhcp.h"
|
||||
#include "l2_packet/l2_packet.h"
|
||||
#include "hostapd.h"
|
||||
#include "sta_info.h"
|
||||
@ -18,29 +17,6 @@
|
||||
#include "x_snoop.h"
|
||||
#include "dhcp_snoop.h"
|
||||
|
||||
struct bootp_pkt {
|
||||
struct iphdr iph;
|
||||
struct udphdr udph;
|
||||
u8 op;
|
||||
u8 htype;
|
||||
u8 hlen;
|
||||
u8 hops;
|
||||
be32 xid;
|
||||
be16 secs;
|
||||
be16 flags;
|
||||
be32 client_ip;
|
||||
be32 your_ip;
|
||||
be32 server_ip;
|
||||
be32 relay_ip;
|
||||
u8 hw_addr[16];
|
||||
u8 serv_name[64];
|
||||
u8 boot_file[128];
|
||||
u8 exten[312];
|
||||
} STRUCT_PACKED;
|
||||
|
||||
#define DHCPACK 5
|
||||
static const u8 ic_bootp_cookie[] = { 99, 130, 83, 99 };
|
||||
|
||||
|
||||
static const char * ipaddr_str(u32 addr)
|
||||
{
|
||||
@ -74,24 +50,26 @@ static void handle_dhcp(void *ctx, const u8 *src_addr, const u8 *buf,
|
||||
if (tot_len > (unsigned int) (len - ETH_HLEN))
|
||||
return;
|
||||
|
||||
if (os_memcmp(b->exten, ic_bootp_cookie, ARRAY_SIZE(ic_bootp_cookie)))
|
||||
if (WPA_GET_BE32(b->exten) != DHCP_MAGIC)
|
||||
return;
|
||||
|
||||
/* Parse DHCP options */
|
||||
end = (const u8 *) b + tot_len;
|
||||
pos = &b->exten[4];
|
||||
while (pos < end && *pos != 0xff) {
|
||||
while (pos < end && *pos != DHCP_OPT_END) {
|
||||
const u8 *opt = pos++;
|
||||
|
||||
if (*opt == 0) /* padding */
|
||||
if (*opt == DHCP_OPT_PAD)
|
||||
continue;
|
||||
|
||||
if (pos >= end || 1 + *pos > end - pos)
|
||||
break;
|
||||
pos += *pos + 1;
|
||||
if (pos >= end)
|
||||
break;
|
||||
|
||||
switch (*opt) {
|
||||
case 1: /* subnet mask */
|
||||
case DHCP_OPT_SUBNET_MASK:
|
||||
if (opt[1] == 4)
|
||||
subnet_mask = WPA_GET_BE32(&opt[2]);
|
||||
if (subnet_mask == 0)
|
||||
@ -101,7 +79,7 @@ static void handle_dhcp(void *ctx, const u8 *src_addr, const u8 *buf,
|
||||
prefixlen--;
|
||||
}
|
||||
break;
|
||||
case 53: /* message type */
|
||||
case DHCP_OPT_MSG_TYPE:
|
||||
if (opt[1])
|
||||
msgtype = opt[2];
|
||||
break;
|
||||
@ -176,4 +154,5 @@ int dhcp_snoop_init(struct hostapd_data *hapd)
|
||||
void dhcp_snoop_deinit(struct hostapd_data *hapd)
|
||||
{
|
||||
l2_packet_deinit(hapd->sock_dhcp);
|
||||
hapd->sock_dhcp = NULL;
|
||||
}
|
||||
|
2096
contrib/wpa/src/ap/dpp_hostapd.c
Normal file
2096
contrib/wpa/src/ap/dpp_hostapd.c
Normal file
File diff suppressed because it is too large
Load Diff
43
contrib/wpa/src/ap/dpp_hostapd.h
Normal file
43
contrib/wpa/src/ap/dpp_hostapd.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* hostapd / DPP integration
|
||||
* Copyright (c) 2017, Qualcomm Atheros, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef DPP_HOSTAPD_H
|
||||
#define DPP_HOSTAPD_H
|
||||
|
||||
int hostapd_dpp_qr_code(struct hostapd_data *hapd, const char *cmd);
|
||||
int hostapd_dpp_bootstrap_gen(struct hostapd_data *hapd, const char *cmd);
|
||||
int hostapd_dpp_bootstrap_remove(struct hostapd_data *hapd, const char *id);
|
||||
const char * hostapd_dpp_bootstrap_get_uri(struct hostapd_data *hapd,
|
||||
unsigned int id);
|
||||
int hostapd_dpp_bootstrap_info(struct hostapd_data *hapd, int id,
|
||||
char *reply, int reply_size);
|
||||
int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd);
|
||||
int hostapd_dpp_listen(struct hostapd_data *hapd, const char *cmd);
|
||||
void hostapd_dpp_listen_stop(struct hostapd_data *hapd);
|
||||
void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src,
|
||||
const u8 *buf, size_t len, unsigned int freq);
|
||||
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);
|
||||
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);
|
||||
int hostapd_dpp_configurator_sign(struct hostapd_data *hapd, const char *cmd);
|
||||
int hostapd_dpp_configurator_get_key(struct hostapd_data *hapd, unsigned int id,
|
||||
char *buf, size_t buflen);
|
||||
int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd);
|
||||
int hostapd_dpp_pkex_remove(struct hostapd_data *hapd, const char *id);
|
||||
void hostapd_dpp_stop(struct hostapd_data *hapd);
|
||||
int hostapd_dpp_init(struct hostapd_data *hapd);
|
||||
void hostapd_dpp_deinit(struct hostapd_data *hapd);
|
||||
void hostapd_dpp_init_global(struct hapd_interfaces *ifaces);
|
||||
void hostapd_dpp_deinit_global(struct hapd_interfaces *ifaces);
|
||||
|
||||
#endif /* DPP_HOSTAPD_H */
|
@ -31,10 +31,74 @@
|
||||
#include "wps_hostapd.h"
|
||||
#include "ap_drv_ops.h"
|
||||
#include "ap_config.h"
|
||||
#include "ap_mlme.h"
|
||||
#include "hw_features.h"
|
||||
#include "dfs.h"
|
||||
#include "beacon.h"
|
||||
#include "mbo_ap.h"
|
||||
#include "dpp_hostapd.h"
|
||||
#include "fils_hlp.h"
|
||||
|
||||
|
||||
#ifdef CONFIG_FILS
|
||||
void hostapd_notify_assoc_fils_finish(struct hostapd_data *hapd,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
u16 reply_res = WLAN_STATUS_SUCCESS;
|
||||
struct ieee802_11_elems elems;
|
||||
u8 buf[IEEE80211_MAX_MMPDU_SIZE], *p = buf;
|
||||
int new_assoc;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s FILS: Finish association with " MACSTR,
|
||||
__func__, MAC2STR(sta->addr));
|
||||
eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
|
||||
if (!sta->fils_pending_assoc_req)
|
||||
return;
|
||||
|
||||
ieee802_11_parse_elems(sta->fils_pending_assoc_req,
|
||||
sta->fils_pending_assoc_req_len, &elems, 0);
|
||||
if (!elems.fils_session) {
|
||||
wpa_printf(MSG_DEBUG, "%s failed to find FILS Session element",
|
||||
__func__);
|
||||
return;
|
||||
}
|
||||
|
||||
p = hostapd_eid_assoc_fils_session(sta->wpa_sm, p,
|
||||
elems.fils_session,
|
||||
sta->fils_hlp_resp);
|
||||
|
||||
reply_res = hostapd_sta_assoc(hapd, sta->addr,
|
||||
sta->fils_pending_assoc_is_reassoc,
|
||||
WLAN_STATUS_SUCCESS,
|
||||
buf, p - buf);
|
||||
ap_sta_set_authorized(hapd, sta, 1);
|
||||
new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
|
||||
sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
|
||||
sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
|
||||
hostapd_set_sta_flags(hapd, sta);
|
||||
wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FILS);
|
||||
ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
|
||||
hostapd_new_assoc_sta(hapd, sta, !new_assoc);
|
||||
os_free(sta->fils_pending_assoc_req);
|
||||
sta->fils_pending_assoc_req = NULL;
|
||||
sta->fils_pending_assoc_req_len = 0;
|
||||
wpabuf_free(sta->fils_hlp_resp);
|
||||
sta->fils_hlp_resp = NULL;
|
||||
wpabuf_free(sta->hlp_dhcp_discover);
|
||||
sta->hlp_dhcp_discover = NULL;
|
||||
fils_hlp_deinit(hapd);
|
||||
|
||||
/*
|
||||
* Remove the station in case transmission of a success response fails
|
||||
* (the STA was added associated to the driver) or if the station was
|
||||
* previously added unassociated.
|
||||
*/
|
||||
if (reply_res != WLAN_STATUS_SUCCESS || sta->added_unassoc) {
|
||||
hostapd_drv_sta_remove(hapd, sta->addr);
|
||||
sta->added_unassoc = 0;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
|
||||
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
@ -45,10 +109,10 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
struct ieee802_11_elems elems;
|
||||
const u8 *ie;
|
||||
size_t ielen;
|
||||
#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
|
||||
#if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS) || defined(CONFIG_OWE)
|
||||
u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
|
||||
u8 *p = buf;
|
||||
#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
|
||||
#endif /* CONFIG_IEEE80211R_AP || CONFIG_IEEE80211W || CONFIG_FILS || CONFIG_OWE */
|
||||
u16 reason = WLAN_REASON_UNSPECIFIED;
|
||||
u16 status = WLAN_STATUS_SUCCESS;
|
||||
const u8 *p2p_dev_addr = NULL;
|
||||
@ -171,6 +235,14 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
elems.hs20_len - 4);
|
||||
} else
|
||||
sta->hs20_ie = NULL;
|
||||
|
||||
wpabuf_free(sta->roaming_consortium);
|
||||
if (elems.roaming_cons_sel)
|
||||
sta->roaming_consortium = wpabuf_alloc_copy(
|
||||
elems.roaming_cons_sel + 4,
|
||||
elems.roaming_cons_sel_len - 4);
|
||||
else
|
||||
sta->roaming_consortium = NULL;
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
#ifdef CONFIG_FST
|
||||
@ -198,7 +270,9 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
#endif /* CONFIG_WPS */
|
||||
|
||||
wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA");
|
||||
return -1;
|
||||
reason = WLAN_REASON_INVALID_IE;
|
||||
status = WLAN_STATUS_INVALID_IE;
|
||||
goto fail;
|
||||
}
|
||||
#ifdef CONFIG_WPS
|
||||
if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 &&
|
||||
@ -231,7 +305,8 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
}
|
||||
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
|
||||
ie, ielen,
|
||||
elems.mdie, elems.mdie_len);
|
||||
elems.mdie, elems.mdie_len,
|
||||
elems.owe_dh, elems.owe_dh_len);
|
||||
if (res != WPA_IE_OK) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WPA/RSN information element rejected? (res %u)",
|
||||
@ -252,8 +327,8 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
reason = WLAN_REASON_INVALID_IE;
|
||||
status = WLAN_STATUS_INVALID_IE;
|
||||
} else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) {
|
||||
reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
|
||||
status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
|
||||
reason = WLAN_REASON_CIPHER_SUITE_REJECTED;
|
||||
status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
else {
|
||||
@ -263,10 +338,14 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
goto fail;
|
||||
}
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
|
||||
if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
|
||||
(WLAN_STA_ASSOC | WLAN_STA_MFP) &&
|
||||
!sta->sa_query_timed_out &&
|
||||
sta->sa_query_count > 0)
|
||||
ap_check_sa_query_timeout(hapd, sta);
|
||||
if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
|
||||
if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
|
||||
(WLAN_STA_ASSOC | WLAN_STA_MFP) &&
|
||||
!sta->sa_query_timed_out &&
|
||||
(sta->auth_alg != WLAN_AUTH_FT)) {
|
||||
/*
|
||||
* STA has already been associated with MFP and SA
|
||||
@ -293,7 +372,7 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
sta->flags &= ~WLAN_STA_MFP;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
if (sta->auth_alg == WLAN_AUTH_FT) {
|
||||
status = wpa_ft_validate_reassoc(sta->wpa_sm, req_ies,
|
||||
req_ies_len);
|
||||
@ -307,7 +386,7 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
} else if (hapd->conf->wps_state) {
|
||||
#ifdef CONFIG_WPS
|
||||
struct wpabuf *wps;
|
||||
@ -375,19 +454,128 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
skip_wpa_check:
|
||||
#endif /* CONFIG_WPS */
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf),
|
||||
sta->auth_alg, req_ies, req_ies_len);
|
||||
if (!p) {
|
||||
wpa_printf(MSG_DEBUG, "FT: Failed to write AssocResp IEs");
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
#ifdef CONFIG_FILS
|
||||
if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
|
||||
sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
|
||||
sta->auth_alg == WLAN_AUTH_FILS_PK) {
|
||||
int delay_assoc = 0;
|
||||
|
||||
if (!req_ies)
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
|
||||
if (!wpa_fils_validate_fils_session(sta->wpa_sm, req_ies,
|
||||
req_ies_len,
|
||||
sta->fils_session)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: Session validation failed");
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
}
|
||||
|
||||
res = wpa_fils_validate_key_confirm(sta->wpa_sm, req_ies,
|
||||
req_ies_len);
|
||||
if (res < 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: Key Confirm validation failed");
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
}
|
||||
|
||||
if (fils_process_hlp(hapd, sta, req_ies, req_ies_len) > 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: Delaying Assoc Response (HLP)");
|
||||
delay_assoc = 1;
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: Going ahead with Assoc Response (no HLP)");
|
||||
}
|
||||
|
||||
if (sta) {
|
||||
wpa_printf(MSG_DEBUG, "FILS: HLP callback cleanup");
|
||||
eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
|
||||
os_free(sta->fils_pending_assoc_req);
|
||||
sta->fils_pending_assoc_req = NULL;
|
||||
sta->fils_pending_assoc_req_len = 0;
|
||||
wpabuf_free(sta->fils_hlp_resp);
|
||||
sta->fils_hlp_resp = NULL;
|
||||
sta->fils_drv_assoc_finish = 0;
|
||||
}
|
||||
|
||||
if (sta && delay_assoc && status == WLAN_STATUS_SUCCESS) {
|
||||
u8 *req_tmp;
|
||||
|
||||
req_tmp = os_malloc(req_ies_len);
|
||||
if (!req_tmp) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: buffer allocation failed for assoc req");
|
||||
goto fail;
|
||||
}
|
||||
os_memcpy(req_tmp, req_ies, req_ies_len);
|
||||
sta->fils_pending_assoc_req = req_tmp;
|
||||
sta->fils_pending_assoc_req_len = req_ies_len;
|
||||
sta->fils_pending_assoc_is_reassoc = reassoc;
|
||||
sta->fils_drv_assoc_finish = 1;
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: Waiting for HLP processing before sending (Re)Association Response frame to "
|
||||
MACSTR, MAC2STR(sta->addr));
|
||||
eloop_register_timeout(
|
||||
0, hapd->conf->fils_hlp_wait_time * 1024,
|
||||
fils_hlp_timeout, hapd, sta);
|
||||
return 0;
|
||||
}
|
||||
p = hostapd_eid_assoc_fils_session(sta->wpa_sm, p,
|
||||
elems.fils_session,
|
||||
sta->fils_hlp_resp);
|
||||
wpa_hexdump(MSG_DEBUG, "FILS Assoc Resp BUF (IEs)",
|
||||
buf, p - buf);
|
||||
}
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
#ifdef CONFIG_OWE
|
||||
if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
|
||||
wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
|
||||
elems.owe_dh) {
|
||||
u8 *npos;
|
||||
|
||||
npos = owe_assoc_req_process(hapd, sta,
|
||||
elems.owe_dh, elems.owe_dh_len,
|
||||
p, sizeof(buf) - (p - buf),
|
||||
&reason);
|
||||
if (npos)
|
||||
p = npos;
|
||||
if (!npos &&
|
||||
reason == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) {
|
||||
status = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
|
||||
hostapd_sta_assoc(hapd, addr, reassoc, status, buf,
|
||||
p - buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!npos || reason != WLAN_STATUS_SUCCESS)
|
||||
goto fail;
|
||||
}
|
||||
#endif /* CONFIG_OWE */
|
||||
|
||||
#if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_FILS) || defined(CONFIG_OWE)
|
||||
hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
|
||||
|
||||
if (sta->auth_alg == WLAN_AUTH_FT)
|
||||
if (sta->auth_alg == WLAN_AUTH_FT ||
|
||||
sta->auth_alg == WLAN_AUTH_FILS_SK ||
|
||||
sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
|
||||
sta->auth_alg == WLAN_AUTH_FILS_PK)
|
||||
ap_sta_set_authorized(hapd, sta, 1);
|
||||
#else /* CONFIG_IEEE80211R */
|
||||
#else /* CONFIG_IEEE80211R_AP || CONFIG_FILS */
|
||||
/* Keep compiler silent about unused variables */
|
||||
if (status) {
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#endif /* CONFIG_IEEE80211R_AP || CONFIG_FILS */
|
||||
|
||||
new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
|
||||
sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
|
||||
@ -397,6 +585,12 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
|
||||
if (reassoc && (sta->auth_alg == WLAN_AUTH_FT))
|
||||
wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
|
||||
#ifdef CONFIG_FILS
|
||||
else if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
|
||||
sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
|
||||
sta->auth_alg == WLAN_AUTH_FILS_PK)
|
||||
wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FILS);
|
||||
#endif /* CONFIG_FILS */
|
||||
else
|
||||
wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
|
||||
|
||||
@ -414,9 +608,9 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
|
||||
ap_free_sta(hapd, sta);
|
||||
return -1;
|
||||
@ -464,15 +658,81 @@ void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr)
|
||||
{
|
||||
struct sta_info *sta = ap_get_sta(hapd, addr);
|
||||
|
||||
if (!sta || !hapd->conf->disassoc_low_ack)
|
||||
if (!sta || !hapd->conf->disassoc_low_ack || sta->agreed_to_steer)
|
||||
return;
|
||||
|
||||
hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_INFO,
|
||||
"disconnected due to excessive missing ACKs");
|
||||
hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_DISASSOC_LOW_ACK);
|
||||
if (sta)
|
||||
ap_sta_disassociate(hapd, sta, WLAN_REASON_DISASSOC_LOW_ACK);
|
||||
ap_sta_disassociate(hapd, sta, WLAN_REASON_DISASSOC_LOW_ACK);
|
||||
}
|
||||
|
||||
|
||||
void hostapd_event_sta_opmode_changed(struct hostapd_data *hapd, const u8 *addr,
|
||||
enum smps_mode smps_mode,
|
||||
enum chan_width chan_width, u8 rx_nss)
|
||||
{
|
||||
struct sta_info *sta = ap_get_sta(hapd, addr);
|
||||
const char *txt;
|
||||
|
||||
if (!sta)
|
||||
return;
|
||||
|
||||
switch (smps_mode) {
|
||||
case SMPS_AUTOMATIC:
|
||||
txt = "automatic";
|
||||
break;
|
||||
case SMPS_OFF:
|
||||
txt = "off";
|
||||
break;
|
||||
case SMPS_DYNAMIC:
|
||||
txt = "dynamic";
|
||||
break;
|
||||
case SMPS_STATIC:
|
||||
txt = "static";
|
||||
break;
|
||||
default:
|
||||
txt = NULL;
|
||||
break;
|
||||
}
|
||||
if (txt) {
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, STA_OPMODE_SMPS_MODE_CHANGED
|
||||
MACSTR " %s", MAC2STR(addr), txt);
|
||||
}
|
||||
|
||||
switch (chan_width) {
|
||||
case CHAN_WIDTH_20_NOHT:
|
||||
txt = "20(no-HT)";
|
||||
break;
|
||||
case CHAN_WIDTH_20:
|
||||
txt = "20";
|
||||
break;
|
||||
case CHAN_WIDTH_40:
|
||||
txt = "40";
|
||||
break;
|
||||
case CHAN_WIDTH_80:
|
||||
txt = "80";
|
||||
break;
|
||||
case CHAN_WIDTH_80P80:
|
||||
txt = "80+80";
|
||||
break;
|
||||
case CHAN_WIDTH_160:
|
||||
txt = "160";
|
||||
break;
|
||||
default:
|
||||
txt = NULL;
|
||||
break;
|
||||
}
|
||||
if (txt) {
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, STA_OPMODE_MAX_BW_CHANGED
|
||||
MACSTR " %s", MAC2STR(addr), txt);
|
||||
}
|
||||
|
||||
if (rx_nss != 0xff) {
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, STA_OPMODE_N_SS_CHANGED
|
||||
MACSTR " %d", MAC2STR(addr), rx_nss);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -485,9 +745,9 @@ 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, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
|
||||
freq, ht, offset, width, channel_width_to_string(width),
|
||||
cf1, cf2);
|
||||
"driver had channel switch: freq=%d, ht=%d, vht_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
|
||||
freq, ht, hapd->iconf->ch_switch_vht_config, offset,
|
||||
width, channel_width_to_string(width), cf1, cf2);
|
||||
|
||||
hapd->iface->freq = freq;
|
||||
|
||||
@ -532,14 +792,26 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
|
||||
|
||||
hapd->iconf->channel = channel;
|
||||
hapd->iconf->ieee80211n = ht;
|
||||
if (!ht)
|
||||
if (!ht) {
|
||||
hapd->iconf->ieee80211ac = 0;
|
||||
} else if (hapd->iconf->ch_switch_vht_config) {
|
||||
/* CHAN_SWITCH VHT config */
|
||||
if (hapd->iconf->ch_switch_vht_config &
|
||||
CH_SWITCH_VHT_ENABLED)
|
||||
hapd->iconf->ieee80211ac = 1;
|
||||
else if (hapd->iconf->ch_switch_vht_config &
|
||||
CH_SWITCH_VHT_DISABLED)
|
||||
hapd->iconf->ieee80211ac = 0;
|
||||
}
|
||||
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;
|
||||
|
||||
is_dfs = ieee80211_is_dfs(freq);
|
||||
is_dfs = ieee80211_is_dfs(freq, hapd->iface->hw_features,
|
||||
hapd->iface->num_hw_features);
|
||||
|
||||
if (hapd->csa_in_progress &&
|
||||
freq == hapd->cs_freq_params.freq) {
|
||||
@ -690,7 +962,7 @@ int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
|
||||
|
||||
#ifdef HOSTAPD
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
static void hostapd_notify_auth_ft_finish(void *ctx, const u8 *dst,
|
||||
const u8 *bssid,
|
||||
u16 auth_transaction, u16 status,
|
||||
@ -709,7 +981,33 @@ static void hostapd_notify_auth_ft_finish(void *ctx, const u8 *dst,
|
||||
|
||||
hostapd_sta_auth(hapd, dst, auth_transaction, status, ies, ies_len);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
|
||||
#ifdef CONFIG_FILS
|
||||
static void hostapd_notify_auth_fils_finish(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, u16 resp,
|
||||
struct wpabuf *data, int pub)
|
||||
{
|
||||
if (resp == WLAN_STATUS_SUCCESS) {
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG, "authentication OK (FILS)");
|
||||
sta->flags |= WLAN_STA_AUTH;
|
||||
wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
|
||||
sta->auth_alg = WLAN_AUTH_FILS_SK;
|
||||
mlme_authenticate_indication(hapd, sta);
|
||||
} else {
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"authentication failed (FILS)");
|
||||
}
|
||||
|
||||
hostapd_sta_auth(hapd, sta->addr, 2, resp,
|
||||
data ? wpabuf_head(data) : NULL,
|
||||
data ? wpabuf_len(data) : 0);
|
||||
wpabuf_free(data);
|
||||
}
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
|
||||
static void hostapd_notif_auth(struct hostapd_data *hapd,
|
||||
@ -730,7 +1028,7 @@ static void hostapd_notif_auth(struct hostapd_data *hapd,
|
||||
}
|
||||
sta->flags &= ~WLAN_STA_PREAUTH;
|
||||
ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
if (rx_auth->auth_type == WLAN_AUTH_FT && hapd->wpa_auth) {
|
||||
sta->auth_alg = WLAN_AUTH_FT;
|
||||
if (sta->wpa_sm == NULL)
|
||||
@ -748,7 +1046,19 @@ static void hostapd_notif_auth(struct hostapd_data *hapd,
|
||||
hostapd_notify_auth_ft_finish, hapd);
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
#ifdef CONFIG_FILS
|
||||
if (rx_auth->auth_type == WLAN_AUTH_FILS_SK) {
|
||||
sta->auth_alg = WLAN_AUTH_FILS_SK;
|
||||
handle_auth_fils(hapd, sta, rx_auth->ies, rx_auth->ies_len,
|
||||
rx_auth->auth_type, rx_auth->auth_transaction,
|
||||
rx_auth->status_code,
|
||||
hostapd_notify_auth_fils_finish);
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
fail:
|
||||
hostapd_sta_auth(hapd, rx_auth->peer, rx_auth->auth_transaction + 1,
|
||||
status, resp_ies, resp_ies_len);
|
||||
@ -762,32 +1072,36 @@ static void hostapd_action_rx(struct hostapd_data *hapd,
|
||||
struct sta_info *sta;
|
||||
size_t plen __maybe_unused;
|
||||
u16 fc;
|
||||
u8 *action __maybe_unused;
|
||||
|
||||
if (drv_mgmt->frame_len < 24 + 1)
|
||||
if (drv_mgmt->frame_len < IEEE80211_HDRLEN + 2 + 1)
|
||||
return;
|
||||
|
||||
plen = drv_mgmt->frame_len - 24 - 1;
|
||||
plen = drv_mgmt->frame_len - IEEE80211_HDRLEN - 1;
|
||||
|
||||
mgmt = (struct ieee80211_mgmt *) drv_mgmt->frame;
|
||||
fc = le_to_host16(mgmt->frame_control);
|
||||
if (WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION)
|
||||
return; /* handled by the driver */
|
||||
|
||||
wpa_printf(MSG_DEBUG, "RX_ACTION cat %d action plen %d",
|
||||
mgmt->u.action.category, (int) plen);
|
||||
action = (u8 *) &mgmt->u.action.u;
|
||||
wpa_printf(MSG_DEBUG, "RX_ACTION category %u action %u sa " MACSTR
|
||||
" da " MACSTR " plen %d",
|
||||
mgmt->u.action.category, *action,
|
||||
MAC2STR(mgmt->sa), MAC2STR(mgmt->da), (int) plen);
|
||||
|
||||
sta = ap_get_sta(hapd, mgmt->sa);
|
||||
if (sta == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "%s: station not found", __func__);
|
||||
return;
|
||||
}
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
if (mgmt->u.action.category == WLAN_ACTION_FT) {
|
||||
const u8 *payload = drv_mgmt->frame + 24 + 1;
|
||||
|
||||
wpa_ft_action_rx(sta->wpa_sm, payload, plen);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
if (mgmt->u.action.category == WLAN_ACTION_SA_QUERY && plen >= 4) {
|
||||
ieee802_11_sa_query_action(
|
||||
@ -796,18 +1110,34 @@ static void hostapd_action_rx(struct hostapd_data *hapd,
|
||||
mgmt->u.action.u.sa_query_resp.trans_id);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
#ifdef CONFIG_WNM
|
||||
#ifdef CONFIG_WNM_AP
|
||||
if (mgmt->u.action.category == WLAN_ACTION_WNM) {
|
||||
ieee802_11_rx_wnm_action_ap(hapd, mgmt, drv_mgmt->frame_len);
|
||||
}
|
||||
#endif /* CONFIG_WNM */
|
||||
#endif /* CONFIG_WNM_AP */
|
||||
#ifdef CONFIG_FST
|
||||
if (mgmt->u.action.category == WLAN_ACTION_FST && hapd->iface->fst) {
|
||||
fst_rx_action(hapd->iface->fst, mgmt, drv_mgmt->frame_len);
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_FST */
|
||||
#ifdef CONFIG_DPP
|
||||
if (plen >= 1 + 4 &&
|
||||
mgmt->u.action.u.vs_public_action.action ==
|
||||
WLAN_PA_VENDOR_SPECIFIC &&
|
||||
WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) ==
|
||||
OUI_WFA &&
|
||||
mgmt->u.action.u.vs_public_action.variable[0] ==
|
||||
DPP_OUI_TYPE) {
|
||||
const u8 *pos, *end;
|
||||
|
||||
pos = mgmt->u.action.u.vs_public_action.oui;
|
||||
end = drv_mgmt->frame + drv_mgmt->frame_len;
|
||||
hostapd_dpp_rx_action(hapd, mgmt->sa, pos, end - pos,
|
||||
drv_mgmt->freq);
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_DPP */
|
||||
}
|
||||
|
||||
|
||||
@ -891,6 +1221,7 @@ static int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
|
||||
}
|
||||
|
||||
os_memset(&fi, 0, sizeof(fi));
|
||||
fi.freq = rx_mgmt->freq;
|
||||
fi.datarate = rx_mgmt->datarate;
|
||||
fi.ssi_signal = rx_mgmt->ssi_signal;
|
||||
|
||||
@ -1122,6 +1453,16 @@ static void hostapd_event_dfs_radar_detected(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_event_dfs_pre_cac_expired(struct hostapd_data *hapd,
|
||||
struct dfs_event *radar)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "DFS Pre-CAC expired on %d MHz", radar->freq);
|
||||
hostapd_dfs_pre_cac_expired(hapd->iface, radar->freq, radar->ht_enabled,
|
||||
radar->chan_offset, radar->chan_width,
|
||||
radar->cf1, radar->cf2);
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_event_dfs_cac_finished(struct hostapd_data *hapd,
|
||||
struct dfs_event *radar)
|
||||
{
|
||||
@ -1164,6 +1505,28 @@ static void hostapd_event_dfs_cac_started(struct hostapd_data *hapd,
|
||||
#endif /* NEED_AP_MLME */
|
||||
|
||||
|
||||
static void hostapd_event_wds_sta_interface_status(struct hostapd_data *hapd,
|
||||
int istatus,
|
||||
const char *ifname,
|
||||
const u8 *addr)
|
||||
{
|
||||
struct sta_info *sta = ap_get_sta(hapd, addr);
|
||||
|
||||
if (sta) {
|
||||
os_free(sta->ifname_wds);
|
||||
if (istatus == INTERFACE_ADDED)
|
||||
sta->ifname_wds = os_strdup(ifname);
|
||||
else
|
||||
sta->ifname_wds = NULL;
|
||||
}
|
||||
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, "%sifname=%s sta_addr=" MACSTR,
|
||||
istatus == INTERFACE_ADDED ?
|
||||
WDS_STA_INTERFACE_ADDED : WDS_STA_INTERFACE_REMOVED,
|
||||
ifname, MAC2STR(addr));
|
||||
}
|
||||
|
||||
|
||||
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||
union wpa_event_data *data)
|
||||
{
|
||||
@ -1314,6 +1677,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||
break;
|
||||
hostapd_event_dfs_radar_detected(hapd, &data->dfs_event);
|
||||
break;
|
||||
case EVENT_DFS_PRE_CAC_EXPIRED:
|
||||
if (!data)
|
||||
break;
|
||||
hostapd_event_dfs_pre_cac_expired(hapd, &data->dfs_event);
|
||||
break;
|
||||
case EVENT_DFS_CAC_FINISHED:
|
||||
if (!data)
|
||||
break;
|
||||
@ -1351,7 +1719,10 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||
* Try to re-enable interface if the driver stopped it
|
||||
* when the interface got disabled.
|
||||
*/
|
||||
wpa_auth_reconfig_group_keys(hapd->wpa_auth);
|
||||
if (hapd->wpa_auth)
|
||||
wpa_auth_reconfig_group_keys(hapd->wpa_auth);
|
||||
else
|
||||
hostapd_reconfig_encryption(hapd);
|
||||
hapd->reenable_beacon = 1;
|
||||
ieee802_11_set_beacon(hapd);
|
||||
}
|
||||
@ -1367,6 +1738,18 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||
&data->acs_selected_channels);
|
||||
break;
|
||||
#endif /* CONFIG_ACS */
|
||||
case EVENT_STATION_OPMODE_CHANGED:
|
||||
hostapd_event_sta_opmode_changed(hapd, data->sta_opmode.addr,
|
||||
data->sta_opmode.smps_mode,
|
||||
data->sta_opmode.chan_width,
|
||||
data->sta_opmode.rx_nss);
|
||||
break;
|
||||
case EVENT_WDS_STA_INTERFACE_STATUS:
|
||||
hostapd_event_wds_sta_interface_status(
|
||||
hapd, data->wds_sta_interface.istatus,
|
||||
data->wds_sta_interface.ifname,
|
||||
data->wds_sta_interface.sta_addr);
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "Unknown event %d", event);
|
||||
break;
|
||||
|
@ -91,6 +91,8 @@ static int get_user_cb(void *ctx, int argc, char *argv[], char *col[])
|
||||
set_user_methods(user, argv[i]);
|
||||
} else if (os_strcmp(col[i], "remediation") == 0 && argv[i]) {
|
||||
user->remediation = strlen(argv[i]) > 0;
|
||||
} else if (os_strcmp(col[i], "t_c_timestamp") == 0 && argv[i]) {
|
||||
user->t_c_timestamp = strtol(argv[i], NULL, 10);
|
||||
}
|
||||
}
|
||||
|
||||
|
191
contrib/wpa/src/ap/eth_p_oui.c
Normal file
191
contrib/wpa/src/ap/eth_p_oui.c
Normal file
@ -0,0 +1,191 @@
|
||||
/*
|
||||
* hostapd / IEEE 802 OUI Extended EtherType 88-B7
|
||||
* Copyright (c) 2016, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* 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 "l2_packet/l2_packet.h"
|
||||
#include "hostapd.h"
|
||||
#include "eth_p_oui.h"
|
||||
|
||||
/*
|
||||
* See IEEE Std 802-2014, Clause 9.2.4 for the definition of the OUI Extended
|
||||
* EtherType 88-B7. This file implements this with OUI 00:13:74 and
|
||||
* vendor-specific subtype 0x0001.
|
||||
*/
|
||||
static const u8 global_oui[] = { 0x00, 0x13, 0x74, 0x00, 0x01 };
|
||||
|
||||
struct eth_p_oui_iface {
|
||||
struct dl_list list;
|
||||
char ifname[IFNAMSIZ + 1];
|
||||
struct l2_packet_data *l2;
|
||||
struct dl_list receiver;
|
||||
};
|
||||
|
||||
struct eth_p_oui_ctx {
|
||||
struct dl_list list;
|
||||
struct eth_p_oui_iface *iface;
|
||||
/* all data needed to deliver and unregister */
|
||||
u8 oui_suffix; /* last byte of OUI */
|
||||
void (*rx_callback)(void *ctx, const u8 *src_addr,
|
||||
const u8 *dst_addr, u8 oui_suffix,
|
||||
const u8 *buf, size_t len);
|
||||
void *rx_callback_ctx;
|
||||
};
|
||||
|
||||
|
||||
void eth_p_oui_deliver(struct eth_p_oui_ctx *ctx, const u8 *src_addr,
|
||||
const u8 *dst_addr, const u8 *buf, size_t len)
|
||||
{
|
||||
ctx->rx_callback(ctx->rx_callback_ctx, src_addr, dst_addr,
|
||||
ctx->oui_suffix, buf, len);
|
||||
}
|
||||
|
||||
|
||||
static void eth_p_rx(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
|
||||
{
|
||||
struct eth_p_oui_iface *iface = ctx;
|
||||
struct eth_p_oui_ctx *receiver;
|
||||
const struct l2_ethhdr *ethhdr;
|
||||
|
||||
if (len < sizeof(*ethhdr) + sizeof(global_oui) + 1) {
|
||||
/* too short packet */
|
||||
return;
|
||||
}
|
||||
|
||||
ethhdr = (struct l2_ethhdr *) buf;
|
||||
/* trim eth_hdr from buf and len */
|
||||
buf += sizeof(*ethhdr);
|
||||
len -= sizeof(*ethhdr);
|
||||
|
||||
/* verify OUI and vendor-specific subtype match */
|
||||
if (os_memcmp(buf, global_oui, sizeof(global_oui)) != 0)
|
||||
return;
|
||||
buf += sizeof(global_oui);
|
||||
len -= sizeof(global_oui);
|
||||
|
||||
dl_list_for_each(receiver, &iface->receiver,
|
||||
struct eth_p_oui_ctx, list) {
|
||||
if (buf[0] != receiver->oui_suffix)
|
||||
continue;
|
||||
|
||||
eth_p_oui_deliver(receiver, ethhdr->h_source, ethhdr->h_dest,
|
||||
buf + 1, len - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct eth_p_oui_ctx *
|
||||
eth_p_oui_register(struct hostapd_data *hapd, const char *ifname, u8 oui_suffix,
|
||||
void (*rx_callback)(void *ctx, const u8 *src_addr,
|
||||
const u8 *dst_addr, u8 oui_suffix,
|
||||
const u8 *buf, size_t len),
|
||||
void *rx_callback_ctx)
|
||||
{
|
||||
struct eth_p_oui_iface *iface;
|
||||
struct eth_p_oui_ctx *receiver;
|
||||
int found = 0;
|
||||
struct hapd_interfaces *interfaces;
|
||||
|
||||
receiver = os_zalloc(sizeof(*receiver));
|
||||
if (!receiver)
|
||||
goto err;
|
||||
|
||||
receiver->oui_suffix = oui_suffix;
|
||||
receiver->rx_callback = rx_callback;
|
||||
receiver->rx_callback_ctx = rx_callback_ctx;
|
||||
|
||||
interfaces = hapd->iface->interfaces;
|
||||
|
||||
dl_list_for_each(iface, &interfaces->eth_p_oui, struct eth_p_oui_iface,
|
||||
list) {
|
||||
if (os_strcmp(iface->ifname, ifname) != 0)
|
||||
continue;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
iface = os_zalloc(sizeof(*iface));
|
||||
if (!iface)
|
||||
goto err;
|
||||
|
||||
os_strlcpy(iface->ifname, ifname, sizeof(iface->ifname));
|
||||
iface->l2 = l2_packet_init(ifname, NULL, ETH_P_OUI, eth_p_rx,
|
||||
iface, 1);
|
||||
if (!iface->l2) {
|
||||
os_free(iface);
|
||||
goto err;
|
||||
}
|
||||
dl_list_init(&iface->receiver);
|
||||
|
||||
dl_list_add_tail(&interfaces->eth_p_oui, &iface->list);
|
||||
}
|
||||
|
||||
dl_list_add_tail(&iface->receiver, &receiver->list);
|
||||
receiver->iface = iface;
|
||||
|
||||
return receiver;
|
||||
err:
|
||||
os_free(receiver);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void eth_p_oui_unregister(struct eth_p_oui_ctx *ctx)
|
||||
{
|
||||
struct eth_p_oui_iface *iface;
|
||||
|
||||
if (!ctx)
|
||||
return;
|
||||
|
||||
iface = ctx->iface;
|
||||
|
||||
dl_list_del(&ctx->list);
|
||||
os_free(ctx);
|
||||
|
||||
if (dl_list_empty(&iface->receiver)) {
|
||||
dl_list_del(&iface->list);
|
||||
l2_packet_deinit(iface->l2);
|
||||
os_free(iface);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int eth_p_oui_send(struct eth_p_oui_ctx *ctx, const u8 *src_addr,
|
||||
const u8 *dst_addr, const u8 *buf, size_t len)
|
||||
{
|
||||
struct eth_p_oui_iface *iface = ctx->iface;
|
||||
u8 *packet, *p;
|
||||
size_t packet_len;
|
||||
int ret;
|
||||
struct l2_ethhdr *ethhdr;
|
||||
|
||||
packet_len = sizeof(*ethhdr) + sizeof(global_oui) + 1 + len;
|
||||
packet = os_zalloc(packet_len);
|
||||
if (!packet)
|
||||
return -1;
|
||||
p = packet;
|
||||
|
||||
ethhdr = (struct l2_ethhdr *) packet;
|
||||
os_memcpy(ethhdr->h_source, src_addr, ETH_ALEN);
|
||||
os_memcpy(ethhdr->h_dest, dst_addr, ETH_ALEN);
|
||||
ethhdr->h_proto = host_to_be16(ETH_P_OUI);
|
||||
p += sizeof(*ethhdr);
|
||||
|
||||
os_memcpy(p, global_oui, sizeof(global_oui));
|
||||
p[sizeof(global_oui)] = ctx->oui_suffix;
|
||||
p += sizeof(global_oui) + 1;
|
||||
|
||||
os_memcpy(p, buf, len);
|
||||
|
||||
ret = l2_packet_send(iface->l2, NULL, 0, packet, packet_len);
|
||||
os_free(packet);
|
||||
return ret;
|
||||
}
|
28
contrib/wpa/src/ap/eth_p_oui.h
Normal file
28
contrib/wpa/src/ap/eth_p_oui.h
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* hostapd / IEEE 802 OUI Extended Ethertype
|
||||
* Copyright (c) 2016, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef ETH_P_OUI_H
|
||||
#define ETH_P_OUI_H
|
||||
|
||||
struct eth_p_oui_ctx;
|
||||
struct hostapd_data;
|
||||
|
||||
/* rx_callback only gets payload after OUI passed as buf */
|
||||
struct eth_p_oui_ctx *
|
||||
eth_p_oui_register(struct hostapd_data *hapd, const char *ifname, u8 oui_suffix,
|
||||
void (*rx_callback)(void *ctx, const u8 *src_addr,
|
||||
const u8 *dst_addr, u8 oui_suffix,
|
||||
const u8 *buf, size_t len),
|
||||
void *rx_callback_ctx);
|
||||
void eth_p_oui_unregister(struct eth_p_oui_ctx *eth_p_oui);
|
||||
int eth_p_oui_send(struct eth_p_oui_ctx *ctx, const u8 *src_addr,
|
||||
const u8 *dst_addr, const u8 *buf, size_t len);
|
||||
void eth_p_oui_deliver(struct eth_p_oui_ctx *ctx, const u8 *src_addr,
|
||||
const u8 *dst_addr, const u8 *buf, size_t len);
|
||||
|
||||
#endif /* ETH_P_OUI_H */
|
641
contrib/wpa/src/ap/fils_hlp.c
Normal file
641
contrib/wpa/src/ap/fils_hlp.c
Normal file
@ -0,0 +1,641 @@
|
||||
/*
|
||||
* FILS HLP request processing
|
||||
* Copyright (c) 2017, Qualcomm Atheros, Inc.
|
||||
*
|
||||
* 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 "common/dhcp.h"
|
||||
#include "hostapd.h"
|
||||
#include "sta_info.h"
|
||||
#include "ieee802_11.h"
|
||||
#include "fils_hlp.h"
|
||||
|
||||
|
||||
static be16 ip_checksum(const void *buf, size_t len)
|
||||
{
|
||||
u32 sum = 0;
|
||||
const u16 *pos;
|
||||
|
||||
for (pos = buf; len >= 2; len -= 2)
|
||||
sum += ntohs(*pos++);
|
||||
if (len)
|
||||
sum += ntohs(*pos << 8);
|
||||
|
||||
sum = (sum >> 16) + (sum & 0xffff);
|
||||
sum += sum >> 16;
|
||||
return htons(~sum);
|
||||
}
|
||||
|
||||
|
||||
static int fils_dhcp_request(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
struct dhcp_data *dhcpoffer, u8 *dhcpofferend)
|
||||
{
|
||||
u8 *pos, *end;
|
||||
struct dhcp_data *dhcp;
|
||||
struct sockaddr_in addr;
|
||||
ssize_t res;
|
||||
const u8 *server_id = NULL;
|
||||
|
||||
if (!sta->hlp_dhcp_discover) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: No pending HLP DHCPDISCOVER available");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Convert to DHCPREQUEST, remove rapid commit option, replace requested
|
||||
* IP address option with yiaddr. */
|
||||
pos = wpabuf_mhead(sta->hlp_dhcp_discover);
|
||||
end = pos + wpabuf_len(sta->hlp_dhcp_discover);
|
||||
dhcp = (struct dhcp_data *) pos;
|
||||
pos = (u8 *) (dhcp + 1);
|
||||
pos += 4; /* skip magic */
|
||||
while (pos < end && *pos != DHCP_OPT_END) {
|
||||
u8 opt, olen;
|
||||
|
||||
opt = *pos++;
|
||||
if (opt == DHCP_OPT_PAD)
|
||||
continue;
|
||||
if (pos >= end)
|
||||
break;
|
||||
olen = *pos++;
|
||||
if (olen > end - pos)
|
||||
break;
|
||||
|
||||
switch (opt) {
|
||||
case DHCP_OPT_MSG_TYPE:
|
||||
if (olen > 0)
|
||||
*pos = DHCPREQUEST;
|
||||
break;
|
||||
case DHCP_OPT_RAPID_COMMIT:
|
||||
case DHCP_OPT_REQUESTED_IP_ADDRESS:
|
||||
case DHCP_OPT_SERVER_ID:
|
||||
/* Remove option */
|
||||
pos -= 2;
|
||||
os_memmove(pos, pos + 2 + olen, end - pos - 2 - olen);
|
||||
end -= 2 + olen;
|
||||
olen = 0;
|
||||
break;
|
||||
}
|
||||
pos += olen;
|
||||
}
|
||||
if (pos >= end || *pos != DHCP_OPT_END) {
|
||||
wpa_printf(MSG_DEBUG, "FILS: Could not update DHCPDISCOVER");
|
||||
return -1;
|
||||
}
|
||||
sta->hlp_dhcp_discover->used = pos - (u8 *) dhcp;
|
||||
|
||||
/* Copy Server ID option from DHCPOFFER to DHCPREQUEST */
|
||||
pos = (u8 *) (dhcpoffer + 1);
|
||||
end = dhcpofferend;
|
||||
pos += 4; /* skip magic */
|
||||
while (pos < end && *pos != DHCP_OPT_END) {
|
||||
u8 opt, olen;
|
||||
|
||||
opt = *pos++;
|
||||
if (opt == DHCP_OPT_PAD)
|
||||
continue;
|
||||
if (pos >= end)
|
||||
break;
|
||||
olen = *pos++;
|
||||
if (olen > end - pos)
|
||||
break;
|
||||
|
||||
switch (opt) {
|
||||
case DHCP_OPT_SERVER_ID:
|
||||
server_id = pos - 2;
|
||||
break;
|
||||
}
|
||||
pos += olen;
|
||||
}
|
||||
|
||||
if (wpabuf_resize(&sta->hlp_dhcp_discover,
|
||||
6 + 1 + (server_id ? 2 + server_id[1] : 0)))
|
||||
return -1;
|
||||
if (server_id)
|
||||
wpabuf_put_data(sta->hlp_dhcp_discover, server_id,
|
||||
2 + server_id[1]);
|
||||
wpabuf_put_u8(sta->hlp_dhcp_discover, DHCP_OPT_REQUESTED_IP_ADDRESS);
|
||||
wpabuf_put_u8(sta->hlp_dhcp_discover, 4);
|
||||
wpabuf_put_data(sta->hlp_dhcp_discover, &dhcpoffer->your_ip, 4);
|
||||
wpabuf_put_u8(sta->hlp_dhcp_discover, DHCP_OPT_END);
|
||||
|
||||
os_memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = hapd->conf->dhcp_server.u.v4.s_addr;
|
||||
addr.sin_port = htons(hapd->conf->dhcp_server_port);
|
||||
res = sendto(hapd->dhcp_sock, wpabuf_head(sta->hlp_dhcp_discover),
|
||||
wpabuf_len(sta->hlp_dhcp_discover), 0,
|
||||
(const struct sockaddr *) &addr, sizeof(addr));
|
||||
if (res < 0) {
|
||||
wpa_printf(MSG_ERROR, "FILS: DHCP sendto failed: %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: Acting as DHCP rapid commit proxy for %s:%d",
|
||||
inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
|
||||
wpabuf_free(sta->hlp_dhcp_discover);
|
||||
sta->hlp_dhcp_discover = NULL;
|
||||
sta->fils_dhcp_rapid_commit_proxy = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void fils_dhcp_handler(int sd, void *eloop_ctx, void *sock_ctx)
|
||||
{
|
||||
struct hostapd_data *hapd = sock_ctx;
|
||||
struct sta_info *sta;
|
||||
u8 buf[1500], *pos, *end, *end_opt = NULL;
|
||||
struct dhcp_data *dhcp;
|
||||
struct sockaddr_in addr;
|
||||
socklen_t addr_len;
|
||||
ssize_t res;
|
||||
u8 msgtype = 0;
|
||||
int rapid_commit = 0;
|
||||
struct iphdr *iph;
|
||||
struct udphdr *udph;
|
||||
struct wpabuf *resp;
|
||||
const u8 *rpos;
|
||||
size_t left, len;
|
||||
|
||||
addr_len = sizeof(addr);
|
||||
res = recvfrom(sd, buf, sizeof(buf), 0,
|
||||
(struct sockaddr *) &addr, &addr_len);
|
||||
if (res < 0) {
|
||||
wpa_printf(MSG_DEBUG, "FILS: DHCP read failed: %s",
|
||||
strerror(errno));
|
||||
return;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "FILS: DHCP response from server %s:%d (len=%d)",
|
||||
inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), (int) res);
|
||||
wpa_hexdump(MSG_MSGDUMP, "FILS: HLP - DHCP server response", buf, res);
|
||||
if ((size_t) res < sizeof(*dhcp))
|
||||
return;
|
||||
dhcp = (struct dhcp_data *) buf;
|
||||
if (dhcp->op != 2)
|
||||
return; /* Not a BOOTREPLY */
|
||||
if (dhcp->relay_ip != hapd->conf->own_ip_addr.u.v4.s_addr) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: HLP - DHCP response to unknown relay address 0x%x",
|
||||
dhcp->relay_ip);
|
||||
return;
|
||||
}
|
||||
dhcp->relay_ip = 0;
|
||||
pos = (u8 *) (dhcp + 1);
|
||||
end = &buf[res];
|
||||
|
||||
if (end - pos < 4 || WPA_GET_BE32(pos) != DHCP_MAGIC) {
|
||||
wpa_printf(MSG_DEBUG, "FILS: HLP - no DHCP magic in response");
|
||||
return;
|
||||
}
|
||||
pos += 4;
|
||||
|
||||
wpa_hexdump(MSG_DEBUG, "FILS: HLP - DHCP options in response",
|
||||
pos, end - pos);
|
||||
while (pos < end && *pos != DHCP_OPT_END) {
|
||||
u8 opt, olen;
|
||||
|
||||
opt = *pos++;
|
||||
if (opt == DHCP_OPT_PAD)
|
||||
continue;
|
||||
if (pos >= end)
|
||||
break;
|
||||
olen = *pos++;
|
||||
if (olen > end - pos)
|
||||
break;
|
||||
|
||||
switch (opt) {
|
||||
case DHCP_OPT_MSG_TYPE:
|
||||
if (olen > 0)
|
||||
msgtype = pos[0];
|
||||
break;
|
||||
case DHCP_OPT_RAPID_COMMIT:
|
||||
rapid_commit = 1;
|
||||
break;
|
||||
}
|
||||
pos += olen;
|
||||
}
|
||||
if (pos < end && *pos == DHCP_OPT_END)
|
||||
end_opt = pos;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: HLP - DHCP message type %u (rapid_commit=%d hw_addr="
|
||||
MACSTR ")",
|
||||
msgtype, rapid_commit, MAC2STR(dhcp->hw_addr));
|
||||
|
||||
sta = ap_get_sta(hapd, dhcp->hw_addr);
|
||||
if (!sta || !sta->fils_pending_assoc_req) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: No pending HLP DHCP exchange with hw_addr "
|
||||
MACSTR, MAC2STR(dhcp->hw_addr));
|
||||
return;
|
||||
}
|
||||
|
||||
if (hapd->conf->dhcp_rapid_commit_proxy && msgtype == DHCPOFFER &&
|
||||
!rapid_commit) {
|
||||
/* Use hostapd to take care of 4-message exchange and convert
|
||||
* the final DHCPACK to rapid commit version. */
|
||||
if (fils_dhcp_request(hapd, sta, dhcp, end) == 0)
|
||||
return;
|
||||
/* failed, so send the server response as-is */
|
||||
} else if (msgtype != DHCPACK) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: No DHCPACK available from the server and cannot do rapid commit proxying");
|
||||
}
|
||||
|
||||
pos = buf;
|
||||
resp = wpabuf_alloc(2 * ETH_ALEN + 6 + 2 +
|
||||
sizeof(*iph) + sizeof(*udph) + (end - pos) + 2);
|
||||
if (!resp)
|
||||
return;
|
||||
wpabuf_put_data(resp, sta->addr, ETH_ALEN);
|
||||
wpabuf_put_data(resp, hapd->own_addr, ETH_ALEN);
|
||||
wpabuf_put_data(resp, "\xaa\xaa\x03\x00\x00\x00", 6);
|
||||
wpabuf_put_be16(resp, ETH_P_IP);
|
||||
iph = wpabuf_put(resp, sizeof(*iph));
|
||||
iph->version = 4;
|
||||
iph->ihl = sizeof(*iph) / 4;
|
||||
iph->tot_len = htons(sizeof(*iph) + sizeof(*udph) + (end - pos));
|
||||
iph->ttl = 1;
|
||||
iph->protocol = 17; /* UDP */
|
||||
iph->saddr = hapd->conf->dhcp_server.u.v4.s_addr;
|
||||
iph->daddr = dhcp->client_ip;
|
||||
iph->check = ip_checksum(iph, sizeof(*iph));
|
||||
udph = wpabuf_put(resp, sizeof(*udph));
|
||||
udph->uh_sport = htons(DHCP_SERVER_PORT);
|
||||
udph->uh_dport = htons(DHCP_CLIENT_PORT);
|
||||
udph->uh_ulen = htons(sizeof(*udph) + (end - pos));
|
||||
udph->uh_sum = htons(0x0000); /* TODO: calculate checksum */
|
||||
if (hapd->conf->dhcp_rapid_commit_proxy && msgtype == DHCPACK &&
|
||||
!rapid_commit && sta->fils_dhcp_rapid_commit_proxy && end_opt) {
|
||||
/* Add rapid commit option */
|
||||
wpabuf_put_data(resp, pos, end_opt - pos);
|
||||
wpabuf_put_u8(resp, DHCP_OPT_RAPID_COMMIT);
|
||||
wpabuf_put_u8(resp, 0);
|
||||
wpabuf_put_data(resp, end_opt, end - end_opt);
|
||||
} else {
|
||||
wpabuf_put_data(resp, pos, end - pos);
|
||||
}
|
||||
if (wpabuf_resize(&sta->fils_hlp_resp, wpabuf_len(resp) +
|
||||
2 * wpabuf_len(resp) / 255 + 100)) {
|
||||
wpabuf_free(resp);
|
||||
return;
|
||||
}
|
||||
|
||||
rpos = wpabuf_head(resp);
|
||||
left = wpabuf_len(resp);
|
||||
|
||||
wpabuf_put_u8(sta->fils_hlp_resp, WLAN_EID_EXTENSION); /* Element ID */
|
||||
if (left <= 254)
|
||||
len = 1 + left;
|
||||
else
|
||||
len = 255;
|
||||
wpabuf_put_u8(sta->fils_hlp_resp, len); /* Length */
|
||||
/* Element ID Extension */
|
||||
wpabuf_put_u8(sta->fils_hlp_resp, WLAN_EID_EXT_FILS_HLP_CONTAINER);
|
||||
/* Destination MAC Address, Source MAC Address, HLP Packet.
|
||||
* HLP Packet is in MSDU format (i.e., including the LLC/SNAP header
|
||||
* when LPD is used). */
|
||||
wpabuf_put_data(sta->fils_hlp_resp, rpos, len - 1);
|
||||
rpos += len - 1;
|
||||
left -= len - 1;
|
||||
while (left) {
|
||||
wpabuf_put_u8(sta->fils_hlp_resp, WLAN_EID_FRAGMENT);
|
||||
len = left > 255 ? 255 : left;
|
||||
wpabuf_put_u8(sta->fils_hlp_resp, len);
|
||||
wpabuf_put_data(sta->fils_hlp_resp, rpos, len);
|
||||
rpos += len;
|
||||
left -= len;
|
||||
}
|
||||
wpabuf_free(resp);
|
||||
|
||||
if (sta->fils_drv_assoc_finish)
|
||||
hostapd_notify_assoc_fils_finish(hapd, sta);
|
||||
else
|
||||
fils_hlp_finish_assoc(hapd, sta);
|
||||
}
|
||||
|
||||
|
||||
static int fils_process_hlp_dhcp(struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
const u8 *msg, size_t len)
|
||||
{
|
||||
const struct dhcp_data *dhcp;
|
||||
struct wpabuf *dhcp_buf;
|
||||
struct dhcp_data *dhcp_msg;
|
||||
u8 msgtype = 0;
|
||||
int rapid_commit = 0;
|
||||
const u8 *pos = msg, *end;
|
||||
struct sockaddr_in addr;
|
||||
ssize_t res;
|
||||
|
||||
if (len < sizeof(*dhcp))
|
||||
return 0;
|
||||
dhcp = (const struct dhcp_data *) pos;
|
||||
end = pos + len;
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: HLP request DHCP: op=%u htype=%u hlen=%u hops=%u xid=0x%x",
|
||||
dhcp->op, dhcp->htype, dhcp->hlen, dhcp->hops,
|
||||
ntohl(dhcp->xid));
|
||||
pos += sizeof(*dhcp);
|
||||
if (dhcp->op != 1)
|
||||
return 0; /* Not a BOOTREQUEST */
|
||||
|
||||
if (end - pos < 4)
|
||||
return 0;
|
||||
if (WPA_GET_BE32(pos) != DHCP_MAGIC) {
|
||||
wpa_printf(MSG_DEBUG, "FILS: HLP - no DHCP magic");
|
||||
return 0;
|
||||
}
|
||||
pos += 4;
|
||||
|
||||
wpa_hexdump(MSG_DEBUG, "FILS: HLP - DHCP options", pos, end - pos);
|
||||
while (pos < end && *pos != DHCP_OPT_END) {
|
||||
u8 opt, olen;
|
||||
|
||||
opt = *pos++;
|
||||
if (opt == DHCP_OPT_PAD)
|
||||
continue;
|
||||
if (pos >= end)
|
||||
break;
|
||||
olen = *pos++;
|
||||
if (olen > end - pos)
|
||||
break;
|
||||
|
||||
switch (opt) {
|
||||
case DHCP_OPT_MSG_TYPE:
|
||||
if (olen > 0)
|
||||
msgtype = pos[0];
|
||||
break;
|
||||
case DHCP_OPT_RAPID_COMMIT:
|
||||
rapid_commit = 1;
|
||||
break;
|
||||
}
|
||||
pos += olen;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "FILS: HLP - DHCP message type %u", msgtype);
|
||||
if (msgtype != DHCPDISCOVER)
|
||||
return 0;
|
||||
|
||||
if (hapd->conf->dhcp_server.af != AF_INET ||
|
||||
hapd->conf->dhcp_server.u.v4.s_addr == 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: HLP - no DHCPv4 server configured - drop request");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (hapd->conf->own_ip_addr.af != AF_INET ||
|
||||
hapd->conf->own_ip_addr.u.v4.s_addr == 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: HLP - no IPv4 own_ip_addr configured - drop request");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (hapd->dhcp_sock < 0) {
|
||||
int s;
|
||||
|
||||
s = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (s < 0) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"FILS: Failed to open DHCP socket: %s",
|
||||
strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (hapd->conf->dhcp_relay_port) {
|
||||
os_memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr =
|
||||
hapd->conf->own_ip_addr.u.v4.s_addr;
|
||||
addr.sin_port = htons(hapd->conf->dhcp_relay_port);
|
||||
if (bind(s, (struct sockaddr *) &addr, sizeof(addr))) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"FILS: Failed to bind DHCP socket: %s",
|
||||
strerror(errno));
|
||||
close(s);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (eloop_register_sock(s, EVENT_TYPE_READ,
|
||||
fils_dhcp_handler, NULL, hapd)) {
|
||||
close(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
hapd->dhcp_sock = s;
|
||||
}
|
||||
|
||||
dhcp_buf = wpabuf_alloc(len);
|
||||
if (!dhcp_buf)
|
||||
return 0;
|
||||
dhcp_msg = wpabuf_put(dhcp_buf, len);
|
||||
os_memcpy(dhcp_msg, msg, len);
|
||||
dhcp_msg->relay_ip = hapd->conf->own_ip_addr.u.v4.s_addr;
|
||||
os_memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = hapd->conf->dhcp_server.u.v4.s_addr;
|
||||
addr.sin_port = htons(hapd->conf->dhcp_server_port);
|
||||
res = sendto(hapd->dhcp_sock, dhcp_msg, len, 0,
|
||||
(const struct sockaddr *) &addr, sizeof(addr));
|
||||
if (res < 0) {
|
||||
wpa_printf(MSG_ERROR, "FILS: DHCP sendto failed: %s",
|
||||
strerror(errno));
|
||||
wpabuf_free(dhcp_buf);
|
||||
/* Close the socket to try to recover from error */
|
||||
eloop_unregister_read_sock(hapd->dhcp_sock);
|
||||
close(hapd->dhcp_sock);
|
||||
hapd->dhcp_sock = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: HLP relayed DHCP request to server %s:%d (rapid_commit=%d)",
|
||||
inet_ntoa(addr.sin_addr), ntohs(addr.sin_port),
|
||||
rapid_commit);
|
||||
if (hapd->conf->dhcp_rapid_commit_proxy && rapid_commit) {
|
||||
/* Store a copy of the DHCPDISCOVER for rapid commit proxying
|
||||
* purposes if the server does not support the rapid commit
|
||||
* option. */
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: Store DHCPDISCOVER for rapid commit proxy");
|
||||
wpabuf_free(sta->hlp_dhcp_discover);
|
||||
sta->hlp_dhcp_discover = dhcp_buf;
|
||||
} else {
|
||||
wpabuf_free(dhcp_buf);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int fils_process_hlp_udp(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, const u8 *dst,
|
||||
const u8 *pos, size_t len)
|
||||
{
|
||||
const struct iphdr *iph;
|
||||
const struct udphdr *udph;
|
||||
u16 sport, dport, ulen;
|
||||
|
||||
if (len < sizeof(*iph) + sizeof(*udph))
|
||||
return 0;
|
||||
iph = (const struct iphdr *) pos;
|
||||
udph = (const struct udphdr *) (iph + 1);
|
||||
sport = ntohs(udph->uh_sport);
|
||||
dport = ntohs(udph->uh_dport);
|
||||
ulen = ntohs(udph->uh_ulen);
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: HLP request UDP: sport=%u dport=%u ulen=%u sum=0x%x",
|
||||
sport, dport, ulen, ntohs(udph->uh_sum));
|
||||
/* TODO: Check UDP checksum */
|
||||
if (ulen < sizeof(*udph) || ulen > len - sizeof(*iph))
|
||||
return 0;
|
||||
|
||||
if (dport == DHCP_SERVER_PORT && sport == DHCP_CLIENT_PORT) {
|
||||
return fils_process_hlp_dhcp(hapd, sta, (const u8 *) (udph + 1),
|
||||
ulen - sizeof(*udph));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int fils_process_hlp_ip(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, const u8 *dst,
|
||||
const u8 *pos, size_t len)
|
||||
{
|
||||
const struct iphdr *iph;
|
||||
u16 tot_len;
|
||||
|
||||
if (len < sizeof(*iph))
|
||||
return 0;
|
||||
iph = (const struct iphdr *) pos;
|
||||
if (ip_checksum(iph, sizeof(*iph)) != 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: HLP request IPv4 packet had invalid header checksum - dropped");
|
||||
return 0;
|
||||
}
|
||||
tot_len = ntohs(iph->tot_len);
|
||||
if (tot_len > len)
|
||||
return 0;
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: HLP request IPv4: saddr=%08x daddr=%08x protocol=%u",
|
||||
iph->saddr, iph->daddr, iph->protocol);
|
||||
switch (iph->protocol) {
|
||||
case 17:
|
||||
return fils_process_hlp_udp(hapd, sta, dst, pos, len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int fils_process_hlp_req(struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
const u8 *pos, size_t len)
|
||||
{
|
||||
const u8 *pkt, *end;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "FILS: HLP request from " MACSTR " (dst=" MACSTR
|
||||
" src=" MACSTR " len=%u)",
|
||||
MAC2STR(sta->addr), MAC2STR(pos), MAC2STR(pos + ETH_ALEN),
|
||||
(unsigned int) len);
|
||||
if (os_memcmp(sta->addr, pos + ETH_ALEN, ETH_ALEN) != 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FILS: Ignore HLP request with unexpected source address"
|
||||
MACSTR, MAC2STR(pos + ETH_ALEN));
|
||||
return 0;
|
||||
}
|
||||
|
||||
end = pos + len;
|
||||
pkt = pos + 2 * ETH_ALEN;
|
||||
if (end - pkt >= 6 &&
|
||||
os_memcmp(pkt, "\xaa\xaa\x03\x00\x00\x00", 6) == 0)
|
||||
pkt += 6; /* Remove SNAP/LLC header */
|
||||
wpa_hexdump(MSG_MSGDUMP, "FILS: HLP request packet", pkt, end - pkt);
|
||||
|
||||
if (end - pkt < 2)
|
||||
return 0;
|
||||
|
||||
switch (WPA_GET_BE16(pkt)) {
|
||||
case ETH_P_IP:
|
||||
return fils_process_hlp_ip(hapd, sta, pos, pkt + 2,
|
||||
end - pkt - 2);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int fils_process_hlp(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *pos, int left)
|
||||
{
|
||||
const u8 *end = pos + left;
|
||||
u8 *tmp, *tmp_pos;
|
||||
int ret = 0;
|
||||
|
||||
/* Old DHCPDISCOVER is not needed anymore, if it was still pending */
|
||||
wpabuf_free(sta->hlp_dhcp_discover);
|
||||
sta->hlp_dhcp_discover = NULL;
|
||||
sta->fils_dhcp_rapid_commit_proxy = 0;
|
||||
|
||||
/* Check if there are any FILS HLP Container elements */
|
||||
while (end - pos >= 2) {
|
||||
if (2 + pos[1] > end - pos)
|
||||
return 0;
|
||||
if (pos[0] == WLAN_EID_EXTENSION &&
|
||||
pos[1] >= 1 + 2 * ETH_ALEN &&
|
||||
pos[2] == WLAN_EID_EXT_FILS_HLP_CONTAINER)
|
||||
break;
|
||||
pos += 2 + pos[1];
|
||||
}
|
||||
if (end - pos < 2)
|
||||
return 0; /* No FILS HLP Container elements */
|
||||
|
||||
tmp = os_malloc(end - pos);
|
||||
if (!tmp)
|
||||
return 0;
|
||||
|
||||
while (end - pos >= 2) {
|
||||
if (2 + pos[1] > end - pos ||
|
||||
pos[0] != WLAN_EID_EXTENSION ||
|
||||
pos[1] < 1 + 2 * ETH_ALEN ||
|
||||
pos[2] != WLAN_EID_EXT_FILS_HLP_CONTAINER)
|
||||
break;
|
||||
tmp_pos = tmp;
|
||||
os_memcpy(tmp_pos, pos + 3, pos[1] - 1);
|
||||
tmp_pos += pos[1] - 1;
|
||||
pos += 2 + pos[1];
|
||||
|
||||
/* Add possible fragments */
|
||||
while (end - pos >= 2 && pos[0] == WLAN_EID_FRAGMENT &&
|
||||
2 + pos[1] <= end - pos) {
|
||||
os_memcpy(tmp_pos, pos + 2, pos[1]);
|
||||
tmp_pos += pos[1];
|
||||
pos += 2 + pos[1];
|
||||
}
|
||||
|
||||
if (fils_process_hlp_req(hapd, sta, tmp, tmp_pos - tmp) > 0)
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
os_free(tmp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void fils_hlp_deinit(struct hostapd_data *hapd)
|
||||
{
|
||||
if (hapd->dhcp_sock >= 0) {
|
||||
eloop_unregister_read_sock(hapd->dhcp_sock);
|
||||
close(hapd->dhcp_sock);
|
||||
hapd->dhcp_sock = -1;
|
||||
}
|
||||
}
|
27
contrib/wpa/src/ap/fils_hlp.h
Normal file
27
contrib/wpa/src/ap/fils_hlp.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* FILS HLP request processing
|
||||
* Copyright (c) 2017, Qualcomm Atheros, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef FILS_HLP_H
|
||||
#define FILS_HLP_H
|
||||
|
||||
int fils_process_hlp(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *pos, int left);
|
||||
|
||||
#ifdef CONFIG_FILS
|
||||
|
||||
void fils_hlp_deinit(struct hostapd_data *hapd);
|
||||
|
||||
#else /* CONFIG_FILS */
|
||||
|
||||
static inline void fils_hlp_deinit(struct hostapd_data *hapd)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
#endif /* FILS_HLP_H */
|
714
contrib/wpa/src/ap/gas_query_ap.c
Normal file
714
contrib/wpa/src/ap/gas_query_ap.c
Normal file
@ -0,0 +1,714 @@
|
||||
/*
|
||||
* Generic advertisement service (GAS) query (hostapd)
|
||||
* Copyright (c) 2009, Atheros Communications
|
||||
* Copyright (c) 2011-2017, Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2011-2014, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "utils/eloop.h"
|
||||
#include "utils/list.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/gas.h"
|
||||
#include "common/wpa_ctrl.h"
|
||||
#include "hostapd.h"
|
||||
#include "sta_info.h"
|
||||
#include "ap_drv_ops.h"
|
||||
#include "gas_query_ap.h"
|
||||
|
||||
|
||||
/** GAS query timeout in seconds */
|
||||
#define GAS_QUERY_TIMEOUT_PERIOD 2
|
||||
|
||||
/* GAS query wait-time / duration in ms */
|
||||
#define GAS_QUERY_WAIT_TIME_INITIAL 1000
|
||||
#define GAS_QUERY_WAIT_TIME_COMEBACK 150
|
||||
|
||||
/**
|
||||
* struct gas_query_pending - Pending GAS query
|
||||
*/
|
||||
struct gas_query_pending {
|
||||
struct dl_list list;
|
||||
struct gas_query_ap *gas;
|
||||
u8 addr[ETH_ALEN];
|
||||
u8 dialog_token;
|
||||
u8 next_frag_id;
|
||||
unsigned int wait_comeback:1;
|
||||
unsigned int offchannel_tx_started:1;
|
||||
unsigned int retry:1;
|
||||
int freq;
|
||||
u16 status_code;
|
||||
struct wpabuf *req;
|
||||
struct wpabuf *adv_proto;
|
||||
struct wpabuf *resp;
|
||||
struct os_reltime last_oper;
|
||||
void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
|
||||
enum gas_query_ap_result result,
|
||||
const struct wpabuf *adv_proto,
|
||||
const struct wpabuf *resp, u16 status_code);
|
||||
void *ctx;
|
||||
u8 sa[ETH_ALEN];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct gas_query_ap - Internal GAS query data
|
||||
*/
|
||||
struct gas_query_ap {
|
||||
struct hostapd_data *hapd;
|
||||
void *msg_ctx;
|
||||
struct dl_list pending; /* struct gas_query_pending */
|
||||
struct gas_query_pending *current;
|
||||
};
|
||||
|
||||
|
||||
static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx);
|
||||
static void gas_query_timeout(void *eloop_data, void *user_ctx);
|
||||
static void gas_query_rx_comeback_timeout(void *eloop_data, void *user_ctx);
|
||||
static void gas_query_tx_initial_req(struct gas_query_ap *gas,
|
||||
struct gas_query_pending *query);
|
||||
static int gas_query_new_dialog_token(struct gas_query_ap *gas, const u8 *dst);
|
||||
|
||||
|
||||
static int ms_from_time(struct os_reltime *last)
|
||||
{
|
||||
struct os_reltime now, res;
|
||||
|
||||
os_get_reltime(&now);
|
||||
os_reltime_sub(&now, last, &res);
|
||||
return res.sec * 1000 + res.usec / 1000;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gas_query_ap_init - Initialize GAS query component
|
||||
* @hapd: Pointer to hostapd data
|
||||
* Returns: Pointer to GAS query data or %NULL on failure
|
||||
*/
|
||||
struct gas_query_ap * gas_query_ap_init(struct hostapd_data *hapd,
|
||||
void *msg_ctx)
|
||||
{
|
||||
struct gas_query_ap *gas;
|
||||
|
||||
gas = os_zalloc(sizeof(*gas));
|
||||
if (!gas)
|
||||
return NULL;
|
||||
|
||||
gas->hapd = hapd;
|
||||
gas->msg_ctx = msg_ctx;
|
||||
dl_list_init(&gas->pending);
|
||||
|
||||
return gas;
|
||||
}
|
||||
|
||||
|
||||
static const char * gas_result_txt(enum gas_query_ap_result result)
|
||||
{
|
||||
switch (result) {
|
||||
case GAS_QUERY_AP_SUCCESS:
|
||||
return "SUCCESS";
|
||||
case GAS_QUERY_AP_FAILURE:
|
||||
return "FAILURE";
|
||||
case GAS_QUERY_AP_TIMEOUT:
|
||||
return "TIMEOUT";
|
||||
case GAS_QUERY_AP_PEER_ERROR:
|
||||
return "PEER_ERROR";
|
||||
case GAS_QUERY_AP_INTERNAL_ERROR:
|
||||
return "INTERNAL_ERROR";
|
||||
case GAS_QUERY_AP_DELETED_AT_DEINIT:
|
||||
return "DELETED_AT_DEINIT";
|
||||
}
|
||||
|
||||
return "N/A";
|
||||
}
|
||||
|
||||
|
||||
static void gas_query_free(struct gas_query_pending *query, int del_list)
|
||||
{
|
||||
if (del_list)
|
||||
dl_list_del(&query->list);
|
||||
|
||||
wpabuf_free(query->req);
|
||||
wpabuf_free(query->adv_proto);
|
||||
wpabuf_free(query->resp);
|
||||
os_free(query);
|
||||
}
|
||||
|
||||
|
||||
static void gas_query_done(struct gas_query_ap *gas,
|
||||
struct gas_query_pending *query,
|
||||
enum gas_query_ap_result result)
|
||||
{
|
||||
wpa_msg(gas->msg_ctx, MSG_INFO, GAS_QUERY_DONE "addr=" MACSTR
|
||||
" dialog_token=%u freq=%d status_code=%u result=%s",
|
||||
MAC2STR(query->addr), query->dialog_token, query->freq,
|
||||
query->status_code, gas_result_txt(result));
|
||||
if (gas->current == query)
|
||||
gas->current = NULL;
|
||||
eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
|
||||
eloop_cancel_timeout(gas_query_timeout, gas, query);
|
||||
eloop_cancel_timeout(gas_query_rx_comeback_timeout, gas, query);
|
||||
dl_list_del(&query->list);
|
||||
query->cb(query->ctx, query->addr, query->dialog_token, result,
|
||||
query->adv_proto, query->resp, query->status_code);
|
||||
gas_query_free(query, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gas_query_ap_deinit - Deinitialize GAS query component
|
||||
* @gas: GAS query data from gas_query_init()
|
||||
*/
|
||||
void gas_query_ap_deinit(struct gas_query_ap *gas)
|
||||
{
|
||||
struct gas_query_pending *query, *next;
|
||||
|
||||
if (gas == NULL)
|
||||
return;
|
||||
|
||||
dl_list_for_each_safe(query, next, &gas->pending,
|
||||
struct gas_query_pending, list)
|
||||
gas_query_done(gas, query, GAS_QUERY_AP_DELETED_AT_DEINIT);
|
||||
|
||||
os_free(gas);
|
||||
}
|
||||
|
||||
|
||||
static struct gas_query_pending *
|
||||
gas_query_get_pending(struct gas_query_ap *gas, const u8 *addr, u8 dialog_token)
|
||||
{
|
||||
struct gas_query_pending *q;
|
||||
dl_list_for_each(q, &gas->pending, struct gas_query_pending, list) {
|
||||
if (os_memcmp(q->addr, addr, ETH_ALEN) == 0 &&
|
||||
q->dialog_token == dialog_token)
|
||||
return q;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int gas_query_append(struct gas_query_pending *query, const u8 *data,
|
||||
size_t len)
|
||||
{
|
||||
if (wpabuf_resize(&query->resp, len) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: No memory to store the response");
|
||||
return -1;
|
||||
}
|
||||
wpabuf_put_data(query->resp, data, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void gas_query_ap_tx_status(struct gas_query_ap *gas, const u8 *dst,
|
||||
const u8 *data, size_t data_len, int ok)
|
||||
{
|
||||
struct gas_query_pending *query;
|
||||
int dur;
|
||||
|
||||
if (!gas || !gas->current) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Unexpected TX status: dst=" MACSTR
|
||||
" ok=%d - no query in progress", MAC2STR(dst), ok);
|
||||
return;
|
||||
}
|
||||
|
||||
query = gas->current;
|
||||
|
||||
dur = ms_from_time(&query->last_oper);
|
||||
wpa_printf(MSG_DEBUG, "GAS: TX status: dst=" MACSTR
|
||||
" ok=%d query=%p dialog_token=%u dur=%d ms",
|
||||
MAC2STR(dst), ok, query, query->dialog_token, dur);
|
||||
if (os_memcmp(dst, query->addr, ETH_ALEN) != 0) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: TX status for unexpected destination");
|
||||
return;
|
||||
}
|
||||
os_get_reltime(&query->last_oper);
|
||||
|
||||
eloop_cancel_timeout(gas_query_timeout, gas, query);
|
||||
if (!ok) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: No ACK to GAS request");
|
||||
eloop_register_timeout(0, 250000, gas_query_timeout,
|
||||
gas, query);
|
||||
} else {
|
||||
eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0,
|
||||
gas_query_timeout, gas, query);
|
||||
}
|
||||
if (query->wait_comeback && !query->retry) {
|
||||
eloop_cancel_timeout(gas_query_rx_comeback_timeout,
|
||||
gas, query);
|
||||
eloop_register_timeout(
|
||||
0, (GAS_QUERY_WAIT_TIME_COMEBACK + 10) * 1000,
|
||||
gas_query_rx_comeback_timeout, gas, query);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int pmf_in_use(struct hostapd_data *hapd, const u8 *addr)
|
||||
{
|
||||
struct sta_info *sta;
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
return sta && (sta->flags & WLAN_STA_MFP);
|
||||
}
|
||||
|
||||
|
||||
static int gas_query_tx(struct gas_query_ap *gas,
|
||||
struct gas_query_pending *query,
|
||||
struct wpabuf *req, unsigned int wait_time)
|
||||
{
|
||||
int res, prot = pmf_in_use(gas->hapd, query->addr);
|
||||
|
||||
wpa_printf(MSG_DEBUG, "GAS: Send action frame to " MACSTR " len=%u "
|
||||
"freq=%d prot=%d using src addr " MACSTR,
|
||||
MAC2STR(query->addr), (unsigned int) wpabuf_len(req),
|
||||
query->freq, prot, MAC2STR(query->sa));
|
||||
if (prot) {
|
||||
u8 *categ = wpabuf_mhead_u8(req);
|
||||
*categ = WLAN_ACTION_PROTECTED_DUAL;
|
||||
}
|
||||
os_get_reltime(&query->last_oper);
|
||||
res = hostapd_drv_send_action(gas->hapd, query->freq, wait_time,
|
||||
query->addr, wpabuf_head(req),
|
||||
wpabuf_len(req));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static void gas_query_tx_comeback_req(struct gas_query_ap *gas,
|
||||
struct gas_query_pending *query)
|
||||
{
|
||||
struct wpabuf *req;
|
||||
unsigned int wait_time;
|
||||
|
||||
req = gas_build_comeback_req(query->dialog_token);
|
||||
if (req == NULL) {
|
||||
gas_query_done(gas, query, GAS_QUERY_AP_INTERNAL_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
wait_time = (query->retry || !query->offchannel_tx_started) ?
|
||||
GAS_QUERY_WAIT_TIME_INITIAL : GAS_QUERY_WAIT_TIME_COMEBACK;
|
||||
|
||||
if (gas_query_tx(gas, query, req, wait_time) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
|
||||
MACSTR, MAC2STR(query->addr));
|
||||
gas_query_done(gas, query, GAS_QUERY_AP_INTERNAL_ERROR);
|
||||
}
|
||||
|
||||
wpabuf_free(req);
|
||||
}
|
||||
|
||||
|
||||
static void gas_query_rx_comeback_timeout(void *eloop_data, void *user_ctx)
|
||||
{
|
||||
struct gas_query_ap *gas = eloop_data;
|
||||
struct gas_query_pending *query = user_ctx;
|
||||
int dialog_token;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"GAS: No response to comeback request received (retry=%u)",
|
||||
query->retry);
|
||||
if (gas->current != query || query->retry)
|
||||
return;
|
||||
dialog_token = gas_query_new_dialog_token(gas, query->addr);
|
||||
if (dialog_token < 0)
|
||||
return;
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"GAS: Retry GAS query due to comeback response timeout");
|
||||
query->retry = 1;
|
||||
query->dialog_token = dialog_token;
|
||||
*(wpabuf_mhead_u8(query->req) + 2) = dialog_token;
|
||||
query->wait_comeback = 0;
|
||||
query->next_frag_id = 0;
|
||||
wpabuf_free(query->adv_proto);
|
||||
query->adv_proto = NULL;
|
||||
eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
|
||||
eloop_cancel_timeout(gas_query_timeout, gas, query);
|
||||
gas_query_tx_initial_req(gas, query);
|
||||
}
|
||||
|
||||
|
||||
static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx)
|
||||
{
|
||||
struct gas_query_ap *gas = eloop_data;
|
||||
struct gas_query_pending *query = user_ctx;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "GAS: Comeback timeout for request to " MACSTR,
|
||||
MAC2STR(query->addr));
|
||||
gas_query_tx_comeback_req(gas, query);
|
||||
}
|
||||
|
||||
|
||||
static void gas_query_tx_comeback_req_delay(struct gas_query_ap *gas,
|
||||
struct gas_query_pending *query,
|
||||
u16 comeback_delay)
|
||||
{
|
||||
unsigned int secs, usecs;
|
||||
|
||||
secs = (comeback_delay * 1024) / 1000000;
|
||||
usecs = comeback_delay * 1024 - secs * 1000000;
|
||||
wpa_printf(MSG_DEBUG, "GAS: Send comeback request to " MACSTR
|
||||
" in %u secs %u usecs", MAC2STR(query->addr), secs, usecs);
|
||||
eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
|
||||
eloop_register_timeout(secs, usecs, gas_query_tx_comeback_timeout,
|
||||
gas, query);
|
||||
}
|
||||
|
||||
|
||||
static void gas_query_rx_initial(struct gas_query_ap *gas,
|
||||
struct gas_query_pending *query,
|
||||
const u8 *adv_proto, const u8 *resp,
|
||||
size_t len, u16 comeback_delay)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "GAS: Received initial response from "
|
||||
MACSTR " (dialog_token=%u comeback_delay=%u)",
|
||||
MAC2STR(query->addr), query->dialog_token, comeback_delay);
|
||||
|
||||
query->adv_proto = wpabuf_alloc_copy(adv_proto, 2 + adv_proto[1]);
|
||||
if (query->adv_proto == NULL) {
|
||||
gas_query_done(gas, query, GAS_QUERY_AP_INTERNAL_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (comeback_delay) {
|
||||
eloop_cancel_timeout(gas_query_timeout, gas, query);
|
||||
query->wait_comeback = 1;
|
||||
gas_query_tx_comeback_req_delay(gas, query, comeback_delay);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Query was completed without comeback mechanism */
|
||||
if (gas_query_append(query, resp, len) < 0) {
|
||||
gas_query_done(gas, query, GAS_QUERY_AP_INTERNAL_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
gas_query_done(gas, query, GAS_QUERY_AP_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
static void gas_query_rx_comeback(struct gas_query_ap *gas,
|
||||
struct gas_query_pending *query,
|
||||
const u8 *adv_proto, const u8 *resp,
|
||||
size_t len, u8 frag_id, u8 more_frags,
|
||||
u16 comeback_delay)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "GAS: Received comeback response from "
|
||||
MACSTR " (dialog_token=%u frag_id=%u more_frags=%u "
|
||||
"comeback_delay=%u)",
|
||||
MAC2STR(query->addr), query->dialog_token, frag_id,
|
||||
more_frags, comeback_delay);
|
||||
eloop_cancel_timeout(gas_query_rx_comeback_timeout, gas, query);
|
||||
|
||||
if ((size_t) 2 + adv_proto[1] != wpabuf_len(query->adv_proto) ||
|
||||
os_memcmp(adv_proto, wpabuf_head(query->adv_proto),
|
||||
wpabuf_len(query->adv_proto)) != 0) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Advertisement Protocol changed "
|
||||
"between initial and comeback response from "
|
||||
MACSTR, MAC2STR(query->addr));
|
||||
gas_query_done(gas, query, GAS_QUERY_AP_PEER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (comeback_delay) {
|
||||
if (frag_id) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Invalid comeback response "
|
||||
"with non-zero frag_id and comeback_delay "
|
||||
"from " MACSTR, MAC2STR(query->addr));
|
||||
gas_query_done(gas, query, GAS_QUERY_AP_PEER_ERROR);
|
||||
return;
|
||||
}
|
||||
gas_query_tx_comeback_req_delay(gas, query, comeback_delay);
|
||||
return;
|
||||
}
|
||||
|
||||
if (frag_id != query->next_frag_id) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Unexpected frag_id in response "
|
||||
"from " MACSTR, MAC2STR(query->addr));
|
||||
if (frag_id + 1 == query->next_frag_id) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Drop frame as possible "
|
||||
"retry of previous fragment");
|
||||
return;
|
||||
}
|
||||
gas_query_done(gas, query, GAS_QUERY_AP_PEER_ERROR);
|
||||
return;
|
||||
}
|
||||
query->next_frag_id++;
|
||||
|
||||
if (gas_query_append(query, resp, len) < 0) {
|
||||
gas_query_done(gas, query, GAS_QUERY_AP_INTERNAL_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (more_frags) {
|
||||
gas_query_tx_comeback_req(gas, query);
|
||||
return;
|
||||
}
|
||||
|
||||
gas_query_done(gas, query, GAS_QUERY_AP_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gas_query_ap_rx - Indicate reception of a Public Action or Protected Dual
|
||||
* frame
|
||||
* @gas: GAS query data from gas_query_init()
|
||||
* @sa: Source MAC address of the Action frame
|
||||
* @categ: Category of the Action frame
|
||||
* @data: Payload of the Action frame
|
||||
* @len: Length of @data
|
||||
* @freq: Frequency (in MHz) on which the frame was received
|
||||
* Returns: 0 if the Public Action frame was a GAS frame or -1 if not
|
||||
*/
|
||||
int gas_query_ap_rx(struct gas_query_ap *gas, const u8 *sa, u8 categ,
|
||||
const u8 *data, size_t len, int freq)
|
||||
{
|
||||
struct gas_query_pending *query;
|
||||
u8 action, dialog_token, frag_id = 0, more_frags = 0;
|
||||
u16 comeback_delay, resp_len;
|
||||
const u8 *pos, *adv_proto;
|
||||
int prot, pmf;
|
||||
unsigned int left;
|
||||
|
||||
if (!gas || len < 4)
|
||||
return -1;
|
||||
|
||||
pos = data;
|
||||
action = *pos++;
|
||||
dialog_token = *pos++;
|
||||
|
||||
if (action != WLAN_PA_GAS_INITIAL_RESP &&
|
||||
action != WLAN_PA_GAS_COMEBACK_RESP)
|
||||
return -1; /* Not a GAS response */
|
||||
|
||||
prot = categ == WLAN_ACTION_PROTECTED_DUAL;
|
||||
pmf = pmf_in_use(gas->hapd, sa);
|
||||
if (prot && !pmf) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Drop unexpected protected GAS frame when PMF is disabled");
|
||||
return 0;
|
||||
}
|
||||
if (!prot && pmf) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Drop unexpected unprotected GAS frame when PMF is enabled");
|
||||
return 0;
|
||||
}
|
||||
|
||||
query = gas_query_get_pending(gas, sa, dialog_token);
|
||||
if (query == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: No pending query found for " MACSTR
|
||||
" dialog token %u", MAC2STR(sa), dialog_token);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "GAS: Response in %d ms from " MACSTR,
|
||||
ms_from_time(&query->last_oper), MAC2STR(sa));
|
||||
|
||||
if (query->wait_comeback && action == WLAN_PA_GAS_INITIAL_RESP) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Unexpected initial response from "
|
||||
MACSTR " dialog token %u when waiting for comeback "
|
||||
"response", MAC2STR(sa), dialog_token);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!query->wait_comeback && action == WLAN_PA_GAS_COMEBACK_RESP) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Unexpected comeback response from "
|
||||
MACSTR " dialog token %u when waiting for initial "
|
||||
"response", MAC2STR(sa), dialog_token);
|
||||
return 0;
|
||||
}
|
||||
|
||||
query->status_code = WPA_GET_LE16(pos);
|
||||
pos += 2;
|
||||
|
||||
if (query->status_code == WLAN_STATUS_QUERY_RESP_OUTSTANDING &&
|
||||
action == WLAN_PA_GAS_COMEBACK_RESP) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Allow non-zero status for outstanding comeback response");
|
||||
} else if (query->status_code != WLAN_STATUS_SUCCESS) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Query to " MACSTR " dialog token "
|
||||
"%u failed - status code %u",
|
||||
MAC2STR(sa), dialog_token, query->status_code);
|
||||
gas_query_done(gas, query, GAS_QUERY_AP_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (action == WLAN_PA_GAS_COMEBACK_RESP) {
|
||||
if (pos + 1 > data + len)
|
||||
return 0;
|
||||
frag_id = *pos & 0x7f;
|
||||
more_frags = (*pos & 0x80) >> 7;
|
||||
pos++;
|
||||
}
|
||||
|
||||
/* Comeback Delay */
|
||||
if (pos + 2 > data + len)
|
||||
return 0;
|
||||
comeback_delay = WPA_GET_LE16(pos);
|
||||
pos += 2;
|
||||
|
||||
/* Advertisement Protocol element */
|
||||
if (pos + 2 > data + len || pos + 2 + pos[1] > data + len) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: No room for Advertisement "
|
||||
"Protocol element in the response from " MACSTR,
|
||||
MAC2STR(sa));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*pos != WLAN_EID_ADV_PROTO) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Unexpected Advertisement "
|
||||
"Protocol element ID %u in response from " MACSTR,
|
||||
*pos, MAC2STR(sa));
|
||||
return 0;
|
||||
}
|
||||
|
||||
adv_proto = pos;
|
||||
pos += 2 + pos[1];
|
||||
|
||||
/* Query Response Length */
|
||||
if (pos + 2 > data + len) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: No room for GAS Response Length");
|
||||
return 0;
|
||||
}
|
||||
resp_len = WPA_GET_LE16(pos);
|
||||
pos += 2;
|
||||
|
||||
left = data + len - pos;
|
||||
if (resp_len > left) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Truncated Query Response in "
|
||||
"response from " MACSTR, MAC2STR(sa));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (resp_len < left) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Ignore %u octets of extra data "
|
||||
"after Query Response from " MACSTR,
|
||||
left - resp_len, MAC2STR(sa));
|
||||
}
|
||||
|
||||
if (action == WLAN_PA_GAS_COMEBACK_RESP)
|
||||
gas_query_rx_comeback(gas, query, adv_proto, pos, resp_len,
|
||||
frag_id, more_frags, comeback_delay);
|
||||
else
|
||||
gas_query_rx_initial(gas, query, adv_proto, pos, resp_len,
|
||||
comeback_delay);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void gas_query_timeout(void *eloop_data, void *user_ctx)
|
||||
{
|
||||
struct gas_query_ap *gas = eloop_data;
|
||||
struct gas_query_pending *query = user_ctx;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "GAS: No response received for query to " MACSTR
|
||||
" dialog token %u",
|
||||
MAC2STR(query->addr), query->dialog_token);
|
||||
gas_query_done(gas, query, GAS_QUERY_AP_TIMEOUT);
|
||||
}
|
||||
|
||||
|
||||
static int gas_query_dialog_token_available(struct gas_query_ap *gas,
|
||||
const u8 *dst, u8 dialog_token)
|
||||
{
|
||||
struct gas_query_pending *q;
|
||||
dl_list_for_each(q, &gas->pending, struct gas_query_pending, list) {
|
||||
if (os_memcmp(dst, q->addr, ETH_ALEN) == 0 &&
|
||||
dialog_token == q->dialog_token)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void gas_query_tx_initial_req(struct gas_query_ap *gas,
|
||||
struct gas_query_pending *query)
|
||||
{
|
||||
if (gas_query_tx(gas, query, query->req,
|
||||
GAS_QUERY_WAIT_TIME_INITIAL) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
|
||||
MACSTR, MAC2STR(query->addr));
|
||||
gas_query_done(gas, query, GAS_QUERY_AP_INTERNAL_ERROR);
|
||||
return;
|
||||
}
|
||||
gas->current = query;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "GAS: Starting query timeout for dialog token %u",
|
||||
query->dialog_token);
|
||||
eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0,
|
||||
gas_query_timeout, gas, query);
|
||||
}
|
||||
|
||||
|
||||
static int gas_query_new_dialog_token(struct gas_query_ap *gas, const u8 *dst)
|
||||
{
|
||||
static int next_start = 0;
|
||||
int dialog_token;
|
||||
|
||||
for (dialog_token = 0; dialog_token < 256; dialog_token++) {
|
||||
if (gas_query_dialog_token_available(
|
||||
gas, dst, (next_start + dialog_token) % 256))
|
||||
break;
|
||||
}
|
||||
if (dialog_token == 256)
|
||||
return -1; /* Too many pending queries */
|
||||
dialog_token = (next_start + dialog_token) % 256;
|
||||
next_start = (dialog_token + 1) % 256;
|
||||
return dialog_token;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gas_query_ap_req - Request a GAS query
|
||||
* @gas: GAS query data from gas_query_init()
|
||||
* @dst: Destination MAC address for the query
|
||||
* @freq: Frequency (in MHz) for the channel on which to send the query
|
||||
* @req: GAS query payload (to be freed by gas_query module in case of success
|
||||
* return)
|
||||
* @cb: Callback function for reporting GAS query result and response
|
||||
* @ctx: Context pointer to use with the @cb call
|
||||
* Returns: dialog token (>= 0) on success or -1 on failure
|
||||
*/
|
||||
int gas_query_ap_req(struct gas_query_ap *gas, const u8 *dst, int freq,
|
||||
struct wpabuf *req,
|
||||
void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
|
||||
enum gas_query_ap_result result,
|
||||
const struct wpabuf *adv_proto,
|
||||
const struct wpabuf *resp, u16 status_code),
|
||||
void *ctx)
|
||||
{
|
||||
struct gas_query_pending *query;
|
||||
int dialog_token;
|
||||
|
||||
if (!gas || wpabuf_len(req) < 3)
|
||||
return -1;
|
||||
|
||||
dialog_token = gas_query_new_dialog_token(gas, dst);
|
||||
if (dialog_token < 0)
|
||||
return -1;
|
||||
|
||||
query = os_zalloc(sizeof(*query));
|
||||
if (query == NULL)
|
||||
return -1;
|
||||
|
||||
query->gas = gas;
|
||||
os_memcpy(query->addr, dst, ETH_ALEN);
|
||||
query->dialog_token = dialog_token;
|
||||
query->freq = freq;
|
||||
query->cb = cb;
|
||||
query->ctx = ctx;
|
||||
query->req = req;
|
||||
dl_list_add(&gas->pending, &query->list);
|
||||
|
||||
*(wpabuf_mhead_u8(req) + 2) = dialog_token;
|
||||
|
||||
wpa_msg(gas->msg_ctx, MSG_INFO, GAS_QUERY_START "addr=" MACSTR
|
||||
" dialog_token=%u freq=%d",
|
||||
MAC2STR(query->addr), query->dialog_token, query->freq);
|
||||
|
||||
gas_query_tx_initial_req(gas, query);
|
||||
|
||||
return dialog_token;
|
||||
}
|
43
contrib/wpa/src/ap/gas_query_ap.h
Normal file
43
contrib/wpa/src/ap/gas_query_ap.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Generic advertisement service (GAS) query
|
||||
* Copyright (c) 2009, Atheros Communications
|
||||
* Copyright (c) 2011-2017, Qualcomm Atheros
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef GAS_QUERY_AP_H
|
||||
#define GAS_QUERY_AP_H
|
||||
|
||||
struct gas_query_ap;
|
||||
|
||||
struct gas_query_ap * gas_query_ap_init(struct hostapd_data *hapd,
|
||||
void *msg_ctx);
|
||||
void gas_query_ap_deinit(struct gas_query_ap *gas);
|
||||
int gas_query_ap_rx(struct gas_query_ap *gas, const u8 *sa, u8 categ,
|
||||
const u8 *data, size_t len, int freq);
|
||||
|
||||
/**
|
||||
* enum gas_query_ap_result - GAS query result
|
||||
*/
|
||||
enum gas_query_ap_result {
|
||||
GAS_QUERY_AP_SUCCESS,
|
||||
GAS_QUERY_AP_FAILURE,
|
||||
GAS_QUERY_AP_TIMEOUT,
|
||||
GAS_QUERY_AP_PEER_ERROR,
|
||||
GAS_QUERY_AP_INTERNAL_ERROR,
|
||||
GAS_QUERY_AP_DELETED_AT_DEINIT
|
||||
};
|
||||
|
||||
int gas_query_ap_req(struct gas_query_ap *gas, const u8 *dst, int freq,
|
||||
struct wpabuf *req,
|
||||
void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
|
||||
enum gas_query_ap_result result,
|
||||
const struct wpabuf *adv_proto,
|
||||
const struct wpabuf *resp, u16 status_code),
|
||||
void *ctx);
|
||||
void gas_query_ap_tx_status(struct gas_query_ap *gas, const u8 *dst,
|
||||
const u8 *data, size_t data_len, int ok);
|
||||
|
||||
#endif /* GAS_QUERY_AP_H */
|
@ -11,14 +11,31 @@
|
||||
#include "common.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/gas.h"
|
||||
#include "common/wpa_ctrl.h"
|
||||
#include "utils/eloop.h"
|
||||
#include "hostapd.h"
|
||||
#include "ap_config.h"
|
||||
#include "ap_drv_ops.h"
|
||||
#include "dpp_hostapd.h"
|
||||
#include "sta_info.h"
|
||||
#include "gas_serv.h"
|
||||
|
||||
|
||||
#ifdef CONFIG_DPP
|
||||
static void gas_serv_write_dpp_adv_proto(struct wpabuf *buf)
|
||||
{
|
||||
wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
|
||||
wpabuf_put_u8(buf, 8); /* Length */
|
||||
wpabuf_put_u8(buf, 0x7f);
|
||||
wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
|
||||
wpabuf_put_u8(buf, 5);
|
||||
wpabuf_put_be24(buf, OUI_WFA);
|
||||
wpabuf_put_u8(buf, DPP_OUI_TYPE);
|
||||
wpabuf_put_u8(buf, 0x01);
|
||||
}
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
|
||||
static void convert_to_protected_dual(struct wpabuf *msg)
|
||||
{
|
||||
u8 *categ = wpabuf_mhead_u8(msg);
|
||||
@ -50,9 +67,12 @@ gas_dialog_create(struct hostapd_data *hapd, const u8 *addr, u8 dialog_token)
|
||||
sta->flags |= WLAN_STA_GAS;
|
||||
/*
|
||||
* The default inactivity is 300 seconds. We don't need
|
||||
* it to be that long.
|
||||
* it to be that long. Use five second timeout and increase this
|
||||
* with the comeback_delay for testing cases.
|
||||
*/
|
||||
ap_sta_session_timeout(hapd, sta, 5);
|
||||
ap_sta_session_timeout(hapd, sta,
|
||||
hapd->conf->gas_comeback_delay / 1024 +
|
||||
5);
|
||||
} else {
|
||||
ap_sta_replenish_timeout(hapd, sta, 5);
|
||||
}
|
||||
@ -161,8 +181,12 @@ static void anqp_add_hs_capab_list(struct hostapd_data *hapd,
|
||||
wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS);
|
||||
if (hapd->conf->hs20_osu_providers_count)
|
||||
wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_LIST);
|
||||
if (hapd->conf->hs20_osu_providers_nai_count)
|
||||
wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_NAI_LIST);
|
||||
if (hapd->conf->hs20_icons_count)
|
||||
wpabuf_put_u8(buf, HS20_STYPE_ICON_REQUEST);
|
||||
if (hapd->conf->hs20_operator_icon_count)
|
||||
wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_ICON_METADATA);
|
||||
gas_anqp_set_element_len(buf, len);
|
||||
}
|
||||
#endif /* CONFIG_HS20 */
|
||||
@ -255,20 +279,29 @@ static void anqp_add_capab_list(struct hostapd_data *hapd,
|
||||
wpabuf_put_le16(buf, ANQP_DOMAIN_NAME);
|
||||
if (get_anqp_elem(hapd, ANQP_EMERGENCY_ALERT_URI))
|
||||
wpabuf_put_le16(buf, ANQP_EMERGENCY_ALERT_URI);
|
||||
if (get_anqp_elem(hapd, ANQP_TDLS_CAPABILITY))
|
||||
wpabuf_put_le16(buf, ANQP_TDLS_CAPABILITY);
|
||||
if (get_anqp_elem(hapd, ANQP_EMERGENCY_NAI))
|
||||
wpabuf_put_le16(buf, ANQP_EMERGENCY_NAI);
|
||||
if (get_anqp_elem(hapd, ANQP_NEIGHBOR_REPORT))
|
||||
wpabuf_put_le16(buf, ANQP_NEIGHBOR_REPORT);
|
||||
for (id = 273; id < 277; id++) {
|
||||
if (get_anqp_elem(hapd, id))
|
||||
wpabuf_put_le16(buf, id);
|
||||
}
|
||||
if (get_anqp_elem(hapd, ANQP_VENUE_URL))
|
||||
#ifdef CONFIG_FILS
|
||||
if (!dl_list_empty(&hapd->conf->fils_realms) ||
|
||||
get_anqp_elem(hapd, ANQP_FILS_REALM_INFO))
|
||||
wpabuf_put_le16(buf, ANQP_FILS_REALM_INFO);
|
||||
#endif /* CONFIG_FILS */
|
||||
if (get_anqp_elem(hapd, ANQP_CAG))
|
||||
wpabuf_put_le16(buf, ANQP_CAG);
|
||||
if (hapd->conf->venue_url || get_anqp_elem(hapd, ANQP_VENUE_URL))
|
||||
wpabuf_put_le16(buf, ANQP_VENUE_URL);
|
||||
if (get_anqp_elem(hapd, ANQP_ADVICE_OF_CHARGE))
|
||||
wpabuf_put_le16(buf, ANQP_ADVICE_OF_CHARGE);
|
||||
if (get_anqp_elem(hapd, ANQP_LOCAL_CONTENT))
|
||||
wpabuf_put_le16(buf, ANQP_LOCAL_CONTENT);
|
||||
for (id = 280; id < 300; id++) {
|
||||
if (get_anqp_elem(hapd, id))
|
||||
wpabuf_put_le16(buf, id);
|
||||
}
|
||||
#ifdef CONFIG_HS20
|
||||
anqp_add_hs_capab_list(hapd, buf);
|
||||
#endif /* CONFIG_HS20 */
|
||||
@ -299,6 +332,29 @@ static void anqp_add_venue_name(struct hostapd_data *hapd, struct wpabuf *buf)
|
||||
}
|
||||
|
||||
|
||||
static void anqp_add_venue_url(struct hostapd_data *hapd, struct wpabuf *buf)
|
||||
{
|
||||
if (anqp_add_override(hapd, buf, ANQP_VENUE_URL))
|
||||
return;
|
||||
|
||||
if (hapd->conf->venue_url) {
|
||||
u8 *len;
|
||||
unsigned int i;
|
||||
|
||||
len = gas_anqp_add_element(buf, ANQP_VENUE_URL);
|
||||
for (i = 0; i < hapd->conf->venue_url_count; i++) {
|
||||
struct hostapd_venue_url *url;
|
||||
|
||||
url = &hapd->conf->venue_url[i];
|
||||
wpabuf_put_u8(buf, 1 + url->url_len);
|
||||
wpabuf_put_u8(buf, url->venue_number);
|
||||
wpabuf_put_data(buf, url->url, url->url_len);
|
||||
}
|
||||
gas_anqp_set_element_len(buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void anqp_add_network_auth_type(struct hostapd_data *hapd,
|
||||
struct wpabuf *buf)
|
||||
{
|
||||
@ -548,6 +604,36 @@ static void anqp_add_domain_name(struct hostapd_data *hapd, struct wpabuf *buf)
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_FILS
|
||||
static void anqp_add_fils_realm_info(struct hostapd_data *hapd,
|
||||
struct wpabuf *buf)
|
||||
{
|
||||
size_t count;
|
||||
|
||||
if (anqp_add_override(hapd, buf, ANQP_FILS_REALM_INFO))
|
||||
return;
|
||||
|
||||
count = dl_list_len(&hapd->conf->fils_realms);
|
||||
if (count > 10000)
|
||||
count = 10000;
|
||||
if (count) {
|
||||
struct fils_realm *realm;
|
||||
|
||||
wpabuf_put_le16(buf, ANQP_FILS_REALM_INFO);
|
||||
wpabuf_put_le16(buf, 2 * count);
|
||||
|
||||
dl_list_for_each(realm, &hapd->conf->fils_realms,
|
||||
struct fils_realm, list) {
|
||||
if (count == 0)
|
||||
break;
|
||||
wpabuf_put_data(buf, realm->hash, 2);
|
||||
count--;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
|
||||
#ifdef CONFIG_HS20
|
||||
|
||||
static void anqp_add_operator_friendly_name(struct hostapd_data *hapd,
|
||||
@ -621,6 +707,29 @@ static void anqp_add_operating_class(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
static void anqp_add_icon(struct wpabuf *buf, struct hostapd_bss_config *bss,
|
||||
const char *name)
|
||||
{
|
||||
size_t j;
|
||||
struct hs20_icon *icon = NULL;
|
||||
|
||||
for (j = 0; j < bss->hs20_icons_count && !icon; j++) {
|
||||
if (os_strcmp(name, bss->hs20_icons[j].name) == 0)
|
||||
icon = &bss->hs20_icons[j];
|
||||
}
|
||||
if (!icon)
|
||||
return; /* icon info not found */
|
||||
|
||||
wpabuf_put_le16(buf, icon->width);
|
||||
wpabuf_put_le16(buf, icon->height);
|
||||
wpabuf_put_data(buf, icon->language, 3);
|
||||
wpabuf_put_u8(buf, os_strlen(icon->type));
|
||||
wpabuf_put_str(buf, icon->type);
|
||||
wpabuf_put_u8(buf, os_strlen(icon->name));
|
||||
wpabuf_put_str(buf, icon->name);
|
||||
}
|
||||
|
||||
|
||||
static void anqp_add_osu_provider(struct wpabuf *buf,
|
||||
struct hostapd_bss_config *bss,
|
||||
struct hs20_osu_provider *p)
|
||||
@ -649,32 +758,14 @@ static void anqp_add_osu_provider(struct wpabuf *buf,
|
||||
|
||||
/* OSU Method List */
|
||||
count = wpabuf_put(buf, 1);
|
||||
for (i = 0; p->method_list[i] >= 0; i++)
|
||||
for (i = 0; p->method_list && p->method_list[i] >= 0; i++)
|
||||
wpabuf_put_u8(buf, p->method_list[i]);
|
||||
*count = i;
|
||||
|
||||
/* Icons Available */
|
||||
len2 = wpabuf_put(buf, 2);
|
||||
for (i = 0; i < p->icons_count; i++) {
|
||||
size_t j;
|
||||
struct hs20_icon *icon = NULL;
|
||||
|
||||
for (j = 0; j < bss->hs20_icons_count && !icon; j++) {
|
||||
if (os_strcmp(p->icons[i], bss->hs20_icons[j].name) ==
|
||||
0)
|
||||
icon = &bss->hs20_icons[j];
|
||||
}
|
||||
if (!icon)
|
||||
continue; /* icon info not found */
|
||||
|
||||
wpabuf_put_le16(buf, icon->width);
|
||||
wpabuf_put_le16(buf, icon->height);
|
||||
wpabuf_put_data(buf, icon->language, 3);
|
||||
wpabuf_put_u8(buf, os_strlen(icon->type));
|
||||
wpabuf_put_str(buf, icon->type);
|
||||
wpabuf_put_u8(buf, os_strlen(icon->name));
|
||||
wpabuf_put_str(buf, icon->name);
|
||||
}
|
||||
for (i = 0; i < p->icons_count; i++)
|
||||
anqp_add_icon(buf, bss, p->icons[i]);
|
||||
WPA_PUT_LE16(len2, (u8 *) wpabuf_put(buf, 0) - len2 - 2);
|
||||
|
||||
/* OSU_NAI */
|
||||
@ -728,6 +819,40 @@ static void anqp_add_osu_providers_list(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
static void anqp_add_osu_provider_nai(struct wpabuf *buf,
|
||||
struct hs20_osu_provider *p)
|
||||
{
|
||||
/* OSU_NAI for shared BSS (Single SSID) */
|
||||
if (p->osu_nai2) {
|
||||
wpabuf_put_u8(buf, os_strlen(p->osu_nai2));
|
||||
wpabuf_put_str(buf, p->osu_nai2);
|
||||
} else {
|
||||
wpabuf_put_u8(buf, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void anqp_add_osu_providers_nai_list(struct hostapd_data *hapd,
|
||||
struct wpabuf *buf)
|
||||
{
|
||||
if (hapd->conf->hs20_osu_providers_nai_count) {
|
||||
size_t i;
|
||||
u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
|
||||
wpabuf_put_be24(buf, OUI_WFA);
|
||||
wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
|
||||
wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_NAI_LIST);
|
||||
wpabuf_put_u8(buf, 0); /* Reserved */
|
||||
|
||||
for (i = 0; i < hapd->conf->hs20_osu_providers_count; i++) {
|
||||
anqp_add_osu_provider_nai(
|
||||
buf, &hapd->conf->hs20_osu_providers[i]);
|
||||
}
|
||||
|
||||
gas_anqp_set_element_len(buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void anqp_add_icon_binary_file(struct hostapd_data *hapd,
|
||||
struct wpabuf *buf,
|
||||
const u8 *name, size_t name_len)
|
||||
@ -783,9 +908,49 @@ static void anqp_add_icon_binary_file(struct hostapd_data *hapd,
|
||||
gas_anqp_set_element_len(buf, len);
|
||||
}
|
||||
|
||||
|
||||
static void anqp_add_operator_icon_metadata(struct hostapd_data *hapd,
|
||||
struct wpabuf *buf)
|
||||
{
|
||||
struct hostapd_bss_config *bss = hapd->conf;
|
||||
size_t i;
|
||||
u8 *len;
|
||||
|
||||
if (!bss->hs20_operator_icon_count)
|
||||
return;
|
||||
|
||||
len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
|
||||
|
||||
wpabuf_put_be24(buf, OUI_WFA);
|
||||
wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
|
||||
wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_ICON_METADATA);
|
||||
wpabuf_put_u8(buf, 0); /* Reserved */
|
||||
|
||||
for (i = 0; i < bss->hs20_operator_icon_count; i++)
|
||||
anqp_add_icon(buf, bss, bss->hs20_operator_icon[i]);
|
||||
|
||||
gas_anqp_set_element_len(buf, len);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
static void anqp_add_mbo_cell_data_conn_pref(struct hostapd_data *hapd,
|
||||
struct wpabuf *buf)
|
||||
{
|
||||
if (hapd->conf->mbo_cell_data_conn_pref >= 0) {
|
||||
u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
|
||||
wpabuf_put_be24(buf, OUI_WFA);
|
||||
wpabuf_put_u8(buf, MBO_ANQP_OUI_TYPE);
|
||||
wpabuf_put_u8(buf, MBO_ANQP_SUBTYPE_CELL_CONN_PREF);
|
||||
wpabuf_put_u8(buf, hapd->conf->mbo_cell_data_conn_pref);
|
||||
gas_anqp_set_element_len(buf, len);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_MBO */
|
||||
|
||||
|
||||
static size_t anqp_get_required_len(struct hostapd_data *hapd,
|
||||
const u16 *infoid,
|
||||
unsigned int num_infoid)
|
||||
@ -821,6 +986,10 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
|
||||
len += 1000;
|
||||
if (request & ANQP_REQ_ICON_REQUEST)
|
||||
len += 65536;
|
||||
#ifdef CONFIG_FILS
|
||||
if (request & ANQP_FILS_REALM_INFO)
|
||||
len += 2 * dl_list_len(&hapd->conf->fils_realms);
|
||||
#endif /* CONFIG_FILS */
|
||||
len += anqp_get_required_len(hapd, extra_req, num_extra_req);
|
||||
|
||||
buf = wpabuf_alloc(len);
|
||||
@ -860,8 +1029,19 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
|
||||
if (request & ANQP_REQ_EMERGENCY_NAI)
|
||||
anqp_add_elem(hapd, buf, ANQP_EMERGENCY_NAI);
|
||||
|
||||
for (i = 0; i < num_extra_req; i++)
|
||||
for (i = 0; i < num_extra_req; i++) {
|
||||
#ifdef CONFIG_FILS
|
||||
if (extra_req[i] == ANQP_FILS_REALM_INFO) {
|
||||
anqp_add_fils_realm_info(hapd, buf);
|
||||
continue;
|
||||
}
|
||||
#endif /* CONFIG_FILS */
|
||||
if (extra_req[i] == ANQP_VENUE_URL) {
|
||||
anqp_add_venue_url(hapd, buf);
|
||||
continue;
|
||||
}
|
||||
anqp_add_elem(hapd, buf, extra_req[i]);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HS20
|
||||
if (request & ANQP_REQ_HS_CAPABILITY_LIST)
|
||||
@ -878,8 +1058,17 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
|
||||
anqp_add_osu_providers_list(hapd, buf);
|
||||
if (request & ANQP_REQ_ICON_REQUEST)
|
||||
anqp_add_icon_binary_file(hapd, buf, icon_name, icon_name_len);
|
||||
if (request & ANQP_REQ_OPERATOR_ICON_METADATA)
|
||||
anqp_add_operator_icon_metadata(hapd, buf);
|
||||
if (request & ANQP_REQ_OSU_PROVIDERS_NAI_LIST)
|
||||
anqp_add_osu_providers_nai_list(hapd, buf);
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
if (request & ANQP_REQ_MBO_CELL_DATA_CONN_PREF)
|
||||
anqp_add_mbo_cell_data_conn_pref(hapd, buf);
|
||||
#endif /* CONFIG_MBO */
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
@ -984,7 +1173,17 @@ static void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id,
|
||||
get_anqp_elem(hapd, info_id) != NULL, qi);
|
||||
break;
|
||||
default:
|
||||
if (!get_anqp_elem(hapd, info_id)) {
|
||||
#ifdef CONFIG_FILS
|
||||
if (info_id == ANQP_FILS_REALM_INFO &&
|
||||
!dl_list_empty(&hapd->conf->fils_realms)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"ANQP: FILS Realm Information (local)");
|
||||
} else
|
||||
#endif /* CONFIG_FILS */
|
||||
if (info_id == ANQP_VENUE_URL && hapd->conf->venue_url) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"ANQP: Venue URL (local)");
|
||||
} else if (!get_anqp_elem(hapd, info_id)) {
|
||||
wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u",
|
||||
info_id);
|
||||
break;
|
||||
@ -1050,6 +1249,16 @@ static void rx_anqp_hs_query_list(struct hostapd_data *hapd, u8 subtype,
|
||||
set_anqp_req(ANQP_REQ_OSU_PROVIDERS_LIST, "OSU Providers list",
|
||||
hapd->conf->hs20_osu_providers_count, qi);
|
||||
break;
|
||||
case HS20_STYPE_OPERATOR_ICON_METADATA:
|
||||
set_anqp_req(ANQP_REQ_OPERATOR_ICON_METADATA,
|
||||
"Operator Icon Metadata",
|
||||
hapd->conf->hs20_operator_icon_count, qi);
|
||||
break;
|
||||
case HS20_STYPE_OSU_PROVIDERS_NAI_LIST:
|
||||
set_anqp_req(ANQP_REQ_OSU_PROVIDERS_NAI_LIST,
|
||||
"OSU Providers NAI List",
|
||||
hapd->conf->hs20_osu_providers_nai_count, qi);
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 subtype %u",
|
||||
subtype);
|
||||
@ -1092,49 +1301,12 @@ static void rx_anqp_hs_icon_request(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
|
||||
const u8 *pos, const u8 *end,
|
||||
struct anqp_query_info *qi)
|
||||
static void rx_anqp_vendor_specific_hs20(struct hostapd_data *hapd,
|
||||
const u8 *pos, const u8 *end,
|
||||
struct anqp_query_info *qi)
|
||||
{
|
||||
u32 oui;
|
||||
u8 subtype;
|
||||
|
||||
if (end - pos < 4) {
|
||||
wpa_printf(MSG_DEBUG, "ANQP: Too short vendor specific ANQP "
|
||||
"Query element");
|
||||
return;
|
||||
}
|
||||
|
||||
oui = WPA_GET_BE24(pos);
|
||||
pos += 3;
|
||||
if (oui != OUI_WFA) {
|
||||
wpa_printf(MSG_DEBUG, "ANQP: Unsupported vendor OUI %06x",
|
||||
oui);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
if (*pos == P2P_OUI_TYPE) {
|
||||
/*
|
||||
* This is for P2P SD and will be taken care of by the P2P
|
||||
* implementation. This query needs to be ignored in the generic
|
||||
* GAS server to avoid duplicated response.
|
||||
*/
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"ANQP: Ignore WFA vendor type %u (P2P SD) in generic GAS server",
|
||||
*pos);
|
||||
qi->p2p_sd = 1;
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_P2P */
|
||||
|
||||
if (*pos != HS20_ANQP_OUI_TYPE) {
|
||||
wpa_printf(MSG_DEBUG, "ANQP: Unsupported WFA vendor type %u",
|
||||
*pos);
|
||||
return;
|
||||
}
|
||||
pos++;
|
||||
|
||||
if (end - pos <= 1)
|
||||
return;
|
||||
|
||||
@ -1164,6 +1336,115 @@ static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
static void rx_anqp_vendor_specific_p2p(struct hostapd_data *hapd,
|
||||
struct anqp_query_info *qi)
|
||||
{
|
||||
/*
|
||||
* This is for P2P SD and will be taken care of by the P2P
|
||||
* implementation. This query needs to be ignored in the generic
|
||||
* GAS server to avoid duplicated response.
|
||||
*/
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"ANQP: Ignore WFA vendor type %u (P2P SD) in generic GAS server",
|
||||
P2P_OUI_TYPE);
|
||||
qi->p2p_sd = 1;
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_P2P */
|
||||
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
|
||||
static void rx_anqp_mbo_query_list(struct hostapd_data *hapd, u8 subtype,
|
||||
struct anqp_query_info *qi)
|
||||
{
|
||||
switch (subtype) {
|
||||
case MBO_ANQP_SUBTYPE_CELL_CONN_PREF:
|
||||
set_anqp_req(ANQP_REQ_MBO_CELL_DATA_CONN_PREF,
|
||||
"Cellular Data Connection Preference",
|
||||
hapd->conf->mbo_cell_data_conn_pref >= 0, qi);
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "ANQP: Unsupported MBO subtype %u",
|
||||
subtype);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void rx_anqp_vendor_specific_mbo(struct hostapd_data *hapd,
|
||||
const u8 *pos, const u8 *end,
|
||||
struct anqp_query_info *qi)
|
||||
{
|
||||
u8 subtype;
|
||||
|
||||
if (end - pos < 1)
|
||||
return;
|
||||
|
||||
subtype = *pos++;
|
||||
switch (subtype) {
|
||||
case MBO_ANQP_SUBTYPE_QUERY_LIST:
|
||||
wpa_printf(MSG_DEBUG, "ANQP: MBO Query List");
|
||||
while (pos < end) {
|
||||
rx_anqp_mbo_query_list(hapd, *pos, qi);
|
||||
pos++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "ANQP: Unsupported MBO query subtype %u",
|
||||
subtype);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MBO */
|
||||
|
||||
|
||||
static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
|
||||
const u8 *pos, const u8 *end,
|
||||
struct anqp_query_info *qi)
|
||||
{
|
||||
u32 oui;
|
||||
|
||||
if (end - pos < 4) {
|
||||
wpa_printf(MSG_DEBUG, "ANQP: Too short vendor specific ANQP "
|
||||
"Query element");
|
||||
return;
|
||||
}
|
||||
|
||||
oui = WPA_GET_BE24(pos);
|
||||
pos += 3;
|
||||
if (oui != OUI_WFA) {
|
||||
wpa_printf(MSG_DEBUG, "ANQP: Unsupported vendor OUI %06x",
|
||||
oui);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (*pos) {
|
||||
#ifdef CONFIG_P2P
|
||||
case P2P_OUI_TYPE:
|
||||
rx_anqp_vendor_specific_p2p(hapd, qi);
|
||||
break;
|
||||
#endif /* CONFIG_P2P */
|
||||
#ifdef CONFIG_HS20
|
||||
case HS20_ANQP_OUI_TYPE:
|
||||
rx_anqp_vendor_specific_hs20(hapd, pos + 1, end, qi);
|
||||
break;
|
||||
#endif /* CONFIG_HS20 */
|
||||
#ifdef CONFIG_MBO
|
||||
case MBO_ANQP_OUI_TYPE:
|
||||
rx_anqp_vendor_specific_mbo(hapd, pos + 1, end, qi);
|
||||
break;
|
||||
#endif /* CONFIG_MBO */
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "ANQP: Unsupported WFA vendor type %u",
|
||||
*pos);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void gas_serv_req_local_processing(struct hostapd_data *hapd,
|
||||
const u8 *sa, u8 dialog_token,
|
||||
struct anqp_query_info *qi, int prot,
|
||||
@ -1189,7 +1470,7 @@ static void gas_serv_req_local_processing(struct hostapd_data *hapd,
|
||||
}
|
||||
#endif /* CONFIG_P2P */
|
||||
|
||||
if (wpabuf_len(buf) > hapd->gas_frag_limit ||
|
||||
if (wpabuf_len(buf) > hapd->conf->gas_frag_limit ||
|
||||
hapd->conf->gas_comeback_delay) {
|
||||
struct gas_dialog_info *di;
|
||||
u16 comeback_delay = 1;
|
||||
@ -1240,6 +1521,72 @@ 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)
|
||||
{
|
||||
struct wpabuf *tx_buf;
|
||||
|
||||
if (wpabuf_len(buf) > hapd->conf->gas_frag_limit ||
|
||||
hapd->conf->gas_comeback_delay) {
|
||||
struct gas_dialog_info *di;
|
||||
u16 comeback_delay = 1;
|
||||
|
||||
if (hapd->conf->gas_comeback_delay) {
|
||||
/* Testing - allow overriding of the delay value */
|
||||
comeback_delay = hapd->conf->gas_comeback_delay;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DPP: Too long response to fit in initial response - use GAS comeback");
|
||||
di = gas_dialog_create(hapd, sa, dialog_token);
|
||||
if (!di) {
|
||||
wpa_printf(MSG_INFO, "DPP: Could not create dialog for "
|
||||
MACSTR " (dialog token %u)",
|
||||
MAC2STR(sa), dialog_token);
|
||||
wpabuf_free(buf);
|
||||
tx_buf = gas_build_initial_resp(
|
||||
dialog_token, WLAN_STATUS_UNSPECIFIED_FAILURE,
|
||||
0, 10);
|
||||
if (tx_buf)
|
||||
gas_serv_write_dpp_adv_proto(tx_buf);
|
||||
} else {
|
||||
di->prot = prot;
|
||||
di->sd_resp = buf;
|
||||
di->sd_resp_pos = 0;
|
||||
tx_buf = gas_build_initial_resp(
|
||||
dialog_token, WLAN_STATUS_SUCCESS,
|
||||
comeback_delay, 10);
|
||||
if (tx_buf)
|
||||
gas_serv_write_dpp_adv_proto(tx_buf);
|
||||
}
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"DPP: GAS Initial response (no comeback)");
|
||||
tx_buf = gas_build_initial_resp(
|
||||
dialog_token, WLAN_STATUS_SUCCESS, 0,
|
||||
10 + 2 + wpabuf_len(buf));
|
||||
if (tx_buf) {
|
||||
gas_serv_write_dpp_adv_proto(tx_buf);
|
||||
wpabuf_put_le16(tx_buf, wpabuf_len(buf));
|
||||
wpabuf_put_buf(tx_buf, buf);
|
||||
hostapd_dpp_gas_status_handler(hapd, 1);
|
||||
}
|
||||
wpabuf_free(buf);
|
||||
}
|
||||
if (!tx_buf)
|
||||
return;
|
||||
if (prot)
|
||||
convert_to_protected_dual(tx_buf);
|
||||
hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
|
||||
wpabuf_head(tx_buf),
|
||||
wpabuf_len(tx_buf));
|
||||
wpabuf_free(tx_buf);
|
||||
}
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
|
||||
static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
|
||||
const u8 *sa,
|
||||
const u8 *data, size_t len, int prot,
|
||||
@ -1252,6 +1599,9 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
|
||||
u16 slen;
|
||||
struct anqp_query_info qi;
|
||||
const u8 *adv_proto;
|
||||
#ifdef CONFIG_DPP
|
||||
int dpp = 0;
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
if (len < 1 + 2)
|
||||
return;
|
||||
@ -1279,6 +1629,15 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
|
||||
next = pos + slen;
|
||||
pos++; /* skip QueryRespLenLimit and PAME-BI */
|
||||
|
||||
#ifdef CONFIG_DPP
|
||||
if (slen == 8 && *pos == WLAN_EID_VENDOR_SPECIFIC &&
|
||||
pos[1] == 5 && WPA_GET_BE24(&pos[2]) == OUI_WFA &&
|
||||
pos[5] == DPP_OUI_TYPE && pos[6] == 0x01) {
|
||||
wpa_printf(MSG_DEBUG, "DPP: Configuration Request");
|
||||
dpp = 1;
|
||||
} else
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
|
||||
struct wpabuf *buf;
|
||||
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
|
||||
@ -1318,6 +1677,18 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
|
||||
return;
|
||||
end = pos + slen;
|
||||
|
||||
#ifdef CONFIG_DPP
|
||||
if (dpp) {
|
||||
struct wpabuf *msg;
|
||||
|
||||
msg = hostapd_dpp_gas_req_handler(hapd, sa, pos, slen);
|
||||
if (!msg)
|
||||
return;
|
||||
gas_serv_req_dpp_processing(hapd, sa, dialog_token, prot, msg);
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
/* ANQP Query Request */
|
||||
while (pos < end) {
|
||||
u16 info_id, elen;
|
||||
@ -1339,11 +1710,9 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
|
||||
case ANQP_QUERY_LIST:
|
||||
rx_anqp_query_list(hapd, pos, pos + elen, &qi);
|
||||
break;
|
||||
#ifdef CONFIG_HS20
|
||||
case ANQP_VENDOR_SPECIFIC:
|
||||
rx_anqp_vendor_specific(hapd, pos, pos + elen, &qi);
|
||||
break;
|
||||
#endif /* CONFIG_HS20 */
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "ANQP: Unsupported Query "
|
||||
"Request element %u", info_id);
|
||||
@ -1393,8 +1762,8 @@ static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos;
|
||||
if (frag_len > hapd->gas_frag_limit) {
|
||||
frag_len = hapd->gas_frag_limit;
|
||||
if (frag_len > hapd->conf->gas_frag_limit) {
|
||||
frag_len = hapd->conf->gas_frag_limit;
|
||||
more = 1;
|
||||
}
|
||||
wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: resp frag_len %u",
|
||||
@ -1407,6 +1776,18 @@ static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
|
||||
gas_serv_dialog_clear(dialog);
|
||||
return;
|
||||
}
|
||||
#ifdef CONFIG_DPP
|
||||
if (dialog->dpp) {
|
||||
tx_buf = gas_build_comeback_resp(dialog_token,
|
||||
WLAN_STATUS_SUCCESS,
|
||||
dialog->sd_frag_id, more, 0,
|
||||
10 + frag_len);
|
||||
if (tx_buf) {
|
||||
gas_serv_write_dpp_adv_proto(tx_buf);
|
||||
wpabuf_put_buf(tx_buf, buf);
|
||||
}
|
||||
} else
|
||||
#endif /* CONFIG_DPP */
|
||||
tx_buf = gas_anqp_build_comeback_resp_buf(dialog_token,
|
||||
WLAN_STATUS_SUCCESS,
|
||||
dialog->sd_frag_id,
|
||||
@ -1430,6 +1811,10 @@ static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
|
||||
} else {
|
||||
wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: All fragments of "
|
||||
"SD response sent");
|
||||
#ifdef CONFIG_DPP
|
||||
if (dialog->dpp)
|
||||
hostapd_dpp_gas_status_handler(hapd, 1);
|
||||
#endif /* CONFIG_DPP */
|
||||
gas_serv_dialog_clear(dialog);
|
||||
gas_serv_free_dialogs(hapd, sa);
|
||||
}
|
||||
@ -1495,9 +1880,6 @@ int gas_serv_init(struct hostapd_data *hapd)
|
||||
{
|
||||
hapd->public_action_cb2 = gas_serv_rx_public_action;
|
||||
hapd->public_action_cb2_ctx = hapd;
|
||||
hapd->gas_frag_limit = 1400;
|
||||
if (hapd->conf->gas_frag_limit > 0)
|
||||
hapd->gas_frag_limit = hapd->conf->gas_frag_limit;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@
|
||||
#define ANQP_REQ_EMERGENCY_NAI \
|
||||
(1 << (ANQP_EMERGENCY_NAI - ANQP_QUERY_LIST))
|
||||
/*
|
||||
* First 16 Hotspot 2.0 vendor specific ANQP-elements can be included in the
|
||||
* First 15 Hotspot 2.0 vendor specific ANQP-elements can be included in the
|
||||
* optimized bitmap.
|
||||
*/
|
||||
#define ANQP_REQ_HS_CAPABILITY_LIST \
|
||||
@ -60,6 +60,13 @@
|
||||
(0x10000 << HS20_STYPE_OSU_PROVIDERS_LIST)
|
||||
#define ANQP_REQ_ICON_REQUEST \
|
||||
(0x10000 << HS20_STYPE_ICON_REQUEST)
|
||||
#define ANQP_REQ_OPERATOR_ICON_METADATA \
|
||||
(0x10000 << HS20_STYPE_OPERATOR_ICON_METADATA)
|
||||
#define ANQP_REQ_OSU_PROVIDERS_NAI_LIST \
|
||||
(0x10000 << HS20_STYPE_OSU_PROVIDERS_NAI_LIST)
|
||||
/* The first MBO ANQP-element can be included in the optimized bitmap. */
|
||||
#define ANQP_REQ_MBO_CELL_DATA_CONN_PREF \
|
||||
(BIT(29) << MBO_ANQP_SUBTYPE_CELL_CONN_PREF)
|
||||
|
||||
struct gas_dialog_info {
|
||||
u8 valid;
|
||||
@ -68,6 +75,7 @@ struct gas_dialog_info {
|
||||
size_t sd_resp_pos; /* Offset in sd_resp */
|
||||
u8 sd_frag_id;
|
||||
int prot; /* whether Protected Dual of Public Action frame is used */
|
||||
int dpp; /* whether this is a DPP Config Response */
|
||||
};
|
||||
|
||||
struct hostapd_data;
|
||||
|
@ -31,6 +31,8 @@
|
||||
#include "vlan_init.h"
|
||||
#include "wpa_auth.h"
|
||||
#include "wps_hostapd.h"
|
||||
#include "dpp_hostapd.h"
|
||||
#include "gas_query_ap.h"
|
||||
#include "hw_features.h"
|
||||
#include "wpa_auth_glue.h"
|
||||
#include "ap_drv_ops.h"
|
||||
@ -45,6 +47,9 @@
|
||||
#include "ndisc_snoop.h"
|
||||
#include "neighbor_db.h"
|
||||
#include "rrm.h"
|
||||
#include "fils_hlp.h"
|
||||
#include "acs.h"
|
||||
#include "hs20.h"
|
||||
|
||||
|
||||
static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
|
||||
@ -52,6 +57,8 @@ static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd);
|
||||
static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd);
|
||||
static int setup_interface2(struct hostapd_iface *iface);
|
||||
static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx);
|
||||
static void hostapd_interface_setup_failure_handler(void *eloop_ctx,
|
||||
void *timeout_ctx);
|
||||
|
||||
|
||||
int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
|
||||
@ -71,10 +78,26 @@ int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
|
||||
}
|
||||
|
||||
|
||||
void hostapd_reconfig_encryption(struct hostapd_data *hapd)
|
||||
{
|
||||
if (hapd->wpa_auth)
|
||||
return;
|
||||
|
||||
hostapd_set_privacy(hapd, 0);
|
||||
hostapd_setup_encryption(hapd->conf->iface, hapd);
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_reload_bss(struct hostapd_data *hapd)
|
||||
{
|
||||
struct hostapd_ssid *ssid;
|
||||
|
||||
if (!hapd->started)
|
||||
return;
|
||||
|
||||
if (hapd->conf->wmm_enabled < 0)
|
||||
hapd->conf->wmm_enabled = hapd->iconf->ieee80211n;
|
||||
|
||||
#ifndef CONFIG_NO_RADIUS
|
||||
radius_client_reconfig(hapd->radius, hapd->conf->radius);
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
@ -153,8 +176,27 @@ static void hostapd_clear_old(struct hostapd_iface *iface)
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_iface_conf_changed(struct hostapd_config *newconf,
|
||||
struct hostapd_config *oldconf)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (newconf->num_bss != oldconf->num_bss)
|
||||
return 1;
|
||||
|
||||
for (i = 0; i < newconf->num_bss; i++) {
|
||||
if (os_strcmp(newconf->bss[i]->iface,
|
||||
oldconf->bss[i]->iface) != 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_reload_config(struct hostapd_iface *iface)
|
||||
{
|
||||
struct hapd_interfaces *interfaces = iface->interfaces;
|
||||
struct hostapd_data *hapd = iface->bss[0];
|
||||
struct hostapd_config *newconf, *oldconf;
|
||||
size_t j;
|
||||
@ -177,6 +219,35 @@ int hostapd_reload_config(struct hostapd_iface *iface)
|
||||
hostapd_clear_old(iface);
|
||||
|
||||
oldconf = hapd->iconf;
|
||||
if (hostapd_iface_conf_changed(newconf, oldconf)) {
|
||||
char *fname;
|
||||
int res;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Configuration changes include interface/BSS modification - force full disable+enable sequence");
|
||||
fname = os_strdup(iface->config_fname);
|
||||
if (!fname) {
|
||||
hostapd_config_free(newconf);
|
||||
return -1;
|
||||
}
|
||||
hostapd_remove_iface(interfaces, hapd->conf->iface);
|
||||
iface = hostapd_init(interfaces, fname);
|
||||
os_free(fname);
|
||||
hostapd_config_free(newconf);
|
||||
if (!iface) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Failed to initialize interface on config reload");
|
||||
return -1;
|
||||
}
|
||||
iface->interfaces = interfaces;
|
||||
interfaces->iface[interfaces->count] = iface;
|
||||
interfaces->count++;
|
||||
res = hostapd_enable_iface(iface);
|
||||
if (res < 0)
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Failed to enable interface on config reload");
|
||||
return res;
|
||||
}
|
||||
iface->conf = newconf;
|
||||
|
||||
for (j = 0; j < iface->num_bss; j++) {
|
||||
@ -210,7 +281,7 @@ static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!ifname)
|
||||
if (!ifname || !hapd->drv_priv)
|
||||
return;
|
||||
for (i = 0; i < NUM_WEP_KEYS; i++) {
|
||||
if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i,
|
||||
@ -297,6 +368,10 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
|
||||
hostapd_deinit_wps(hapd);
|
||||
#ifdef CONFIG_DPP
|
||||
hostapd_dpp_deinit(hapd);
|
||||
gas_query_ap_deinit(hapd->gas);
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
authsrv_deinit(hapd);
|
||||
|
||||
@ -341,6 +416,7 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
|
||||
#endif /* CONFIG_MESH */
|
||||
|
||||
hostapd_clean_rrm(hapd);
|
||||
fils_hlp_deinit(hapd);
|
||||
}
|
||||
|
||||
|
||||
@ -357,8 +433,10 @@ static void hostapd_cleanup(struct hostapd_data *hapd)
|
||||
wpa_printf(MSG_DEBUG, "%s(hapd=%p (%s))", __func__, hapd,
|
||||
hapd->conf->iface);
|
||||
if (hapd->iface->interfaces &&
|
||||
hapd->iface->interfaces->ctrl_iface_deinit)
|
||||
hapd->iface->interfaces->ctrl_iface_deinit) {
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, WPA_EVENT_TERMINATING);
|
||||
hapd->iface->interfaces->ctrl_iface_deinit(hapd);
|
||||
}
|
||||
hostapd_free_hapd_data(hapd);
|
||||
}
|
||||
|
||||
@ -387,8 +465,11 @@ static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
|
||||
hostapd_stop_setup_timers(iface);
|
||||
#endif /* NEED_AP_MLME */
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
if (iface->current_mode)
|
||||
acs_cleanup(iface);
|
||||
hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
|
||||
iface->hw_features = NULL;
|
||||
iface->current_mode = NULL;
|
||||
os_free(iface->current_rates);
|
||||
iface->current_rates = NULL;
|
||||
os_free(iface->basic_rates);
|
||||
@ -409,6 +490,8 @@ static void hostapd_cleanup_iface(struct hostapd_iface *iface)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
|
||||
eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
|
||||
eloop_cancel_timeout(hostapd_interface_setup_failure_handler, iface,
|
||||
NULL);
|
||||
|
||||
hostapd_cleanup_iface_partial(iface);
|
||||
hostapd_config_free(iface->conf);
|
||||
@ -484,9 +567,12 @@ static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason)
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Deauthenticate all stations");
|
||||
os_memset(addr, 0xff, ETH_ALEN);
|
||||
hostapd_drv_sta_deauth(hapd, addr, reason);
|
||||
if (hapd->conf && hapd->conf->broadcast_deauth) {
|
||||
wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
|
||||
"Deauthenticate all stations");
|
||||
os_memset(addr, 0xff, ETH_ALEN);
|
||||
hostapd_drv_sta_deauth(hapd, addr, reason);
|
||||
}
|
||||
hostapd_free_stas(hapd);
|
||||
|
||||
return ret;
|
||||
@ -873,6 +959,48 @@ hostapd_das_disconnect(void *ctx, struct radius_das_attrs *attr)
|
||||
return RADIUS_DAS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_HS20
|
||||
static enum radius_das_res
|
||||
hostapd_das_coa(void *ctx, struct radius_das_attrs *attr)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
struct sta_info *sta;
|
||||
int multi;
|
||||
|
||||
if (hostapd_das_nas_mismatch(hapd, attr))
|
||||
return RADIUS_DAS_NAS_MISMATCH;
|
||||
|
||||
sta = hostapd_das_find_sta(hapd, attr, &multi);
|
||||
if (!sta) {
|
||||
if (multi) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"RADIUS DAS: Multiple sessions match - not supported");
|
||||
return RADIUS_DAS_MULTI_SESSION_MATCH;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "RADIUS DAS: No matching session found");
|
||||
return RADIUS_DAS_SESSION_NOT_FOUND;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "RADIUS DAS: Found a matching session " MACSTR
|
||||
" - CoA", MAC2STR(sta->addr));
|
||||
|
||||
if (attr->hs20_t_c_filtering) {
|
||||
if (attr->hs20_t_c_filtering[0] & BIT(0)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"HS 2.0: Unexpected Terms and Conditions filtering required in CoA-Request");
|
||||
return RADIUS_DAS_COA_FAILED;
|
||||
}
|
||||
|
||||
hs20_t_c_filtering(hapd, sta, 0);
|
||||
}
|
||||
|
||||
return RADIUS_DAS_SUCCESS;
|
||||
}
|
||||
#else /* CONFIG_HS20 */
|
||||
#define hostapd_das_coa NULL
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
|
||||
|
||||
@ -956,13 +1084,13 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
|
||||
if (conf->wmm_enabled < 0)
|
||||
conf->wmm_enabled = hapd->iconf->ieee80211n;
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
if (is_zero_ether_addr(conf->r1_key_holder))
|
||||
os_memcpy(conf->r1_key_holder, hapd->own_addr, ETH_ALEN);
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
#ifdef CONFIG_MESH
|
||||
if (hapd->iface->mconf == NULL)
|
||||
if ((hapd->conf->mesh & MESH_ENABLED) && hapd->iface->mconf == NULL)
|
||||
flush_old_stations = 0;
|
||||
#endif /* CONFIG_MESH */
|
||||
|
||||
@ -1047,6 +1175,7 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
|
||||
conf->radius_das_require_message_authenticator;
|
||||
das_conf.ctx = hapd;
|
||||
das_conf.disconnect = hostapd_das_disconnect;
|
||||
das_conf.coa = hostapd_das_coa;
|
||||
hapd->radius_das = radius_das_init(&das_conf);
|
||||
if (hapd->radius_das == NULL) {
|
||||
wpa_printf(MSG_ERROR, "RADIUS DAS initialization "
|
||||
@ -1063,6 +1192,14 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
|
||||
if (hostapd_init_wps(hapd, conf))
|
||||
return -1;
|
||||
|
||||
#ifdef CONFIG_DPP
|
||||
hapd->gas = gas_query_ap_init(hapd, hapd->msg_ctx);
|
||||
if (!hapd->gas)
|
||||
return -1;
|
||||
if (hostapd_dpp_init(hapd))
|
||||
return -1;
|
||||
#endif /* CONFIG_DPP */
|
||||
|
||||
if (authsrv_init(hapd) < 0)
|
||||
return -1;
|
||||
|
||||
@ -1150,7 +1287,7 @@ static void hostapd_tx_queue_params(struct hostapd_iface *iface)
|
||||
struct hostapd_tx_queue_params *p;
|
||||
|
||||
#ifdef CONFIG_MESH
|
||||
if (iface->mconf == NULL)
|
||||
if ((hapd->conf->mesh & MESH_ENABLED) && iface->mconf == NULL)
|
||||
return;
|
||||
#endif /* CONFIG_MESH */
|
||||
|
||||
@ -1561,7 +1698,7 @@ static void hostapd_set_own_neighbor_report(struct hostapd_data *hapd)
|
||||
int vht = hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac;
|
||||
struct wpa_ssid_value ssid;
|
||||
u8 channel, op_class;
|
||||
int center_freq1 = 0, center_freq2 = 0;
|
||||
u8 center_freq1_idx = 0, center_freq2_idx = 0;
|
||||
enum nr_chan_width width;
|
||||
u32 bssid_info;
|
||||
struct wpabuf *nr;
|
||||
@ -1598,22 +1735,22 @@ static void hostapd_set_own_neighbor_report(struct hostapd_data *hapd)
|
||||
|
||||
/* TODO: Set NEI_REP_BSSID_INFO_MOBILITY_DOMAIN if MDE is set */
|
||||
|
||||
ieee80211_freq_to_channel_ext(hapd->iface->freq,
|
||||
hapd->iconf->secondary_channel,
|
||||
hapd->iconf->vht_oper_chwidth,
|
||||
&op_class, &channel);
|
||||
if (ieee80211_freq_to_channel_ext(hapd->iface->freq,
|
||||
hapd->iconf->secondary_channel,
|
||||
hapd->iconf->vht_oper_chwidth,
|
||||
&op_class, &channel) ==
|
||||
NUM_HOSTAPD_MODES)
|
||||
return;
|
||||
width = hostapd_get_nr_chan_width(hapd, ht, vht);
|
||||
if (vht) {
|
||||
center_freq1 = ieee80211_chan_to_freq(
|
||||
NULL, op_class,
|
||||
hapd->iconf->vht_oper_centr_freq_seg0_idx);
|
||||
center_freq1_idx = hapd->iconf->vht_oper_centr_freq_seg0_idx;
|
||||
if (width == NR_CHAN_WIDTH_80P80)
|
||||
center_freq2 = ieee80211_chan_to_freq(
|
||||
NULL, op_class,
|
||||
hapd->iconf->vht_oper_centr_freq_seg1_idx);
|
||||
center_freq2_idx =
|
||||
hapd->iconf->vht_oper_centr_freq_seg1_idx;
|
||||
} else if (ht) {
|
||||
center_freq1 = hapd->iface->freq +
|
||||
10 * hapd->iconf->secondary_channel;
|
||||
ieee80211_freq_to_chan(hapd->iface->freq +
|
||||
10 * hapd->iconf->secondary_channel,
|
||||
¢er_freq1_idx);
|
||||
}
|
||||
|
||||
ssid.ssid_len = hapd->conf->ssid.ssid_len;
|
||||
@ -1641,17 +1778,127 @@ static void hostapd_set_own_neighbor_report(struct hostapd_data *hapd)
|
||||
wpabuf_put_u8(nr, WNM_NEIGHBOR_WIDE_BW_CHAN);
|
||||
wpabuf_put_u8(nr, 3);
|
||||
wpabuf_put_u8(nr, width);
|
||||
wpabuf_put_u8(nr, center_freq1);
|
||||
wpabuf_put_u8(nr, center_freq2);
|
||||
wpabuf_put_u8(nr, center_freq1_idx);
|
||||
wpabuf_put_u8(nr, center_freq2_idx);
|
||||
|
||||
hostapd_neighbor_set(hapd, hapd->own_addr, &ssid, nr, hapd->iconf->lci,
|
||||
hapd->iconf->civic);
|
||||
hapd->iconf->civic, hapd->iconf->stationary_ap);
|
||||
|
||||
wpabuf_free(nr);
|
||||
#endif /* NEED_AP_MLME */
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_OWE
|
||||
|
||||
static int hostapd_owe_iface_iter(struct hostapd_iface *iface, void *ctx)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < iface->num_bss; i++) {
|
||||
struct hostapd_data *bss = iface->bss[i];
|
||||
|
||||
if (os_strcmp(hapd->conf->owe_transition_ifname,
|
||||
bss->conf->iface) != 0)
|
||||
continue;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"OWE: ifname=%s found transition mode ifname=%s BSSID "
|
||||
MACSTR " SSID %s",
|
||||
hapd->conf->iface, bss->conf->iface,
|
||||
MAC2STR(bss->own_addr),
|
||||
wpa_ssid_txt(bss->conf->ssid.ssid,
|
||||
bss->conf->ssid.ssid_len));
|
||||
if (!bss->conf->ssid.ssid_set || !bss->conf->ssid.ssid_len ||
|
||||
is_zero_ether_addr(bss->own_addr))
|
||||
continue;
|
||||
|
||||
os_memcpy(hapd->conf->owe_transition_bssid, bss->own_addr,
|
||||
ETH_ALEN);
|
||||
os_memcpy(hapd->conf->owe_transition_ssid,
|
||||
bss->conf->ssid.ssid, bss->conf->ssid.ssid_len);
|
||||
hapd->conf->owe_transition_ssid_len = bss->conf->ssid.ssid_len;
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"OWE: Copied transition mode information");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_owe_trans_get_info(struct hostapd_data *hapd)
|
||||
{
|
||||
if (hapd->conf->owe_transition_ssid_len > 0 &&
|
||||
!is_zero_ether_addr(hapd->conf->owe_transition_bssid))
|
||||
return 0;
|
||||
|
||||
/* Find transition mode SSID/BSSID information from a BSS operated by
|
||||
* this hostapd instance. */
|
||||
if (!hapd->iface->interfaces ||
|
||||
!hapd->iface->interfaces->for_each_interface)
|
||||
return hostapd_owe_iface_iter(hapd->iface, hapd);
|
||||
else
|
||||
return hapd->iface->interfaces->for_each_interface(
|
||||
hapd->iface->interfaces, hostapd_owe_iface_iter, hapd);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_owe_iface_iter2(struct hostapd_iface *iface, void *ctx)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < iface->num_bss; i++) {
|
||||
struct hostapd_data *bss = iface->bss[i];
|
||||
int res;
|
||||
|
||||
if (!bss->conf->owe_transition_ifname[0])
|
||||
continue;
|
||||
res = hostapd_owe_trans_get_info(bss);
|
||||
if (res == 0)
|
||||
continue;
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"OWE: Matching transition mode interface enabled - update beacon data for %s",
|
||||
bss->conf->iface);
|
||||
ieee802_11_set_beacon(bss);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_OWE */
|
||||
|
||||
|
||||
static void hostapd_owe_update_trans(struct hostapd_iface *iface)
|
||||
{
|
||||
#ifdef CONFIG_OWE
|
||||
/* Check whether the enabled BSS can complete OWE transition mode
|
||||
* configuration for any pending interface. */
|
||||
if (!iface->interfaces ||
|
||||
!iface->interfaces->for_each_interface)
|
||||
hostapd_owe_iface_iter2(iface, NULL);
|
||||
else
|
||||
iface->interfaces->for_each_interface(
|
||||
iface->interfaces, hostapd_owe_iface_iter2, NULL);
|
||||
#endif /* CONFIG_OWE */
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_interface_setup_failure_handler(void *eloop_ctx,
|
||||
void *timeout_ctx)
|
||||
{
|
||||
struct hostapd_iface *iface = eloop_ctx;
|
||||
struct hostapd_data *hapd;
|
||||
|
||||
if (iface->num_bss < 1 || !iface->bss || !iface->bss[0])
|
||||
return;
|
||||
hapd = iface->bss[0];
|
||||
if (hapd->setup_complete_cb)
|
||||
hapd->setup_complete_cb(hapd->setup_complete_cb_ctx);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
|
||||
int err)
|
||||
{
|
||||
@ -1827,6 +2074,7 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
|
||||
#endif /* CONFIG_FST */
|
||||
|
||||
hostapd_set_state(iface, HAPD_IFACE_ENABLED);
|
||||
hostapd_owe_update_trans(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);
|
||||
@ -1851,8 +2099,19 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
|
||||
iface->fst = NULL;
|
||||
}
|
||||
#endif /* CONFIG_FST */
|
||||
if (iface->interfaces && iface->interfaces->terminate_on_error)
|
||||
|
||||
if (iface->interfaces && iface->interfaces->terminate_on_error) {
|
||||
eloop_terminate();
|
||||
} else if (hapd->setup_complete_cb) {
|
||||
/*
|
||||
* Calling hapd->setup_complete_cb directly may cause iface
|
||||
* deinitialization which may be accessed later by the caller.
|
||||
*/
|
||||
eloop_register_timeout(0, 0,
|
||||
hostapd_interface_setup_failure_handler,
|
||||
iface, NULL);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -1997,10 +2256,16 @@ hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
|
||||
hapd->iconf = conf;
|
||||
hapd->conf = bss;
|
||||
hapd->iface = hapd_iface;
|
||||
hapd->driver = hapd->iconf->driver;
|
||||
if (conf)
|
||||
hapd->driver = conf->driver;
|
||||
hapd->ctrl_sock = -1;
|
||||
dl_list_init(&hapd->ctrl_dst);
|
||||
dl_list_init(&hapd->nr_db);
|
||||
hapd->dhcp_sock = -1;
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
dl_list_init(&hapd->l2_queue);
|
||||
dl_list_init(&hapd->l2_oui_queue);
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
return hapd;
|
||||
}
|
||||
@ -2028,12 +2293,6 @@ void hostapd_interface_deinit(struct hostapd_iface *iface)
|
||||
|
||||
hostapd_set_state(iface, HAPD_IFACE_DISABLED);
|
||||
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
#ifdef NEED_AP_MLME
|
||||
hostapd_stop_setup_timers(iface);
|
||||
eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL);
|
||||
#endif /* NEED_AP_MLME */
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
|
||||
iface->wait_channel_update = 0;
|
||||
|
||||
@ -2049,6 +2308,13 @@ void hostapd_interface_deinit(struct hostapd_iface *iface)
|
||||
break;
|
||||
hostapd_bss_deinit(iface->bss[j]);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
#ifdef NEED_AP_MLME
|
||||
hostapd_stop_setup_timers(iface);
|
||||
eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL);
|
||||
#endif /* NEED_AP_MLME */
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
}
|
||||
|
||||
|
||||
@ -2402,6 +2668,11 @@ int hostapd_disable_iface(struct hostapd_iface *hapd_iface)
|
||||
!!(hapd_iface->drv_flags &
|
||||
WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
|
||||
|
||||
#ifdef NEED_AP_MLME
|
||||
for (j = 0; j < hapd_iface->num_bss; j++)
|
||||
hostapd_cleanup_cs_params(hapd_iface->bss[j]);
|
||||
#endif /* NEED_AP_MLME */
|
||||
|
||||
/* same as hostapd_interface_deinit without deinitializing ctrl-iface */
|
||||
for (j = 0; j < hapd_iface->num_bss; j++) {
|
||||
struct hostapd_data *hapd = hapd_iface->bss[j];
|
||||
@ -2459,7 +2730,7 @@ hostapd_config_alloc(struct hapd_interfaces *interfaces, const char *ifname,
|
||||
if (conf == NULL) {
|
||||
wpa_printf(MSG_ERROR, "%s: Failed to allocate memory for "
|
||||
"configuration", __func__);
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (driver) {
|
||||
@ -2612,6 +2883,7 @@ int hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
hostapd_owe_update_trans(hapd_iface);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2829,12 +3101,24 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
ieee802_1x_new_station(hapd, sta);
|
||||
if (reassoc) {
|
||||
if (sta->auth_alg != WLAN_AUTH_FT &&
|
||||
sta->auth_alg != WLAN_AUTH_FILS_SK &&
|
||||
sta->auth_alg != WLAN_AUTH_FILS_SK_PFS &&
|
||||
sta->auth_alg != WLAN_AUTH_FILS_PK &&
|
||||
!(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)))
|
||||
wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH);
|
||||
} else
|
||||
wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm);
|
||||
|
||||
if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
|
||||
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED) {
|
||||
if (eloop_cancel_timeout(ap_handle_timer, hapd, sta) > 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"%s: %s: canceled wired ap_handle_timer timeout for "
|
||||
MACSTR,
|
||||
hapd->conf->iface, __func__,
|
||||
MAC2STR(sta->addr));
|
||||
}
|
||||
} else if (!(hapd->iface->drv_flags &
|
||||
WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"%s: %s: reschedule ap_handle_timer timeout for "
|
||||
MACSTR " (%d seconds - ap_max_inactivity)",
|
||||
@ -2928,60 +3212,52 @@ static int hostapd_build_beacon_data(struct hostapd_data *hapd,
|
||||
goto free_ap_params;
|
||||
|
||||
ret = -1;
|
||||
beacon->head = os_malloc(params.head_len);
|
||||
beacon->head = os_memdup(params.head, params.head_len);
|
||||
if (!beacon->head)
|
||||
goto free_ap_extra_ies;
|
||||
|
||||
os_memcpy(beacon->head, params.head, params.head_len);
|
||||
beacon->head_len = params.head_len;
|
||||
|
||||
beacon->tail = os_malloc(params.tail_len);
|
||||
beacon->tail = os_memdup(params.tail, params.tail_len);
|
||||
if (!beacon->tail)
|
||||
goto free_beacon;
|
||||
|
||||
os_memcpy(beacon->tail, params.tail, params.tail_len);
|
||||
beacon->tail_len = params.tail_len;
|
||||
|
||||
if (params.proberesp != NULL) {
|
||||
beacon->probe_resp = os_malloc(params.proberesp_len);
|
||||
beacon->probe_resp = os_memdup(params.proberesp,
|
||||
params.proberesp_len);
|
||||
if (!beacon->probe_resp)
|
||||
goto free_beacon;
|
||||
|
||||
os_memcpy(beacon->probe_resp, params.proberesp,
|
||||
params.proberesp_len);
|
||||
beacon->probe_resp_len = params.proberesp_len;
|
||||
}
|
||||
|
||||
/* copy the extra ies */
|
||||
if (beacon_extra) {
|
||||
beacon->beacon_ies = os_malloc(wpabuf_len(beacon_extra));
|
||||
beacon->beacon_ies = os_memdup(beacon_extra->buf,
|
||||
wpabuf_len(beacon_extra));
|
||||
if (!beacon->beacon_ies)
|
||||
goto free_beacon;
|
||||
|
||||
os_memcpy(beacon->beacon_ies,
|
||||
beacon_extra->buf, wpabuf_len(beacon_extra));
|
||||
beacon->beacon_ies_len = wpabuf_len(beacon_extra);
|
||||
}
|
||||
|
||||
if (proberesp_extra) {
|
||||
beacon->proberesp_ies =
|
||||
os_malloc(wpabuf_len(proberesp_extra));
|
||||
beacon->proberesp_ies = os_memdup(proberesp_extra->buf,
|
||||
wpabuf_len(proberesp_extra));
|
||||
if (!beacon->proberesp_ies)
|
||||
goto free_beacon;
|
||||
|
||||
os_memcpy(beacon->proberesp_ies, proberesp_extra->buf,
|
||||
wpabuf_len(proberesp_extra));
|
||||
beacon->proberesp_ies_len = wpabuf_len(proberesp_extra);
|
||||
}
|
||||
|
||||
if (assocresp_extra) {
|
||||
beacon->assocresp_ies =
|
||||
os_malloc(wpabuf_len(assocresp_extra));
|
||||
beacon->assocresp_ies = os_memdup(assocresp_extra->buf,
|
||||
wpabuf_len(assocresp_extra));
|
||||
if (!beacon->assocresp_ies)
|
||||
goto free_beacon;
|
||||
|
||||
os_memcpy(beacon->assocresp_ies, assocresp_extra->buf,
|
||||
wpabuf_len(assocresp_extra));
|
||||
beacon->assocresp_ies_len = wpabuf_len(assocresp_extra);
|
||||
}
|
||||
|
||||
@ -3158,6 +3434,19 @@ void hostapd_cleanup_cs_params(struct hostapd_data *hapd)
|
||||
}
|
||||
|
||||
|
||||
void hostapd_chan_switch_vht_config(struct hostapd_data *hapd, int vht_enabled)
|
||||
{
|
||||
if (vht_enabled)
|
||||
hapd->iconf->ch_switch_vht_config |= CH_SWITCH_VHT_ENABLED;
|
||||
else
|
||||
hapd->iconf->ch_switch_vht_config |= CH_SWITCH_VHT_DISABLED;
|
||||
|
||||
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_INFO, "CHAN_SWITCH VHT CONFIG 0x%x",
|
||||
hapd->iconf->ch_switch_vht_config);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_switch_channel(struct hostapd_data *hapd,
|
||||
struct csa_settings *settings)
|
||||
{
|
||||
@ -3192,7 +3481,6 @@ 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;
|
||||
unsigned int i;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Restarting all CSA-related BSSes");
|
||||
|
||||
@ -3234,10 +3522,8 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface,
|
||||
/*
|
||||
* cs_params must not be cleared earlier because the freq_params
|
||||
* argument may actually point to one of these.
|
||||
* These params will be cleared during interface disable below.
|
||||
*/
|
||||
for (i = 0; i < iface->num_bss; i++)
|
||||
hostapd_cleanup_cs_params(iface->bss[i]);
|
||||
|
||||
hostapd_disable_iface(iface);
|
||||
hostapd_enable_iface(iface);
|
||||
}
|
||||
|
@ -14,6 +14,13 @@
|
||||
#include "ap_config.h"
|
||||
#include "drivers/driver.h"
|
||||
|
||||
#define OCE_STA_CFON_ENABLED(hapd) \
|
||||
((hapd->conf->oce & OCE_STA_CFON) && \
|
||||
(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_OCE_STA_CFON))
|
||||
#define OCE_AP_ENABLED(hapd) \
|
||||
((hapd->conf->oce & OCE_AP) && \
|
||||
(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_OCE_AP))
|
||||
|
||||
struct wpa_ctrl_dst;
|
||||
struct radius_server_data;
|
||||
struct upnp_wps_device_sm;
|
||||
@ -53,7 +60,16 @@ struct hapd_interfaces {
|
||||
#ifndef CONFIG_NO_VLAN
|
||||
struct dynamic_iface *vlan_priv;
|
||||
#endif /* CONFIG_NO_VLAN */
|
||||
#ifdef CONFIG_ETH_P_OUI
|
||||
struct dl_list eth_p_oui; /* OUI Extended EtherType handlers */
|
||||
#endif /* CONFIG_ETH_P_OUI */
|
||||
int eloop_initialized;
|
||||
|
||||
#ifdef CONFIG_DPP
|
||||
int dpp_init_done;
|
||||
struct dl_list dpp_bootstrap; /* struct dpp_bootstrap_info */
|
||||
struct dl_list dpp_configurator; /* struct dpp_configurator */
|
||||
#endif /* CONFIG_DPP */
|
||||
};
|
||||
|
||||
enum hostapd_chan_status {
|
||||
@ -76,6 +92,7 @@ struct hostapd_rate_data {
|
||||
};
|
||||
|
||||
struct hostapd_frame_info {
|
||||
unsigned int freq;
|
||||
u32 channel;
|
||||
u32 datarate;
|
||||
int ssi_signal; /* dBm */
|
||||
@ -109,6 +126,7 @@ struct hostapd_neighbor_entry {
|
||||
struct wpabuf *civic;
|
||||
/* LCI update time */
|
||||
struct os_time lci_date;
|
||||
int stationary;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -184,6 +202,17 @@ struct hostapd_data {
|
||||
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||
|
||||
struct l2_packet_data *l2;
|
||||
|
||||
#ifdef CONFIG_IEEE80211R_AP
|
||||
struct dl_list l2_queue;
|
||||
struct dl_list l2_oui_queue;
|
||||
struct eth_p_oui_ctx *oui_pull;
|
||||
struct eth_p_oui_ctx *oui_resp;
|
||||
struct eth_p_oui_ctx *oui_push;
|
||||
struct eth_p_oui_ctx *oui_sreq;
|
||||
struct eth_p_oui_ctx *oui_sresp;
|
||||
#endif /* CONFIG_IEEE80211R_AP */
|
||||
|
||||
struct wps_context *wps;
|
||||
|
||||
int beacon_set_done;
|
||||
@ -242,9 +271,6 @@ struct hostapd_data {
|
||||
unsigned int cs_c_off_ecsa_beacon;
|
||||
unsigned int cs_c_off_ecsa_proberesp;
|
||||
|
||||
/* BSS Load */
|
||||
unsigned int bss_load_update_timeout;
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
struct p2p_data *p2p;
|
||||
struct p2p_group *p2p_group;
|
||||
@ -259,9 +285,6 @@ struct hostapd_data {
|
||||
int noa_start;
|
||||
int noa_duration;
|
||||
#endif /* CONFIG_P2P */
|
||||
#ifdef CONFIG_INTERWORKING
|
||||
size_t gas_frag_limit;
|
||||
#endif /* CONFIG_INTERWORKING */
|
||||
#ifdef CONFIG_PROXYARP
|
||||
struct l2_packet_data *sock_dhcp;
|
||||
struct l2_packet_data *sock_ndisc;
|
||||
@ -292,6 +315,18 @@ struct hostapd_data {
|
||||
unsigned int ext_eapol_frame_io:1;
|
||||
|
||||
struct l2_packet_data *l2_test;
|
||||
|
||||
enum wpa_alg last_gtk_alg;
|
||||
int last_gtk_key_idx;
|
||||
u8 last_gtk[WPA_GTK_MAX_LEN];
|
||||
size_t last_gtk_len;
|
||||
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
enum wpa_alg last_igtk_alg;
|
||||
int last_igtk_key_idx;
|
||||
u8 last_igtk[WPA_IGTK_MAX_LEN];
|
||||
size_t last_igtk_len;
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
@ -300,10 +335,42 @@ struct hostapd_data {
|
||||
|
||||
struct dl_list nr_db;
|
||||
|
||||
u8 beacon_req_token;
|
||||
u8 lci_req_token;
|
||||
u8 range_req_token;
|
||||
unsigned int lci_req_active:1;
|
||||
unsigned int range_req_active:1;
|
||||
|
||||
int dhcp_sock; /* UDP socket used with the DHCP server */
|
||||
|
||||
#ifdef CONFIG_DPP
|
||||
int dpp_init_done;
|
||||
struct dpp_authentication *dpp_auth;
|
||||
u8 dpp_allowed_roles;
|
||||
int dpp_qr_mutual;
|
||||
int dpp_auth_ok_on_ack;
|
||||
int dpp_in_response_listen;
|
||||
struct gas_query_ap *gas;
|
||||
struct dpp_pkex *dpp_pkex;
|
||||
struct dpp_bootstrap_info *dpp_pkex_bi;
|
||||
char *dpp_pkex_code;
|
||||
char *dpp_pkex_identifier;
|
||||
char *dpp_pkex_auth_cmd;
|
||||
char *dpp_configurator_params;
|
||||
struct os_reltime dpp_last_init;
|
||||
struct os_reltime dpp_init_iter_start;
|
||||
unsigned int dpp_init_max_tries;
|
||||
unsigned int dpp_init_retry_time;
|
||||
unsigned int dpp_resp_wait_time;
|
||||
unsigned int dpp_resp_max_tries;
|
||||
unsigned int dpp_resp_retry_time;
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
char *dpp_config_obj_override;
|
||||
char *dpp_discovery_override;
|
||||
char *dpp_groups_override;
|
||||
unsigned int dpp_ignore_netaccesskey_mismatch:1;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
#endif /* CONFIG_DPP */
|
||||
};
|
||||
|
||||
|
||||
@ -311,6 +378,7 @@ struct hostapd_sta_info {
|
||||
struct dl_list list;
|
||||
u8 addr[ETH_ALEN];
|
||||
struct os_reltime last_seen;
|
||||
int ssi_signal;
|
||||
#ifdef CONFIG_TAXONOMY
|
||||
struct wpabuf *probe_ie_taxonomy;
|
||||
#endif /* CONFIG_TAXONOMY */
|
||||
@ -440,6 +508,10 @@ struct hostapd_iface {
|
||||
u64 last_channel_time_busy;
|
||||
u8 channel_utilization;
|
||||
|
||||
unsigned int chan_util_samples_sum;
|
||||
unsigned int chan_util_num_sample_periods;
|
||||
unsigned int chan_util_average;
|
||||
|
||||
/* eCSA IE will be added only if operating class is specified */
|
||||
u8 cs_oper_class;
|
||||
|
||||
@ -459,6 +531,8 @@ struct hostapd_iface {
|
||||
|
||||
struct dl_list sta_seen; /* struct hostapd_sta_info */
|
||||
unsigned int num_sta_seen;
|
||||
|
||||
u8 dfs_domain;
|
||||
};
|
||||
|
||||
/* hostapd.c */
|
||||
@ -466,6 +540,7 @@ int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
|
||||
int (*cb)(struct hostapd_iface *iface,
|
||||
void *ctx), void *ctx);
|
||||
int hostapd_reload_config(struct hostapd_iface *iface);
|
||||
void hostapd_reconfig_encryption(struct hostapd_data *hapd);
|
||||
struct hostapd_data *
|
||||
hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
|
||||
struct hostapd_config *conf,
|
||||
@ -492,6 +567,7 @@ void hostapd_channel_list_updated(struct hostapd_iface *iface, int initiator);
|
||||
void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s);
|
||||
const char * hostapd_state_text(enum hostapd_iface_state s);
|
||||
int hostapd_csa_in_progress(struct hostapd_iface *iface);
|
||||
void hostapd_chan_switch_vht_config(struct hostapd_data *hapd, int vht_enabled);
|
||||
int hostapd_switch_channel(struct hostapd_data *hapd,
|
||||
struct csa_settings *settings);
|
||||
void
|
||||
@ -499,6 +575,7 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface,
|
||||
const struct hostapd_freq_params *freq_params);
|
||||
void hostapd_cleanup_cs_params(struct hostapd_data *hapd);
|
||||
void hostapd_periodic_iface(struct hostapd_iface *iface);
|
||||
int hostapd_owe_trans_get_info(struct hostapd_data *hapd);
|
||||
|
||||
/* utils.c */
|
||||
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
|
||||
@ -510,6 +587,8 @@ int hostapd_register_probereq_cb(struct hostapd_data *hapd,
|
||||
void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr);
|
||||
|
||||
/* drv_callbacks.c (TODO: move to somewhere else?) */
|
||||
void hostapd_notify_assoc_fils_finish(struct hostapd_data *hapd,
|
||||
struct sta_info *sta);
|
||||
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
const u8 *ie, size_t ielen, int reassoc);
|
||||
void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr);
|
||||
@ -533,6 +612,9 @@ hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
|
||||
|
||||
struct hostapd_data * hostapd_get_iface(struct hapd_interfaces *interfaces,
|
||||
const char *ifname);
|
||||
void hostapd_event_sta_opmode_changed(struct hostapd_data *hapd, const u8 *addr,
|
||||
enum smps_mode smps_mode,
|
||||
enum chan_width chan_width, u8 rx_nss);
|
||||
|
||||
#ifdef CONFIG_FST
|
||||
void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd,
|
||||
|
@ -11,9 +11,11 @@
|
||||
|
||||
#include "common.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/wpa_ctrl.h"
|
||||
#include "hostapd.h"
|
||||
#include "ap_config.h"
|
||||
#include "ap_drv_ops.h"
|
||||
#include "sta_info.h"
|
||||
#include "hs20.h"
|
||||
|
||||
|
||||
@ -175,3 +177,72 @@ int hs20_send_wnm_notification_deauth_req(struct hostapd_data *hapd,
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int hs20_send_wnm_notification_t_c(struct hostapd_data *hapd,
|
||||
const u8 *addr, const char *url)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
int ret;
|
||||
size_t url_len;
|
||||
|
||||
if (!url) {
|
||||
wpa_printf(MSG_INFO, "HS 2.0: No T&C Server URL available");
|
||||
return -1;
|
||||
}
|
||||
|
||||
url_len = os_strlen(url);
|
||||
if (5 + url_len > 255) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"HS 2.0: Too long T&C Server URL for WNM-Notification: '%s'",
|
||||
url);
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf = wpabuf_alloc(4 + 7 + url_len);
|
||||
if (!buf)
|
||||
return -1;
|
||||
|
||||
wpabuf_put_u8(buf, WLAN_ACTION_WNM);
|
||||
wpabuf_put_u8(buf, WNM_NOTIFICATION_REQ);
|
||||
wpabuf_put_u8(buf, 1); /* Dialog token */
|
||||
wpabuf_put_u8(buf, 1); /* Type - 1 reserved for WFA */
|
||||
|
||||
/* Terms and Conditions Acceptance subelement */
|
||||
wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
|
||||
wpabuf_put_u8(buf, 4 + 1 + url_len);
|
||||
wpabuf_put_be24(buf, OUI_WFA);
|
||||
wpabuf_put_u8(buf, HS20_WNM_T_C_ACCEPTANCE);
|
||||
wpabuf_put_u8(buf, url_len);
|
||||
wpabuf_put_str(buf, url);
|
||||
|
||||
ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
|
||||
wpabuf_head(buf), wpabuf_len(buf));
|
||||
|
||||
wpabuf_free(buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void hs20_t_c_filtering(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
int enabled)
|
||||
{
|
||||
if (enabled) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"HS 2.0: Terms and Conditions filtering required for "
|
||||
MACSTR, MAC2STR(sta->addr));
|
||||
sta->hs20_t_c_filtering = 1;
|
||||
/* TODO: Enable firewall filtering for the STA */
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, HS20_T_C_FILTERING_ADD MACSTR,
|
||||
MAC2STR(sta->addr));
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"HS 2.0: Terms and Conditions filtering not required for "
|
||||
MACSTR, MAC2STR(sta->addr));
|
||||
sta->hs20_t_c_filtering = 0;
|
||||
/* TODO: Disable firewall filtering for the STA */
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO,
|
||||
HS20_T_C_FILTERING_REMOVE MACSTR, MAC2STR(sta->addr));
|
||||
}
|
||||
}
|
||||
|
@ -18,5 +18,9 @@ int hs20_send_wnm_notification(struct hostapd_data *hapd, const u8 *addr,
|
||||
int hs20_send_wnm_notification_deauth_req(struct hostapd_data *hapd,
|
||||
const u8 *addr,
|
||||
const struct wpabuf *payload);
|
||||
int hs20_send_wnm_notification_t_c(struct hostapd_data *hapd,
|
||||
const u8 *addr, const char *url);
|
||||
void hs20_t_c_filtering(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
int enabled);
|
||||
|
||||
#endif /* HS20_H */
|
||||
|
@ -78,10 +78,12 @@ int hostapd_get_hw_features(struct hostapd_iface *iface)
|
||||
int i, j;
|
||||
u16 num_modes, flags;
|
||||
struct hostapd_hw_modes *modes;
|
||||
u8 dfs_domain;
|
||||
|
||||
if (hostapd_drv_none(hapd))
|
||||
return -1;
|
||||
modes = hostapd_get_hw_feature_data(hapd, &num_modes, &flags);
|
||||
modes = hostapd_get_hw_feature_data(hapd, &num_modes, &flags,
|
||||
&dfs_domain);
|
||||
if (modes == NULL) {
|
||||
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
@ -91,6 +93,7 @@ int hostapd_get_hw_features(struct hostapd_iface *iface)
|
||||
}
|
||||
|
||||
iface->hw_flags = flags;
|
||||
iface->dfs_domain = dfs_domain;
|
||||
|
||||
hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
|
||||
iface->hw_features = modes;
|
||||
@ -329,6 +332,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;
|
||||
res = 1;
|
||||
wpa_printf(MSG_INFO, "Fallback to 20 MHz");
|
||||
}
|
||||
@ -621,41 +627,6 @@ static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE80211AC
|
||||
|
||||
static int ieee80211ac_cap_check(u32 hw, u32 conf, u32 cap, const char *name)
|
||||
{
|
||||
u32 req_cap = conf & cap;
|
||||
|
||||
/*
|
||||
* Make sure we support all requested capabilities.
|
||||
* NOTE: We assume that 'cap' represents a capability mask,
|
||||
* not a discrete value.
|
||||
*/
|
||||
if ((hw & req_cap) != req_cap) {
|
||||
wpa_printf(MSG_ERROR, "Driver does not support configured VHT capability [%s]",
|
||||
name);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int ieee80211ac_cap_check_max(u32 hw, u32 conf, u32 mask,
|
||||
unsigned int shift,
|
||||
const char *name)
|
||||
{
|
||||
u32 hw_max = hw & mask;
|
||||
u32 conf_val = conf & mask;
|
||||
|
||||
if (conf_val > hw_max) {
|
||||
wpa_printf(MSG_ERROR, "Configured VHT capability [%s] exceeds max value supported by the driver (%d > %d)",
|
||||
name, conf_val >> shift, hw_max >> shift);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int ieee80211ac_supported_vht_capab(struct hostapd_iface *iface)
|
||||
{
|
||||
struct hostapd_hw_modes *mode = iface->current_mode;
|
||||
@ -683,45 +654,7 @@ static int ieee80211ac_supported_vht_capab(struct hostapd_iface *iface)
|
||||
}
|
||||
}
|
||||
|
||||
#define VHT_CAP_CHECK(cap) \
|
||||
do { \
|
||||
if (!ieee80211ac_cap_check(hw, conf, cap, #cap)) \
|
||||
return 0; \
|
||||
} while (0)
|
||||
|
||||
#define VHT_CAP_CHECK_MAX(cap) \
|
||||
do { \
|
||||
if (!ieee80211ac_cap_check_max(hw, conf, cap, cap ## _SHIFT, \
|
||||
#cap)) \
|
||||
return 0; \
|
||||
} while (0)
|
||||
|
||||
VHT_CAP_CHECK_MAX(VHT_CAP_MAX_MPDU_LENGTH_MASK);
|
||||
VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160MHZ);
|
||||
VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ);
|
||||
VHT_CAP_CHECK(VHT_CAP_RXLDPC);
|
||||
VHT_CAP_CHECK(VHT_CAP_SHORT_GI_80);
|
||||
VHT_CAP_CHECK(VHT_CAP_SHORT_GI_160);
|
||||
VHT_CAP_CHECK(VHT_CAP_TXSTBC);
|
||||
VHT_CAP_CHECK_MAX(VHT_CAP_RXSTBC_MASK);
|
||||
VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMER_CAPABLE);
|
||||
VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMEE_CAPABLE);
|
||||
VHT_CAP_CHECK_MAX(VHT_CAP_BEAMFORMEE_STS_MAX);
|
||||
VHT_CAP_CHECK_MAX(VHT_CAP_SOUNDING_DIMENSION_MAX);
|
||||
VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMER_CAPABLE);
|
||||
VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMEE_CAPABLE);
|
||||
VHT_CAP_CHECK(VHT_CAP_VHT_TXOP_PS);
|
||||
VHT_CAP_CHECK(VHT_CAP_HTC_VHT);
|
||||
VHT_CAP_CHECK_MAX(VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX);
|
||||
VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB);
|
||||
VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB);
|
||||
VHT_CAP_CHECK(VHT_CAP_RX_ANTENNA_PATTERN);
|
||||
VHT_CAP_CHECK(VHT_CAP_TX_ANTENNA_PATTERN);
|
||||
|
||||
#undef VHT_CAP_CHECK
|
||||
#undef VHT_CAP_CHECK_MAX
|
||||
|
||||
return 1;
|
||||
return ieee80211ac_cap_check(hw, conf);
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
|
||||
@ -746,7 +679,8 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface)
|
||||
if (!ieee80211n_supported_ht_capab(iface))
|
||||
return -1;
|
||||
#ifdef CONFIG_IEEE80211AC
|
||||
if (!ieee80211ac_supported_vht_capab(iface))
|
||||
if (iface->conf->ieee80211ac &&
|
||||
!ieee80211ac_supported_vht_capab(iface))
|
||||
return -1;
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
ret = ieee80211n_check_40mhz(iface);
|
||||
@ -785,20 +719,41 @@ static int hostapd_is_usable_chan(struct hostapd_iface *iface,
|
||||
chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : "");
|
||||
}
|
||||
|
||||
wpa_printf(MSG_INFO, "Channel %d (%s) not allowed for AP mode",
|
||||
channel, primary ? "primary" : "secondary");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_is_usable_chans(struct hostapd_iface *iface)
|
||||
{
|
||||
int secondary_chan;
|
||||
|
||||
if (!hostapd_is_usable_chan(iface, iface->conf->channel, 1))
|
||||
return 0;
|
||||
|
||||
if (!iface->conf->secondary_channel)
|
||||
return 1;
|
||||
|
||||
return hostapd_is_usable_chan(iface, iface->conf->channel +
|
||||
iface->conf->secondary_channel * 4, 0);
|
||||
if (!iface->conf->ht40_plus_minus_allowed)
|
||||
return hostapd_is_usable_chan(
|
||||
iface, iface->conf->channel +
|
||||
iface->conf->secondary_channel * 4, 0);
|
||||
|
||||
/* Both HT40+ and HT40- are set, pick a valid secondary channel */
|
||||
secondary_chan = iface->conf->channel + 4;
|
||||
if (hostapd_is_usable_chan(iface, secondary_chan, 0)) {
|
||||
iface->conf->secondary_channel = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
secondary_chan = iface->conf->channel - 4;
|
||||
if (hostapd_is_usable_chan(iface, secondary_chan, 0)) {
|
||||
iface->conf->secondary_channel = -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -978,5 +933,19 @@ int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan)
|
||||
|
||||
int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
|
||||
{
|
||||
return hw_get_chan(hapd->iface->current_mode, freq);
|
||||
int i, channel;
|
||||
struct hostapd_hw_modes *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. */
|
||||
for (i = 0; i < hapd->iface->num_hw_features; i++) {
|
||||
mode = &hapd->iface->hw_features[i];
|
||||
channel = hw_get_chan(mode, freq);
|
||||
if (channel)
|
||||
return channel;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -16,6 +16,8 @@ struct hostapd_frame_info;
|
||||
struct ieee80211_ht_capabilities;
|
||||
struct ieee80211_vht_capabilities;
|
||||
struct ieee80211_mgmt;
|
||||
struct vlan_description;
|
||||
struct hostapd_sta_wpa_psk_short;
|
||||
|
||||
int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
|
||||
struct hostapd_frame_info *fi);
|
||||
@ -55,6 +57,8 @@ 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_operation(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,
|
||||
@ -135,4 +139,31 @@ void ap_copy_sta_supp_op_classes(struct sta_info *sta,
|
||||
const u8 *supp_op_classes,
|
||||
size_t supp_op_classes_len);
|
||||
|
||||
u8 * hostapd_eid_fils_indic(struct hostapd_data *hapd, u8 *eid, int hessid);
|
||||
void ieee802_11_finish_fils_auth(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, int success,
|
||||
struct wpabuf *erp_resp,
|
||||
const u8 *msk, size_t msk_len);
|
||||
u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *owe_dh, u8 owe_dh_len,
|
||||
u8 *owe_buf, size_t owe_buf_len, u16 *reason);
|
||||
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,
|
||||
const u8 *pos, size_t len, u16 auth_alg,
|
||||
u16 auth_transaction, u16 status_code,
|
||||
void (*cb)(struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
u16 resp, struct wpabuf *data, int pub));
|
||||
|
||||
size_t hostapd_eid_owe_trans_len(struct hostapd_data *hapd);
|
||||
u8 * hostapd_eid_owe_trans(struct hostapd_data *hapd, u8 *eid, size_t len);
|
||||
int ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
|
||||
const u8 *msg, size_t len, u32 *session_timeout,
|
||||
u32 *acct_interim_interval,
|
||||
struct vlan_description *vlan_id,
|
||||
struct hostapd_sta_wpa_psk_short **psk,
|
||||
char **identity, char **radius_cui,
|
||||
int is_probe_req);
|
||||
|
||||
#endif /* IEEE802_11_H */
|
||||
|
@ -244,6 +244,7 @@ int hostapd_check_acl(struct hostapd_data *hapd, const u8 *addr,
|
||||
* @psk: Linked list buffer for returning WPA PSK
|
||||
* @identity: Buffer for returning identity (from RADIUS)
|
||||
* @radius_cui: Buffer for returning CUI (from RADIUS)
|
||||
* @is_probe_req: Whether this query for a Probe Request frame
|
||||
* Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
|
||||
*
|
||||
* The caller is responsible for freeing the returned *identity and *radius_cui
|
||||
@ -254,7 +255,8 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
|
||||
u32 *acct_interim_interval,
|
||||
struct vlan_description *vlan_id,
|
||||
struct hostapd_sta_wpa_psk_short **psk,
|
||||
char **identity, char **radius_cui)
|
||||
char **identity, char **radius_cui,
|
||||
int is_probe_req)
|
||||
{
|
||||
int res;
|
||||
|
||||
@ -281,6 +283,12 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
|
||||
#else /* CONFIG_NO_RADIUS */
|
||||
struct hostapd_acl_query_data *query;
|
||||
|
||||
if (is_probe_req) {
|
||||
/* Skip RADIUS queries for Probe Request frames to avoid
|
||||
* excessive load on the authentication server. */
|
||||
return HOSTAPD_ACL_ACCEPT;
|
||||
};
|
||||
|
||||
/* Check whether ACL cache has an entry for this station */
|
||||
res = hostapd_acl_cache_get(hapd, addr, session_timeout,
|
||||
acct_interim_interval, vlan_id, psk,
|
||||
@ -327,14 +335,13 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
|
||||
return HOSTAPD_ACL_REJECT;
|
||||
}
|
||||
|
||||
query->auth_msg = os_malloc(len);
|
||||
query->auth_msg = os_memdup(msg, len);
|
||||
if (query->auth_msg == NULL) {
|
||||
wpa_printf(MSG_ERROR, "Failed to allocate memory for "
|
||||
"auth frame.");
|
||||
hostapd_acl_query_free(query);
|
||||
return HOSTAPD_ACL_REJECT;
|
||||
}
|
||||
os_memcpy(query->auth_msg, msg, len);
|
||||
query->auth_msg_len = len;
|
||||
query->next = hapd->acl_queries;
|
||||
hapd->acl_queries = query;
|
||||
@ -665,9 +672,11 @@ void hostapd_acl_deinit(struct hostapd_data *hapd)
|
||||
|
||||
#ifndef CONFIG_NO_RADIUS
|
||||
hostapd_acl_cache_free(hapd->acl_cache);
|
||||
hapd->acl_cache = NULL;
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
|
||||
query = hapd->acl_queries;
|
||||
hapd->acl_queries = NULL;
|
||||
while (query) {
|
||||
prev = query;
|
||||
query = query->next;
|
||||
|
@ -23,7 +23,8 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
|
||||
u32 *acct_interim_interval,
|
||||
struct vlan_description *vlan_id,
|
||||
struct hostapd_sta_wpa_psk_short **psk,
|
||||
char **identity, char **radius_cui);
|
||||
char **identity, char **radius_cui,
|
||||
int is_probe_req);
|
||||
int hostapd_acl_init(struct hostapd_data *hapd);
|
||||
void hostapd_acl_deinit(struct hostapd_data *hapd);
|
||||
void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk);
|
||||
|
88
contrib/wpa/src/ap/ieee802_11_he.c
Normal file
88
contrib/wpa/src/ap/ieee802_11_he.c
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* hostapd / IEEE 802.11ax HE
|
||||
* Copyright (c) 2016-2017, Qualcomm Atheros, Inc.
|
||||
*
|
||||
* 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 "common/ieee802_11_defs.h"
|
||||
#include "hostapd.h"
|
||||
#include "ap_config.h"
|
||||
#include "beacon.h"
|
||||
#include "ieee802_11.h"
|
||||
#include "dfs.h"
|
||||
|
||||
u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid)
|
||||
{
|
||||
struct ieee80211_he_capabilities *cap;
|
||||
u8 *pos = eid;
|
||||
|
||||
if (!hapd->iface->current_mode)
|
||||
return eid;
|
||||
|
||||
*pos++ = WLAN_EID_EXTENSION;
|
||||
*pos++ = 1 + sizeof(struct ieee80211_he_capabilities);
|
||||
*pos++ = WLAN_EID_EXT_HE_CAPABILITIES;
|
||||
|
||||
cap = (struct ieee80211_he_capabilities *) pos;
|
||||
os_memset(cap, 0, sizeof(*cap));
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
pos += sizeof(*cap);
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid)
|
||||
{
|
||||
struct ieee80211_he_operation *oper;
|
||||
u8 *pos = eid;
|
||||
|
||||
if (!hapd->iface->current_mode)
|
||||
return eid;
|
||||
|
||||
*pos++ = WLAN_EID_EXTENSION;
|
||||
*pos++ = 1 + sizeof(struct ieee80211_he_operation);
|
||||
*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);
|
||||
|
||||
if (hapd->iface->conf->he_op.he_twt_required)
|
||||
oper->he_oper_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);
|
||||
|
||||
/* TODO: conditional MaxBSSID Indicator subfield */
|
||||
|
||||
pos += sizeof(*oper);
|
||||
|
||||
return pos;
|
||||
}
|
@ -236,17 +236,29 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd,
|
||||
int i;
|
||||
const u8 *start = (const u8 *) mgmt;
|
||||
const u8 *data = start + IEEE80211_HDRLEN + 2;
|
||||
struct sta_info *sta;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"HT: Received 20/40 BSS Coexistence Management frame from "
|
||||
MACSTR, MAC2STR(mgmt->sa));
|
||||
|
||||
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG, "hostapd_public_action - action=%d",
|
||||
mgmt->u.action.u.public_action.action);
|
||||
|
||||
if (!(iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
|
||||
if (!(iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Ignore 20/40 BSS Coexistence Management frame since 40 MHz capability is not enabled");
|
||||
return;
|
||||
}
|
||||
|
||||
if (len < IEEE80211_HDRLEN + 2 + sizeof(*bc_ie))
|
||||
if (len < IEEE80211_HDRLEN + 2 + sizeof(*bc_ie)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Ignore too short 20/40 BSS Coexistence Management frame");
|
||||
return;
|
||||
}
|
||||
|
||||
/* 20/40 BSS Coexistence element */
|
||||
bc_ie = (struct ieee80211_2040_bss_coex_ie *) data;
|
||||
if (bc_ie->element_id != WLAN_EID_20_40_BSS_COEXISTENCE ||
|
||||
bc_ie->length < 1) {
|
||||
@ -254,13 +266,35 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd,
|
||||
bc_ie->element_id, bc_ie->length);
|
||||
return;
|
||||
}
|
||||
if (len < IEEE80211_HDRLEN + 2 + 2 + bc_ie->length)
|
||||
if (len < IEEE80211_HDRLEN + 2 + 2 + bc_ie->length) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Truncated 20/40 BSS Coexistence element");
|
||||
return;
|
||||
}
|
||||
data += 2 + bc_ie->length;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "20/40 BSS Coexistence Information field: 0x%x",
|
||||
bc_ie->coex_param);
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"20/40 BSS Coexistence Information field: 0x%x (%s%s%s%s%s%s)",
|
||||
bc_ie->coex_param,
|
||||
(bc_ie->coex_param & BIT(0)) ? "[InfoReq]" : "",
|
||||
(bc_ie->coex_param & BIT(1)) ? "[40MHzIntolerant]" : "",
|
||||
(bc_ie->coex_param & BIT(2)) ? "[20MHzBSSWidthReq]" : "",
|
||||
(bc_ie->coex_param & BIT(3)) ? "[OBSSScanExemptionReq]" : "",
|
||||
(bc_ie->coex_param & BIT(4)) ?
|
||||
"[OBSSScanExemptionGrant]" : "",
|
||||
(bc_ie->coex_param & (BIT(5) | BIT(6) | BIT(7))) ?
|
||||
"[Reserved]" : "");
|
||||
|
||||
if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ) {
|
||||
/* Intra-BSS communication prohibiting 20/40 MHz BSS operation
|
||||
*/
|
||||
sta = ap_get_sta(hapd, mgmt->sa);
|
||||
if (!sta || !(sta->flags & WLAN_STA_ASSOC)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Ignore intra-BSS 20/40 BSS Coexistence Management frame from not-associated STA");
|
||||
return;
|
||||
}
|
||||
|
||||
hostapd_logger(hapd, mgmt->sa,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
@ -269,6 +303,8 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_40MHZ_INTOL) {
|
||||
/* Inter-BSS communication prohibiting 20/40 MHz BSS operation
|
||||
*/
|
||||
hostapd_logger(hapd, mgmt->sa,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
@ -276,12 +312,16 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd,
|
||||
is_ht40_allowed = 0;
|
||||
}
|
||||
|
||||
if (start + len - data >= 3 &&
|
||||
data[0] == WLAN_EID_20_40_BSS_INTOLERANT && data[1] >= 1) {
|
||||
/* 20/40 BSS Intolerant Channel Report element (zero or more times) */
|
||||
while (start + len - data >= 3 &&
|
||||
data[0] == WLAN_EID_20_40_BSS_INTOLERANT && data[1] >= 1) {
|
||||
u8 ielen = data[1];
|
||||
|
||||
if (ielen > start + len - data - 2)
|
||||
if (ielen > start + len - data - 2) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Truncated 20/40 BSS Intolerant Channel Report element");
|
||||
return;
|
||||
}
|
||||
ic_report = (struct ieee80211_2040_intol_chan_report *) data;
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"20/40 BSS Intolerant Channel Report: Operating Class %u",
|
||||
@ -292,8 +332,10 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd,
|
||||
for (i = 0; i < ielen - 1; i++) {
|
||||
u8 chan = ic_report->variable[i];
|
||||
|
||||
if (chan == iface->conf->channel)
|
||||
continue; /* matching own primary channel */
|
||||
if (is_40_allowed(iface, chan))
|
||||
continue;
|
||||
continue; /* not within affected channels */
|
||||
hostapd_logger(hapd, mgmt->sa,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
@ -301,6 +343,8 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd,
|
||||
chan);
|
||||
is_ht40_allowed = 0;
|
||||
}
|
||||
|
||||
data += 2 + ielen;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "is_ht40_allowed=%d num_sta_ht40_intolerant=%d",
|
||||
is_ht40_allowed, iface->num_sta_ht40_intolerant);
|
||||
@ -340,8 +384,8 @@ u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
* that did not specify a valid WMM IE in the (Re)Association Request
|
||||
* frame.
|
||||
*/
|
||||
if (!ht_capab ||
|
||||
!(sta->flags & WLAN_STA_WMM) || hapd->conf->disable_11n) {
|
||||
if (!ht_capab || !(sta->flags & WLAN_STA_WMM) ||
|
||||
!hapd->iconf->ieee80211n || hapd->conf->disable_11n) {
|
||||
sta->flags &= ~WLAN_STA_HT;
|
||||
os_free(sta->ht_capabilities);
|
||||
sta->ht_capabilities = NULL;
|
||||
|
@ -178,6 +178,10 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
|
||||
case 1: /* Bits 8-15 */
|
||||
if (hapd->conf->proxy_arp)
|
||||
*pos |= 0x10; /* Bit 12 - Proxy ARP */
|
||||
if (hapd->conf->coloc_intf_reporting) {
|
||||
/* Bit 13 - Collocated Interference Reporting */
|
||||
*pos |= 0x20;
|
||||
}
|
||||
break;
|
||||
case 2: /* Bits 16-23 */
|
||||
if (hapd->conf->wnm_sleep_mode)
|
||||
@ -186,9 +190,9 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
|
||||
*pos |= 0x08; /* Bit 19 - BSS Transition */
|
||||
break;
|
||||
case 3: /* Bits 24-31 */
|
||||
#ifdef CONFIG_WNM
|
||||
#ifdef CONFIG_WNM_AP
|
||||
*pos |= 0x02; /* Bit 25 - SSID List */
|
||||
#endif /* CONFIG_WNM */
|
||||
#endif /* CONFIG_WNM_AP */
|
||||
if (hapd->conf->time_advertisement == 2)
|
||||
*pos |= 0x08; /* Bit 27 - UTC TSF Offset */
|
||||
if (hapd->conf->interworking)
|
||||
@ -218,12 +222,21 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
|
||||
if (hapd->conf->ssid.utf8_ssid)
|
||||
*pos |= 0x01; /* Bit 48 - UTF-8 SSID */
|
||||
break;
|
||||
case 7: /* Bits 56-63 */
|
||||
break;
|
||||
case 8: /* Bits 64-71 */
|
||||
if (hapd->conf->ftm_responder)
|
||||
*pos |= 0x40; /* Bit 70 - FTM responder */
|
||||
if (hapd->conf->ftm_initiator)
|
||||
*pos |= 0x80; /* Bit 71 - FTM initiator */
|
||||
break;
|
||||
case 9: /* Bits 72-79 */
|
||||
#ifdef CONFIG_FILS
|
||||
if ((hapd->conf->wpa & WPA_PROTO_RSN) &&
|
||||
wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt))
|
||||
*pos |= 0x01;
|
||||
#endif /* CONFIG_FILS */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -246,10 +259,10 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
|
||||
if (len < 9 &&
|
||||
(hapd->conf->ftm_initiator || hapd->conf->ftm_responder))
|
||||
len = 9;
|
||||
#ifdef CONFIG_WNM
|
||||
#ifdef CONFIG_WNM_AP
|
||||
if (len < 4)
|
||||
len = 4;
|
||||
#endif /* CONFIG_WNM */
|
||||
#endif /* CONFIG_WNM_AP */
|
||||
#ifdef CONFIG_HS20
|
||||
if (hapd->conf->hs20 && len < 6)
|
||||
len = 6;
|
||||
@ -258,6 +271,11 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
|
||||
if (hapd->conf->mbo_enabled && len < 6)
|
||||
len = 6;
|
||||
#endif /* CONFIG_MBO */
|
||||
#ifdef CONFIG_FILS
|
||||
if ((!(hapd->conf->wpa & WPA_PROTO_RSN) ||
|
||||
!wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt)) && len < 10)
|
||||
len = 10;
|
||||
#endif /* CONFIG_FILS */
|
||||
if (len < hapd->iface->extended_capa_len)
|
||||
len = hapd->iface->extended_capa_len;
|
||||
if (len == 0)
|
||||
@ -432,7 +450,7 @@ u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
if (hapd->conf->time_advertisement != 2)
|
||||
if (hapd->conf->time_advertisement != 2 || !hapd->conf->time_zone)
|
||||
return eid;
|
||||
|
||||
len = os_strlen(hapd->conf->time_zone);
|
||||
@ -503,7 +521,7 @@ u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid)
|
||||
{
|
||||
u8 *pos = eid;
|
||||
|
||||
#ifdef CONFIG_WNM
|
||||
#ifdef CONFIG_WNM_AP
|
||||
if (hapd->conf->ap_max_inactivity > 0) {
|
||||
unsigned int val;
|
||||
*pos++ = WLAN_EID_BSS_MAX_IDLE_PERIOD;
|
||||
@ -521,7 +539,7 @@ u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid)
|
||||
pos += 2;
|
||||
*pos++ = 0x00; /* TODO: Protected Keep-Alive Required */
|
||||
}
|
||||
#endif /* CONFIG_WNM */
|
||||
#endif /* CONFIG_WNM_AP */
|
||||
|
||||
return pos;
|
||||
}
|
||||
@ -531,23 +549,38 @@ u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid)
|
||||
|
||||
u8 * hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid, size_t len)
|
||||
{
|
||||
u8 mbo[6], *mbo_pos = mbo;
|
||||
u8 mbo[9], *mbo_pos = mbo;
|
||||
u8 *pos = eid;
|
||||
|
||||
if (!hapd->conf->mbo_enabled)
|
||||
if (!hapd->conf->mbo_enabled &&
|
||||
!OCE_STA_CFON_ENABLED(hapd) && !OCE_AP_ENABLED(hapd))
|
||||
return eid;
|
||||
|
||||
*mbo_pos++ = MBO_ATTR_ID_AP_CAPA_IND;
|
||||
*mbo_pos++ = 1;
|
||||
/* Not Cellular aware */
|
||||
*mbo_pos++ = 0;
|
||||
if (hapd->conf->mbo_enabled) {
|
||||
*mbo_pos++ = MBO_ATTR_ID_AP_CAPA_IND;
|
||||
*mbo_pos++ = 1;
|
||||
/* Not Cellular aware */
|
||||
*mbo_pos++ = 0;
|
||||
}
|
||||
|
||||
if (hapd->mbo_assoc_disallow) {
|
||||
if (hapd->conf->mbo_enabled && hapd->mbo_assoc_disallow) {
|
||||
*mbo_pos++ = MBO_ATTR_ID_ASSOC_DISALLOW;
|
||||
*mbo_pos++ = 1;
|
||||
*mbo_pos++ = hapd->mbo_assoc_disallow;
|
||||
}
|
||||
|
||||
if (OCE_STA_CFON_ENABLED(hapd) || OCE_AP_ENABLED(hapd)) {
|
||||
u8 ctrl;
|
||||
|
||||
ctrl = OCE_RELEASE;
|
||||
if (OCE_STA_CFON_ENABLED(hapd) && !OCE_AP_ENABLED(hapd))
|
||||
ctrl |= OCE_IS_STA_CFON;
|
||||
|
||||
*mbo_pos++ = OCE_ATTR_ID_CAPA_IND;
|
||||
*mbo_pos++ = 1;
|
||||
*mbo_pos++ = ctrl;
|
||||
}
|
||||
|
||||
pos += mbo_add_ie(pos, len, mbo, mbo_pos - mbo);
|
||||
|
||||
return pos;
|
||||
@ -556,19 +589,91 @@ u8 * hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid, size_t len)
|
||||
|
||||
u8 hostapd_mbo_ie_len(struct hostapd_data *hapd)
|
||||
{
|
||||
if (!hapd->conf->mbo_enabled)
|
||||
u8 len;
|
||||
|
||||
if (!hapd->conf->mbo_enabled &&
|
||||
!OCE_STA_CFON_ENABLED(hapd) && !OCE_AP_ENABLED(hapd))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* MBO IE header (6) + Capability Indication attribute (3) +
|
||||
* Association Disallowed attribute (3) = 12
|
||||
*/
|
||||
return 6 + 3 + (hapd->mbo_assoc_disallow ? 3 : 0);
|
||||
len = 6;
|
||||
if (hapd->conf->mbo_enabled)
|
||||
len += 3 + (hapd->mbo_assoc_disallow ? 3 : 0);
|
||||
|
||||
/* OCE capability indication attribute (3) */
|
||||
if (OCE_STA_CFON_ENABLED(hapd) || OCE_AP_ENABLED(hapd))
|
||||
len += 3;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MBO */
|
||||
|
||||
|
||||
#ifdef CONFIG_OWE
|
||||
static int hostapd_eid_owe_trans_enabled(struct hostapd_data *hapd)
|
||||
{
|
||||
return hapd->conf->owe_transition_ssid_len > 0 &&
|
||||
!is_zero_ether_addr(hapd->conf->owe_transition_bssid);
|
||||
}
|
||||
#endif /* CONFIG_OWE */
|
||||
|
||||
|
||||
size_t hostapd_eid_owe_trans_len(struct hostapd_data *hapd)
|
||||
{
|
||||
#ifdef CONFIG_OWE
|
||||
if (!hostapd_eid_owe_trans_enabled(hapd))
|
||||
return 0;
|
||||
return 6 + ETH_ALEN + 1 + hapd->conf->owe_transition_ssid_len;
|
||||
#else /* CONFIG_OWE */
|
||||
return 0;
|
||||
#endif /* CONFIG_OWE */
|
||||
}
|
||||
|
||||
|
||||
u8 * hostapd_eid_owe_trans(struct hostapd_data *hapd, u8 *eid,
|
||||
size_t len)
|
||||
{
|
||||
#ifdef CONFIG_OWE
|
||||
u8 *pos = eid;
|
||||
size_t elen;
|
||||
|
||||
if (hapd->conf->owe_transition_ifname[0] &&
|
||||
!hostapd_eid_owe_trans_enabled(hapd))
|
||||
hostapd_owe_trans_get_info(hapd);
|
||||
|
||||
if (!hostapd_eid_owe_trans_enabled(hapd))
|
||||
return pos;
|
||||
|
||||
elen = hostapd_eid_owe_trans_len(hapd);
|
||||
if (len < elen) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"OWE: Not enough room in the buffer for OWE IE");
|
||||
return pos;
|
||||
}
|
||||
|
||||
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
|
||||
*pos++ = elen - 2;
|
||||
WPA_PUT_BE24(pos, OUI_WFA);
|
||||
pos += 3;
|
||||
*pos++ = OWE_OUI_TYPE;
|
||||
os_memcpy(pos, hapd->conf->owe_transition_bssid, ETH_ALEN);
|
||||
pos += ETH_ALEN;
|
||||
*pos++ = hapd->conf->owe_transition_ssid_len;
|
||||
os_memcpy(pos, hapd->conf->owe_transition_ssid,
|
||||
hapd->conf->owe_transition_ssid_len);
|
||||
pos += hapd->conf->owe_transition_ssid_len;
|
||||
|
||||
return pos;
|
||||
#else /* CONFIG_OWE */
|
||||
return eid;
|
||||
#endif /* CONFIG_OWE */
|
||||
}
|
||||
|
||||
|
||||
void ap_copy_sta_supp_op_classes(struct sta_info *sta,
|
||||
const u8 *supp_op_classes,
|
||||
size_t supp_op_classes_len)
|
||||
@ -584,3 +689,66 @@ void ap_copy_sta_supp_op_classes(struct sta_info *sta,
|
||||
os_memcpy(sta->supp_op_classes + 1, supp_op_classes,
|
||||
supp_op_classes_len);
|
||||
}
|
||||
|
||||
|
||||
u8 * hostapd_eid_fils_indic(struct hostapd_data *hapd, u8 *eid, int hessid)
|
||||
{
|
||||
u8 *pos = eid;
|
||||
#ifdef CONFIG_FILS
|
||||
u8 *len;
|
||||
u16 fils_info = 0;
|
||||
size_t realms;
|
||||
struct fils_realm *realm;
|
||||
|
||||
if (!(hapd->conf->wpa & WPA_PROTO_RSN) ||
|
||||
!wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt))
|
||||
return pos;
|
||||
|
||||
realms = dl_list_len(&hapd->conf->fils_realms);
|
||||
if (realms > 7)
|
||||
realms = 7; /* 3 bit count field limits this to max 7 */
|
||||
|
||||
*pos++ = WLAN_EID_FILS_INDICATION;
|
||||
len = pos++;
|
||||
/* TODO: B0..B2: Number of Public Key Identifiers */
|
||||
if (hapd->conf->erp_domain) {
|
||||
/* B3..B5: Number of Realm Identifiers */
|
||||
fils_info |= realms << 3;
|
||||
}
|
||||
/* TODO: B6: FILS IP Address Configuration */
|
||||
if (hapd->conf->fils_cache_id_set)
|
||||
fils_info |= BIT(7);
|
||||
if (hessid && !is_zero_ether_addr(hapd->conf->hessid))
|
||||
fils_info |= BIT(8); /* HESSID Included */
|
||||
/* FILS Shared Key Authentication without PFS Supported */
|
||||
fils_info |= BIT(9);
|
||||
if (hapd->conf->fils_dh_group) {
|
||||
/* FILS Shared Key Authentication with PFS Supported */
|
||||
fils_info |= BIT(10);
|
||||
}
|
||||
/* TODO: B11: FILS Public Key Authentication Supported */
|
||||
/* B12..B15: Reserved */
|
||||
WPA_PUT_LE16(pos, fils_info);
|
||||
pos += 2;
|
||||
if (hapd->conf->fils_cache_id_set) {
|
||||
os_memcpy(pos, hapd->conf->fils_cache_id, FILS_CACHE_ID_LEN);
|
||||
pos += FILS_CACHE_ID_LEN;
|
||||
}
|
||||
if (hessid && !is_zero_ether_addr(hapd->conf->hessid)) {
|
||||
os_memcpy(pos, hapd->conf->hessid, ETH_ALEN);
|
||||
pos += ETH_ALEN;
|
||||
}
|
||||
|
||||
dl_list_for_each(realm, &hapd->conf->fils_realms, struct fils_realm,
|
||||
list) {
|
||||
if (realms == 0)
|
||||
break;
|
||||
realms--;
|
||||
os_memcpy(pos, realm->hash, 2);
|
||||
pos += 2;
|
||||
}
|
||||
*len = pos - len - 1;
|
||||
#endif /* CONFIG_FILS */
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user