Import wpa_supplicant/hostapd 2.6.
This commit is contained in:
parent
b834757ea3
commit
256810032c
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor/wpa/dist/; revision=324714 svn path=/vendor/wpa/2.6/; revision=324715; tag=vendor/wpa/2.6
@ -29,6 +29,34 @@ using your real name. Pseudonyms or anonymous contributions cannot
|
||||
unfortunately be accepted.
|
||||
|
||||
|
||||
The preferred method of submitting the contribution to the project is by
|
||||
email to the hostap mailing list:
|
||||
hostap@lists.infradead.org
|
||||
Note that the list may require subscription before accepting message
|
||||
without moderation. You can subscribe to the list at this address:
|
||||
http://lists.infradead.org/mailman/listinfo/hostap
|
||||
|
||||
The message should contain an inlined patch against the current
|
||||
development branch (i.e., the master branch of
|
||||
git://w1.fi/hostap.git). Please make sure the software you use for
|
||||
sending the patch does not corrupt whitespace. If that cannot be fixed
|
||||
for some reason, it is better to include an attached version of the
|
||||
patch file than just send a whitespace damaged version in the message
|
||||
body.
|
||||
|
||||
The patches should be separate logical changes rather than doing
|
||||
everything in a single patch. In other words, please keep cleanup, new
|
||||
features, and bug fixes all in their own patches. Each patch needs a
|
||||
commit log that describes the changes (what the changes fix, what
|
||||
functionality is added, why the changes are useful, etc.).
|
||||
|
||||
Please try to follow the coding style used in the project.
|
||||
|
||||
In general, the best way of generating a suitable formatted patch file
|
||||
is by committing the changes to a cloned git repository and using git
|
||||
format-patch. The patch can then be sent, e.g., with git send-email.
|
||||
|
||||
|
||||
History of license and contributions terms
|
||||
------------------------------------------
|
||||
|
||||
@ -112,7 +140,7 @@ The license terms used for hostap.git files
|
||||
|
||||
Modified BSD license (no advertisement clause):
|
||||
|
||||
Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> and contributors
|
||||
Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> and contributors
|
||||
All Rights Reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
2
COPYING
2
COPYING
@ -1,7 +1,7 @@
|
||||
wpa_supplicant and hostapd
|
||||
--------------------------
|
||||
|
||||
Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> and contributors
|
||||
Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> and contributors
|
||||
All Rights Reserved.
|
||||
|
||||
|
||||
|
2
README
2
README
@ -1,7 +1,7 @@
|
||||
wpa_supplicant and hostapd
|
||||
--------------------------
|
||||
|
||||
Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> and contributors
|
||||
Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> and contributors
|
||||
All Rights Reserved.
|
||||
|
||||
These programs are licensed under the BSD license (the one with
|
||||
|
1001
hostapd/Android.mk
Normal file
1001
hostapd/Android.mk
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,78 @@
|
||||
ChangeLog for hostapd
|
||||
|
||||
2016-10-02 - v2.6
|
||||
* fixed EAP-pwd last fragment validation
|
||||
[http://w1.fi/security/2015-7/] (CVE-2015-5314)
|
||||
* fixed WPS configuration update vulnerability with malformed passphrase
|
||||
[http://w1.fi/security/2016-1/] (CVE-2016-4476)
|
||||
* extended channel switch support for VHT bandwidth changes
|
||||
* added support for configuring new ANQP-elements with
|
||||
anqp_elem=<InfoID>:<hexdump of payload>
|
||||
* fixed Suite B 192-bit AKM to use proper PMK length
|
||||
(note: this makes old releases incompatible with the fixed behavior)
|
||||
* added no_probe_resp_if_max_sta=1 parameter to disable Probe Response
|
||||
frame sending for not-associated STAs if max_num_sta limit has been
|
||||
reached
|
||||
* added option (-S as command line argument) to request all interfaces
|
||||
to be started at the same time
|
||||
* modified rts_threshold and fragm_threshold configuration parameters
|
||||
to allow -1 to be used to disable RTS/fragmentation
|
||||
* EAP-pwd: added support for Brainpool Elliptic Curves
|
||||
(with OpenSSL 1.0.2 and newer)
|
||||
* fixed EAPOL reauthentication after FT protocol run
|
||||
* fixed FTIE generation for 4-way handshake after FT protocol run
|
||||
* fixed and improved various FST operations
|
||||
* TLS server
|
||||
- support SHA384 and SHA512 hashes
|
||||
- support TLS v1.2 signature algorithm with SHA384 and SHA512
|
||||
- support PKCS #5 v2.0 PBES2
|
||||
- support PKCS #5 with PKCS #12 style key decryption
|
||||
- minimal support for PKCS #12
|
||||
- support OCSP stapling (including ocsp_multi)
|
||||
* added support for OpenSSL 1.1 API changes
|
||||
- drop support for OpenSSL 0.9.8
|
||||
- drop support for OpenSSL 1.0.0
|
||||
* EAP-PEAP: support fast-connect crypto binding
|
||||
* RADIUS
|
||||
- fix Called-Station-Id to not escape SSID
|
||||
- add Event-Timestamp to all Accounting-Request packets
|
||||
- add Acct-Session-Id to Accounting-On/Off
|
||||
- add Acct-Multi-Session-Id ton Access-Request packets
|
||||
- add Service-Type (= Frames)
|
||||
- allow server to provide PSK instead of passphrase for WPA-PSK
|
||||
Tunnel_password case
|
||||
- update full message for interim accounting updates
|
||||
- add Acct-Delay-Time into Accounting messages
|
||||
- add require_message_authenticator configuration option to require
|
||||
CoA/Disconnect-Request packets to be authenticated
|
||||
* started to postpone WNM-Notification frame sending by 100 ms so that
|
||||
the STA has some more time to configure the key before this frame is
|
||||
received after the 4-way handshake
|
||||
* VHT: added interoperability workaround for 80+80 and 160 MHz channels
|
||||
* extended VLAN support (per-STA vif, etc.)
|
||||
* fixed PMKID derivation with SAE
|
||||
* nl80211
|
||||
- added support for full station state operations
|
||||
- fix IEEE 802.1X/WEP EAP reauthentication and rekeying to use
|
||||
unencrypted EAPOL frames
|
||||
* added initial MBO support; number of extensions to WNM BSS Transition
|
||||
Management
|
||||
* added initial functionality for location related operations
|
||||
* added assocresp_elements parameter to allow vendor specific elements
|
||||
to be added into (Re)Association Response frames
|
||||
* improved Public Action frame addressing
|
||||
- use Address 3 = wildcard BSSID in GAS response if a query from an
|
||||
unassociated STA used that address
|
||||
- fix TX status processing for Address 3 = wildcard BSSID
|
||||
- add gas_address3 configuration parameter to control Address 3
|
||||
behavior
|
||||
* added command line parameter -i to override interface parameter in
|
||||
hostapd.conf
|
||||
* added command completion support to hostapd_cli
|
||||
* added passive client taxonomy determination (CONFIG_TAXONOMY=y
|
||||
compile option and "SIGNATURE <addr>" control interface command)
|
||||
* number of small fixes
|
||||
|
||||
2015-09-27 - v2.5
|
||||
* fixed WPS UPnP vulnerability with HTTP chunked transfer encoding
|
||||
[http://w1.fi/security/2015-2/] (CVE-2015-4141)
|
||||
|
106
hostapd/Makefile
106
hostapd/Makefile
@ -6,18 +6,39 @@ ifndef CFLAGS
|
||||
CFLAGS = -MMD -O2 -Wall -g
|
||||
endif
|
||||
|
||||
ifdef LIBS
|
||||
# If LIBS is set with some global build system defaults, clone those for
|
||||
# LIBS_c, LIBS_h, and LIBS_n to cover hostapd_cli, hlr_auc_gw, and
|
||||
# nt_password_hash as well.
|
||||
ifndef LIBS_c
|
||||
LIBS_c := $(LIBS)
|
||||
endif
|
||||
ifndef LIBS_h
|
||||
LIBS_h := $(LIBS)
|
||||
endif
|
||||
ifndef LIBS_n
|
||||
LIBS_n := $(LIBS)
|
||||
endif
|
||||
endif
|
||||
|
||||
CFLAGS += $(EXTRA_CFLAGS)
|
||||
CFLAGS += -I$(abspath ../src)
|
||||
CFLAGS += -I$(abspath ../src/utils)
|
||||
|
||||
export BINDIR ?= /usr/local/bin/
|
||||
|
||||
# Uncomment following line and set the path to your kernel tree include
|
||||
# directory if your C library does not include all header files.
|
||||
# CFLAGS += -DUSE_KERNEL_HEADERS -I/usr/src/linux/include
|
||||
|
||||
-include .config
|
||||
|
||||
ifndef CONFIG_NO_GITVER
|
||||
# Add VERSION_STR postfix for builds from a git repository
|
||||
ifeq ($(wildcard ../.git),../.git)
|
||||
GITVER := $(shell git describe --dirty=+)
|
||||
ifneq ($(GITVER),)
|
||||
CFLAGS += -DGIT_VERSION_STR_POSTFIX=\"-$(GITVER)\"
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef CONFIG_TESTING_OPTIONS
|
||||
CFLAGS += -DCONFIG_TESTING_OPTIONS
|
||||
CONFIG_WPS_TESTING=y
|
||||
@ -63,8 +84,13 @@ OBJS += ../src/ap/pmksa_cache_auth.o
|
||||
OBJS += ../src/ap/ieee802_11_shared.o
|
||||
OBJS += ../src/ap/beacon.o
|
||||
OBJS += ../src/ap/bss_load.o
|
||||
OBJS += ../src/ap/neighbor_db.o
|
||||
OBJS += ../src/ap/rrm.o
|
||||
|
||||
OBJS_c = hostapd_cli.o ../src/common/wpa_ctrl.o ../src/utils/os_$(CONFIG_OS).o
|
||||
OBJS_c = hostapd_cli.o
|
||||
OBJS_c += ../src/common/wpa_ctrl.o
|
||||
OBJS_c += ../src/utils/os_$(CONFIG_OS).o
|
||||
OBJS_c += ../src/common/cli.o
|
||||
|
||||
NEED_RC4=y
|
||||
NEED_AES=y
|
||||
@ -74,6 +100,11 @@ NEED_SHA1=y
|
||||
OBJS += ../src/drivers/drivers.o
|
||||
CFLAGS += -DHOSTAPD
|
||||
|
||||
ifdef CONFIG_TAXONOMY
|
||||
CFLAGS += -DCONFIG_TAXONOMY
|
||||
OBJS += ../src/ap/taxonomy.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_MODULE_TESTS
|
||||
CFLAGS += -DCONFIG_MODULE_TESTS
|
||||
OBJS += hapd_module_tests.o
|
||||
@ -115,6 +146,10 @@ ifdef CONFIG_ELOOP_EPOLL
|
||||
CFLAGS += -DCONFIG_ELOOP_EPOLL
|
||||
endif
|
||||
|
||||
ifdef CONFIG_ELOOP_KQUEUE
|
||||
CFLAGS += -DCONFIG_ELOOP_KQUEUE
|
||||
endif
|
||||
|
||||
OBJS += ../src/utils/common.o
|
||||
OBJS_c += ../src/utils/common.o
|
||||
OBJS += ../src/utils/wpa_debug.o
|
||||
@ -165,22 +200,53 @@ ifdef CONFIG_NO_VLAN
|
||||
CFLAGS += -DCONFIG_NO_VLAN
|
||||
else
|
||||
OBJS += ../src/ap/vlan_init.o
|
||||
ifdef CONFIG_VLAN_NETLINK
|
||||
OBJS += ../src/ap/vlan_ifconfig.o
|
||||
OBJS += ../src/ap/vlan.o
|
||||
ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||
# Define CONFIG_FULL_DYNAMIC_VLAN to have hostapd manipulate bridges
|
||||
# and VLAN interfaces for the VLAN feature.
|
||||
CFLAGS += -DCONFIG_FULL_DYNAMIC_VLAN
|
||||
OBJS += ../src/ap/vlan_full.o
|
||||
ifdef CONFIG_VLAN_NETLINK
|
||||
OBJS += ../src/ap/vlan_util.o
|
||||
else
|
||||
OBJS += ../src/ap/vlan_ioctl.o
|
||||
endif
|
||||
CFLAGS += -DCONFIG_VLAN_NETLINK
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef CONFIG_NO_CTRL_IFACE
|
||||
CFLAGS += -DCONFIG_NO_CTRL_IFACE
|
||||
else
|
||||
ifeq ($(CONFIG_CTRL_IFACE), udp)
|
||||
CFLAGS += -DCONFIG_CTRL_IFACE_UDP
|
||||
else
|
||||
ifeq ($(CONFIG_CTRL_IFACE), udp6)
|
||||
CFLAGS += -DCONFIG_CTRL_IFACE_UDP
|
||||
CFLAGS += -DCONFIG_CTRL_IFACE_UDP_IPV6
|
||||
else
|
||||
ifeq ($(CONFIG_CTRL_IFACE), udp-remote)
|
||||
CFLAGS += -DCONFIG_CTRL_IFACE_UDP
|
||||
CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE
|
||||
else
|
||||
ifeq ($(CONFIG_CTRL_IFACE), udp6-remote)
|
||||
CFLAGS += -DCONFIG_CTRL_IFACE_UDP
|
||||
CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE
|
||||
CFLAGS += -DCONFIG_CTRL_IFACE_UDP_IPV6
|
||||
else
|
||||
CFLAGS += -DCONFIG_CTRL_IFACE_UNIX
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
OBJS += ../src/common/ctrl_iface_common.o
|
||||
OBJS += ctrl_iface.o
|
||||
OBJS += ../src/ap/ctrl_iface_ap.o
|
||||
endif
|
||||
|
||||
CFLAGS += -DCONFIG_CTRL_IFACE -DCONFIG_CTRL_IFACE_UNIX
|
||||
ifndef CONFIG_NO_CTRL_IFACE
|
||||
CFLAGS += -DCONFIG_CTRL_IFACE
|
||||
endif
|
||||
|
||||
ifdef CONFIG_IAPP
|
||||
CFLAGS += -DCONFIG_IAPP
|
||||
@ -252,6 +318,11 @@ ifdef CONFIG_IEEE80211AC
|
||||
CFLAGS += -DCONFIG_IEEE80211AC
|
||||
endif
|
||||
|
||||
ifdef CONFIG_MBO
|
||||
CFLAGS += -DCONFIG_MBO
|
||||
OBJS += ../src/ap/mbo_ap.o
|
||||
endif
|
||||
|
||||
include ../src/drivers/drivers.mak
|
||||
OBJS += $(DRV_AP_OBJS)
|
||||
CFLAGS += $(DRV_AP_CFLAGS)
|
||||
@ -534,6 +605,7 @@ endif
|
||||
ifeq ($(CONFIG_TLS), openssl)
|
||||
ifdef TLS_FUNCS
|
||||
OBJS += ../src/crypto/tls_openssl.o
|
||||
OBJS += ../src/crypto/tls_openssl_ocsp.o
|
||||
LIBS += -lssl
|
||||
endif
|
||||
OBJS += ../src/crypto/crypto_openssl.o
|
||||
@ -634,6 +706,8 @@ CONFIG_INTERNAL_SHA1=y
|
||||
CONFIG_INTERNAL_MD4=y
|
||||
CONFIG_INTERNAL_MD5=y
|
||||
CONFIG_INTERNAL_SHA256=y
|
||||
CONFIG_INTERNAL_SHA384=y
|
||||
CONFIG_INTERNAL_SHA512=y
|
||||
CONFIG_INTERNAL_RC4=y
|
||||
CONFIG_INTERNAL_DH_GROUP5=y
|
||||
endif
|
||||
@ -794,6 +868,16 @@ CFLAGS += -DCONFIG_SHA384
|
||||
OBJS += ../src/crypto/sha384-prf.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_INTERNAL_SHA384
|
||||
CFLAGS += -DCONFIG_INTERNAL_SHA384
|
||||
OBJS += ../src/crypto/sha384-internal.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_INTERNAL_SHA512
|
||||
CFLAGS += -DCONFIG_INTERNAL_SHA512
|
||||
OBJS += ../src/crypto/sha512-internal.o
|
||||
endif
|
||||
|
||||
ifdef NEED_DH_GROUPS
|
||||
OBJS += ../src/crypto/dh_groups.o
|
||||
endif
|
||||
@ -835,12 +919,6 @@ ifdef CONFIG_DRIVER_RADIUS_ACL
|
||||
CFLAGS += -DCONFIG_DRIVER_RADIUS_ACL
|
||||
endif
|
||||
|
||||
ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||
# define CONFIG_FULL_DYNAMIC_VLAN to have hostapd manipulate bridges
|
||||
# and vlan interfaces for the vlan feature.
|
||||
CFLAGS += -DCONFIG_FULL_DYNAMIC_VLAN
|
||||
endif
|
||||
|
||||
ifdef NEED_BASE64
|
||||
OBJS += ../src/utils/base64.o
|
||||
endif
|
||||
|
@ -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-2015, Jouni Malinen <j@w1.fi> and contributors
|
||||
Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> and contributors
|
||||
All Rights Reserved.
|
||||
|
||||
This program is licensed under the BSD license (the one with
|
||||
|
201
hostapd/android.config
Normal file
201
hostapd/android.config
Normal file
@ -0,0 +1,201 @@
|
||||
# Example hostapd build time configuration
|
||||
#
|
||||
# This file lists the configuration options that are used when building the
|
||||
# hostapd binary. All lines starting with # are ignored. Configuration option
|
||||
# lines must be commented out complete, if they are not to be included, i.e.,
|
||||
# just setting VARIABLE=n is not disabling that variable.
|
||||
#
|
||||
# This file is included in Makefile, so variables like CFLAGS and LIBS can also
|
||||
# be modified from here. In most cass, these lines should use += in order not
|
||||
# to override previous values of the variables.
|
||||
|
||||
# Driver interface for Host AP driver
|
||||
#CONFIG_DRIVER_HOSTAP=y
|
||||
|
||||
# Driver interface for wired authenticator
|
||||
#CONFIG_DRIVER_WIRED=y
|
||||
|
||||
# Driver interface for drivers using the nl80211 kernel interface
|
||||
#CONFIG_DRIVER_NL80211=y
|
||||
# driver_nl80211.c requires a rather new libnl (version 1.1) which may not be
|
||||
# shipped with your distribution yet. If that is the case, you need to build
|
||||
# newer libnl version and point the hostapd build to use it.
|
||||
#LIBNL=/usr/src/libnl
|
||||
#CFLAGS += -I$(LIBNL)/include
|
||||
#LIBS += -L$(LIBNL)/lib
|
||||
CONFIG_LIBNL20=y
|
||||
|
||||
# QCA vendor extensions to nl80211
|
||||
CONFIG_DRIVER_NL80211_QCA=y
|
||||
|
||||
# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
|
||||
#CONFIG_DRIVER_BSD=y
|
||||
#CFLAGS += -I/usr/local/include
|
||||
#LIBS += -L/usr/local/lib
|
||||
#LIBS_p += -L/usr/local/lib
|
||||
#LIBS_c += -L/usr/local/lib
|
||||
|
||||
# Driver interface for no driver (e.g., RADIUS server only)
|
||||
#CONFIG_DRIVER_NONE=y
|
||||
|
||||
# IEEE 802.11F/IAPP
|
||||
#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)
|
||||
# This version is an experimental implementation based on IEEE 802.11w/D1.0
|
||||
# draft and is subject to change since the standard has not yet been finalized.
|
||||
# Driver support is also needed for IEEE 802.11w.
|
||||
CONFIG_IEEE80211W=y
|
||||
|
||||
# Integrated EAP server
|
||||
#CONFIG_EAP=y
|
||||
|
||||
# EAP-MD5 for the integrated EAP server
|
||||
#CONFIG_EAP_MD5=y
|
||||
|
||||
# EAP-TLS for the integrated EAP server
|
||||
#CONFIG_EAP_TLS=y
|
||||
|
||||
# EAP-MSCHAPv2 for the integrated EAP server
|
||||
#CONFIG_EAP_MSCHAPV2=y
|
||||
|
||||
# EAP-PEAP for the integrated EAP server
|
||||
#CONFIG_EAP_PEAP=y
|
||||
|
||||
# EAP-GTC for the integrated EAP server
|
||||
#CONFIG_EAP_GTC=y
|
||||
|
||||
# EAP-TTLS for the integrated EAP server
|
||||
#CONFIG_EAP_TTLS=y
|
||||
|
||||
# EAP-SIM for the integrated EAP server
|
||||
#CONFIG_EAP_SIM=y
|
||||
|
||||
# EAP-AKA for the integrated EAP server
|
||||
#CONFIG_EAP_AKA=y
|
||||
|
||||
# EAP-AKA' for the integrated EAP server
|
||||
# This requires CONFIG_EAP_AKA to be enabled, too.
|
||||
#CONFIG_EAP_AKA_PRIME=y
|
||||
|
||||
# EAP-PAX for the integrated EAP server
|
||||
#CONFIG_EAP_PAX=y
|
||||
|
||||
# EAP-PSK for the integrated EAP server (this is _not_ needed for WPA-PSK)
|
||||
#CONFIG_EAP_PSK=y
|
||||
|
||||
# EAP-SAKE for the integrated EAP server
|
||||
#CONFIG_EAP_SAKE=y
|
||||
|
||||
# EAP-GPSK for the integrated EAP server
|
||||
#CONFIG_EAP_GPSK=y
|
||||
# Include support for optional SHA256 cipher suite in EAP-GPSK
|
||||
#CONFIG_EAP_GPSK_SHA256=y
|
||||
|
||||
# EAP-FAST for the integrated EAP server
|
||||
# Note: Default OpenSSL package does not include support for all the
|
||||
# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
|
||||
# the OpenSSL library must be patched (openssl-0.9.9-session-ticket.patch)
|
||||
# to add the needed functions.
|
||||
#CONFIG_EAP_FAST=y
|
||||
|
||||
# Wi-Fi Protected Setup (WPS)
|
||||
CONFIG_WPS=y
|
||||
# Enable UPnP support for external WPS Registrars
|
||||
#CONFIG_WPS_UPNP=y
|
||||
|
||||
# EAP-IKEv2
|
||||
#CONFIG_EAP_IKEV2=y
|
||||
|
||||
# Trusted Network Connect (EAP-TNC)
|
||||
#CONFIG_EAP_TNC=y
|
||||
|
||||
# PKCS#12 (PFX) support (used to read private key and certificate file from
|
||||
# a file that usually has extension .p12 or .pfx)
|
||||
CONFIG_PKCS12=y
|
||||
|
||||
# RADIUS authentication server. This provides access to the integrated EAP
|
||||
# server from external hosts using RADIUS.
|
||||
#CONFIG_RADIUS_SERVER=y
|
||||
|
||||
# Build IPv6 support for RADIUS operations
|
||||
CONFIG_IPV6=y
|
||||
|
||||
# IEEE Std 802.11r-2008 (Fast BSS Transition)
|
||||
#CONFIG_IEEE80211R=y
|
||||
|
||||
# Use the hostapd's IEEE 802.11 authentication (ACL), but without
|
||||
# the IEEE 802.11 Management capability (e.g., FreeBSD/net80211)
|
||||
#CONFIG_DRIVER_RADIUS_ACL=y
|
||||
|
||||
# IEEE 802.11n (High Throughput) support
|
||||
CONFIG_IEEE80211N=y
|
||||
|
||||
# Remove debugging code that is printing out debug messages to stdout.
|
||||
# This can be used to reduce the size of the hostapd considerably if debugging
|
||||
# code is not needed.
|
||||
#CONFIG_NO_STDOUT_DEBUG=y
|
||||
|
||||
# Add support for writing debug log to Android logcat instead of standard output
|
||||
CONFIG_ANDROID_LOG=y
|
||||
|
||||
# Remove support for RADIUS accounting
|
||||
#CONFIG_NO_ACCOUNTING=y
|
||||
|
||||
# Remove support for RADIUS
|
||||
CONFIG_NO_RADIUS=y
|
||||
|
||||
# Remove support for VLANs
|
||||
#CONFIG_NO_VLAN=y
|
||||
|
||||
# Remove support for dumping internal state through control interface commands
|
||||
# This can be used to reduce binary size at the cost of disabling a debugging
|
||||
# option.
|
||||
#CONFIG_NO_DUMP_STATE=y
|
||||
|
||||
# Select wrapper for operatins system and C library specific functions
|
||||
# unix = UNIX/POSIX like systems (default)
|
||||
# win32 = Windows systems
|
||||
# none = Empty template
|
||||
CONFIG_OS=unix
|
||||
|
||||
# Enable tracing code for developer debugging
|
||||
# This tracks use of memory allocations and other registrations and reports
|
||||
# incorrect use with a backtrace of call (or allocation) location.
|
||||
#CONFIG_WPA_TRACE=y
|
||||
# For BSD, comment out these.
|
||||
#LIBS += -lexecinfo
|
||||
#LIBS_p += -lexecinfo
|
||||
#LIBS_c += -lexecinfo
|
||||
|
||||
# Use libbfd to get more details for developer debugging
|
||||
# This enables use of libbfd to get more detailed symbols for the backtraces
|
||||
# generated by CONFIG_WPA_TRACE=y.
|
||||
#CONFIG_WPA_TRACE_BFD=y
|
||||
# For BSD, comment out these.
|
||||
#LIBS += -lbfd -liberty -lz
|
||||
#LIBS_p += -lbfd -liberty -lz
|
||||
#LIBS_c += -lbfd -liberty -lz
|
||||
|
||||
# Should we use poll instead of select? Select is used by default.
|
||||
#CONFIG_ELOOP_POLL=y
|
||||
|
||||
# Should we use epoll instead of select? Select is used by default.
|
||||
#CONFIG_ELOOP_EPOLL=y
|
||||
|
||||
# Enable AP
|
||||
CONFIG_AP=y
|
||||
|
||||
# Enable Fast Session Transfer (FST)
|
||||
#CONFIG_FST=y
|
||||
|
||||
# Multiband Operation support
|
||||
# These extentions facilitate efficient use of multiple frequency bands
|
||||
# available to the AP and the devices that may associate with it.
|
||||
#CONFIG_MBO=y
|
@ -97,6 +97,8 @@ static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
|
||||
}
|
||||
|
||||
vlan->vlan_id = vlan_id;
|
||||
vlan->vlan_desc.untagged = vlan_id;
|
||||
vlan->vlan_desc.notempty = !!vlan_id;
|
||||
os_strlcpy(vlan->ifname, pos, sizeof(vlan->ifname));
|
||||
vlan->next = bss->vlan;
|
||||
bss->vlan = vlan;
|
||||
@ -197,7 +199,10 @@ static int hostapd_config_read_maclist(const char *fname,
|
||||
|
||||
*acl = newacl;
|
||||
os_memcpy((*acl)[*num].addr, addr, ETH_ALEN);
|
||||
(*acl)[*num].vlan_id = vlan_id;
|
||||
os_memset(&(*acl)[*num].vlan_id, 0,
|
||||
sizeof((*acl)[*num].vlan_id));
|
||||
(*acl)[*num].vlan_id.untagged = vlan_id;
|
||||
(*acl)[*num].vlan_id.notempty = !!vlan_id;
|
||||
(*num)++;
|
||||
}
|
||||
|
||||
@ -631,8 +636,7 @@ hostapd_parse_radius_attr(const char *value)
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_parse_das_client(struct hostapd_bss_config *bss,
|
||||
const char *val)
|
||||
static int hostapd_parse_das_client(struct hostapd_bss_config *bss, char *val)
|
||||
{
|
||||
char *secret;
|
||||
|
||||
@ -640,7 +644,7 @@ static int hostapd_parse_das_client(struct hostapd_bss_config *bss,
|
||||
if (secret == NULL)
|
||||
return -1;
|
||||
|
||||
secret++;
|
||||
*secret++ = '\0';
|
||||
|
||||
if (hostapd_parse_ip_addr(val, &bss->radius_das_client_addr))
|
||||
return -1;
|
||||
@ -1519,6 +1523,54 @@ static int parse_nai_realm(struct hostapd_bss_config *bss, char *buf, int line)
|
||||
}
|
||||
|
||||
|
||||
static int parse_anqp_elem(struct hostapd_bss_config *bss, char *buf, int line)
|
||||
{
|
||||
char *delim;
|
||||
u16 infoid;
|
||||
size_t len;
|
||||
struct wpabuf *payload;
|
||||
struct anqp_element *elem;
|
||||
|
||||
delim = os_strchr(buf, ':');
|
||||
if (!delim)
|
||||
return -1;
|
||||
delim++;
|
||||
infoid = atoi(buf);
|
||||
len = os_strlen(delim);
|
||||
if (len & 1)
|
||||
return -1;
|
||||
len /= 2;
|
||||
payload = wpabuf_alloc(len);
|
||||
if (!payload)
|
||||
return -1;
|
||||
if (hexstr2bin(delim, wpabuf_put(payload, len), len) < 0) {
|
||||
wpabuf_free(payload);
|
||||
return -1;
|
||||
}
|
||||
|
||||
dl_list_for_each(elem, &bss->anqp_elem, struct anqp_element, list) {
|
||||
if (elem->infoid == infoid) {
|
||||
/* Update existing entry */
|
||||
wpabuf_free(elem->payload);
|
||||
elem->payload = payload;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add a new entry */
|
||||
elem = os_zalloc(sizeof(*elem));
|
||||
if (!elem) {
|
||||
wpabuf_free(payload);
|
||||
return -1;
|
||||
}
|
||||
elem->infoid = infoid;
|
||||
elem->payload = payload;
|
||||
dl_list_add(&bss->anqp_elem, &elem->list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int parse_qos_map_set(struct hostapd_bss_config *bss,
|
||||
char *buf, int line)
|
||||
{
|
||||
@ -1867,31 +1919,6 @@ static int hs20_parse_osu_service_desc(struct hostapd_bss_config *bss,
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
|
||||
#ifdef CONFIG_WPS_NFC
|
||||
static struct wpabuf * hostapd_parse_bin(const char *buf)
|
||||
{
|
||||
size_t len;
|
||||
struct wpabuf *ret;
|
||||
|
||||
len = os_strlen(buf);
|
||||
if (len & 0x01)
|
||||
return NULL;
|
||||
len /= 2;
|
||||
|
||||
ret = wpabuf_alloc(len);
|
||||
if (ret == NULL)
|
||||
return NULL;
|
||||
|
||||
if (hexstr2bin(buf, wpabuf_put(ret, len), len)) {
|
||||
wpabuf_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_WPS_NFC */
|
||||
|
||||
|
||||
#ifdef CONFIG_ACS
|
||||
static int hostapd_config_parse_acs_chan_bias(struct hostapd_config *conf,
|
||||
char *pos)
|
||||
@ -1934,6 +1961,31 @@ static int hostapd_config_parse_acs_chan_bias(struct hostapd_config *conf,
|
||||
#endif /* CONFIG_ACS */
|
||||
|
||||
|
||||
static int parse_wpabuf_hex(int line, const char *name, struct wpabuf **buf,
|
||||
const char *val)
|
||||
{
|
||||
struct wpabuf *elems;
|
||||
|
||||
if (val[0] == '\0') {
|
||||
wpabuf_free(*buf);
|
||||
*buf = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
elems = wpabuf_parse_bin(val);
|
||||
if (!elems) {
|
||||
wpa_printf(MSG_ERROR, "Line %d: Invalid %s '%s'",
|
||||
line, name, val);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpabuf_free(*buf);
|
||||
*buf = elems;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
struct hostapd_bss_config *bss,
|
||||
const char *buf, char *pos, int line)
|
||||
@ -2084,6 +2136,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
} else if (os_strcmp(buf, "ocsp_stapling_response") == 0) {
|
||||
os_free(bss->ocsp_stapling_response);
|
||||
bss->ocsp_stapling_response = os_strdup(pos);
|
||||
} else if (os_strcmp(buf, "ocsp_stapling_response_multi") == 0) {
|
||||
os_free(bss->ocsp_stapling_response_multi);
|
||||
bss->ocsp_stapling_response_multi = os_strdup(pos);
|
||||
} else if (os_strcmp(buf, "dh_file") == 0) {
|
||||
os_free(bss->dh_file);
|
||||
bss->dh_file = os_strdup(pos);
|
||||
@ -2139,6 +2194,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
} else if (os_strcmp(buf, "eap_sim_db") == 0) {
|
||||
os_free(bss->eap_sim_db);
|
||||
bss->eap_sim_db = os_strdup(pos);
|
||||
} else if (os_strcmp(buf, "eap_sim_db_timeout") == 0) {
|
||||
bss->eap_sim_db_timeout = atoi(pos);
|
||||
} else if (os_strcmp(buf, "eap_sim_aka_result_ind") == 0) {
|
||||
bss->eap_sim_aka_result_ind = atoi(pos);
|
||||
#endif /* EAP_SERVER_SIM */
|
||||
@ -2353,6 +2410,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
bss->radius_das_time_window = atoi(pos);
|
||||
} else if (os_strcmp(buf, "radius_das_require_event_timestamp") == 0) {
|
||||
bss->radius_das_require_event_timestamp = atoi(pos);
|
||||
} else if (os_strcmp(buf, "radius_das_require_message_authenticator") ==
|
||||
0) {
|
||||
bss->radius_das_require_message_authenticator = atoi(pos);
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
} else if (os_strcmp(buf, "auth_algs") == 0) {
|
||||
bss->auth_algs = atoi(pos);
|
||||
@ -2644,7 +2704,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
}
|
||||
} else if (os_strcmp(buf, "rts_threshold") == 0) {
|
||||
conf->rts_threshold = atoi(pos);
|
||||
if (conf->rts_threshold < 0 || conf->rts_threshold > 2347) {
|
||||
if (conf->rts_threshold < -1 || conf->rts_threshold > 65535) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: invalid rts_threshold %d",
|
||||
line, conf->rts_threshold);
|
||||
@ -2652,8 +2712,10 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
}
|
||||
} else if (os_strcmp(buf, "fragm_threshold") == 0) {
|
||||
conf->fragm_threshold = atoi(pos);
|
||||
if (conf->fragm_threshold < 256 ||
|
||||
conf->fragm_threshold > 2346) {
|
||||
if (conf->fragm_threshold == -1) {
|
||||
/* allow a value of -1 */
|
||||
} else if (conf->fragm_threshold < 256 ||
|
||||
conf->fragm_threshold > 2346) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: invalid fragm_threshold %d",
|
||||
line, conf->fragm_threshold);
|
||||
@ -2686,6 +2748,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
conf->preamble = LONG_PREAMBLE;
|
||||
} else if (os_strcmp(buf, "ignore_broadcast_ssid") == 0) {
|
||||
bss->ignore_broadcast_ssid = atoi(pos);
|
||||
} else if (os_strcmp(buf, "no_probe_resp_if_max_sta") == 0) {
|
||||
bss->no_probe_resp_if_max_sta = atoi(pos);
|
||||
} else if (os_strcmp(buf, "wep_default_key") == 0) {
|
||||
bss->ssid.wep.idx = atoi(pos);
|
||||
if (bss->ssid.wep.idx > 3) {
|
||||
@ -2707,6 +2771,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
#ifndef CONFIG_NO_VLAN
|
||||
} else if (os_strcmp(buf, "dynamic_vlan") == 0) {
|
||||
bss->ssid.dynamic_vlan = atoi(pos);
|
||||
} else if (os_strcmp(buf, "per_sta_vif") == 0) {
|
||||
bss->ssid.per_sta_vif = atoi(pos);
|
||||
} else if (os_strcmp(buf, "vlan_file") == 0) {
|
||||
if (hostapd_config_read_vlan_file(bss, pos)) {
|
||||
wpa_printf(MSG_ERROR, "Line %d: failed to read VLAN file '%s'",
|
||||
@ -2762,6 +2828,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
line);
|
||||
return 1;
|
||||
}
|
||||
} else if (os_strcmp(buf, "use_driver_iface_addr") == 0) {
|
||||
conf->use_driver_iface_addr = atoi(pos);
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
} else if (os_strcmp(buf, "ieee80211w") == 0) {
|
||||
bss->ieee80211w = atoi(pos);
|
||||
@ -2827,6 +2895,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
conf->vht_oper_centr_freq_seg1_idx = atoi(pos);
|
||||
} else if (os_strcmp(buf, "vendor_vht") == 0) {
|
||||
bss->vendor_vht = atoi(pos);
|
||||
} else if (os_strcmp(buf, "use_sta_nsts") == 0) {
|
||||
bss->use_sta_nsts = atoi(pos);
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
} else if (os_strcmp(buf, "max_listen_interval") == 0) {
|
||||
bss->max_listen_interval = atoi(pos);
|
||||
@ -2965,15 +3035,15 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
bss->wps_nfc_pw_from_config = 1;
|
||||
} else if (os_strcmp(buf, "wps_nfc_dh_pubkey") == 0) {
|
||||
wpabuf_free(bss->wps_nfc_dh_pubkey);
|
||||
bss->wps_nfc_dh_pubkey = hostapd_parse_bin(pos);
|
||||
bss->wps_nfc_dh_pubkey = wpabuf_parse_bin(pos);
|
||||
bss->wps_nfc_pw_from_config = 1;
|
||||
} else if (os_strcmp(buf, "wps_nfc_dh_privkey") == 0) {
|
||||
wpabuf_free(bss->wps_nfc_dh_privkey);
|
||||
bss->wps_nfc_dh_privkey = hostapd_parse_bin(pos);
|
||||
bss->wps_nfc_dh_privkey = wpabuf_parse_bin(pos);
|
||||
bss->wps_nfc_pw_from_config = 1;
|
||||
} else if (os_strcmp(buf, "wps_nfc_dev_pw") == 0) {
|
||||
wpabuf_free(bss->wps_nfc_dev_pw);
|
||||
bss->wps_nfc_dev_pw = hostapd_parse_bin(pos);
|
||||
bss->wps_nfc_dev_pw = wpabuf_parse_bin(pos);
|
||||
bss->wps_nfc_pw_from_config = 1;
|
||||
#endif /* CONFIG_WPS_NFC */
|
||||
#endif /* CONFIG_WPS */
|
||||
@ -3136,6 +3206,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
} else if (os_strcmp(buf, "nai_realm") == 0) {
|
||||
if (parse_nai_realm(bss, pos, line) < 0)
|
||||
return 1;
|
||||
} else if (os_strcmp(buf, "anqp_elem") == 0) {
|
||||
if (parse_anqp_elem(bss, pos, line) < 0)
|
||||
return 1;
|
||||
} else if (os_strcmp(buf, "gas_frag_limit") == 0) {
|
||||
bss->gas_frag_limit = atoi(pos);
|
||||
} else if (os_strcmp(buf, "gas_comeback_delay") == 0) {
|
||||
@ -3149,13 +3222,15 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
os_free(bss->dump_msk_file);
|
||||
bss->dump_msk_file = os_strdup(pos);
|
||||
#endif /* CONFIG_RADIUS_TEST */
|
||||
#ifdef CONFIG_PROXYARP
|
||||
} else if (os_strcmp(buf, "proxy_arp") == 0) {
|
||||
bss->proxy_arp = atoi(pos);
|
||||
#endif /* CONFIG_PROXYARP */
|
||||
#ifdef CONFIG_HS20
|
||||
} else if (os_strcmp(buf, "hs20") == 0) {
|
||||
bss->hs20 = atoi(pos);
|
||||
} else if (os_strcmp(buf, "disable_dgaf") == 0) {
|
||||
bss->disable_dgaf = atoi(pos);
|
||||
} else if (os_strcmp(buf, "proxy_arp") == 0) {
|
||||
bss->proxy_arp = atoi(pos);
|
||||
} else if (os_strcmp(buf, "na_mcast_to_ucast") == 0) {
|
||||
bss->na_mcast_to_ucast = atoi(pos);
|
||||
} else if (os_strcmp(buf, "osen") == 0) {
|
||||
@ -3231,6 +3306,10 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
} else if (os_strcmp(buf, "subscr_remediation_method") == 0) {
|
||||
bss->subscr_remediation_method = atoi(pos);
|
||||
#endif /* CONFIG_HS20 */
|
||||
#ifdef CONFIG_MBO
|
||||
} else if (os_strcmp(buf, "mbo") == 0) {
|
||||
bss->mbo_enabled = atoi(pos);
|
||||
#endif /* CONFIG_MBO */
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
#define PARSE_TEST_PROBABILITY(_val) \
|
||||
} else if (os_strcmp(buf, #_val) == 0) { \
|
||||
@ -3249,6 +3328,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
PARSE_TEST_PROBABILITY(ignore_assoc_probability)
|
||||
PARSE_TEST_PROBABILITY(ignore_reassoc_probability)
|
||||
PARSE_TEST_PROBABILITY(corrupt_gtk_rekey_mic_probability)
|
||||
} else if (os_strcmp(buf, "ecsa_ie_only") == 0) {
|
||||
conf->ecsa_ie_only = atoi(pos);
|
||||
} else if (os_strcmp(buf, "bss_load_test") == 0) {
|
||||
WPA_PUT_LE16(bss->bss_load_test, atoi(pos));
|
||||
pos = os_strchr(pos, ':');
|
||||
@ -3269,7 +3350,15 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
WPA_PUT_LE16(&bss->bss_load_test[3], atoi(pos));
|
||||
bss->bss_load_test_set = 1;
|
||||
} else if (os_strcmp(buf, "radio_measurements") == 0) {
|
||||
bss->radio_measurements = atoi(pos);
|
||||
/*
|
||||
* DEPRECATED: This parameter will be removed in the future.
|
||||
* Use rrm_neighbor_report instead.
|
||||
*/
|
||||
int val = atoi(pos);
|
||||
|
||||
if (val & BIT(0))
|
||||
bss->radio_measurements[0] |=
|
||||
WLAN_RRM_CAPS_NEIGHBOR_REPORT;
|
||||
} else if (os_strcmp(buf, "own_ie_override") == 0) {
|
||||
struct wpabuf *tmp;
|
||||
size_t len = os_strlen(pos) / 2;
|
||||
@ -3290,35 +3379,11 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
bss->own_ie_override = tmp;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
} else if (os_strcmp(buf, "vendor_elements") == 0) {
|
||||
struct wpabuf *elems;
|
||||
size_t len = os_strlen(pos);
|
||||
if (len & 0x01) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: Invalid vendor_elements '%s'",
|
||||
line, pos);
|
||||
if (parse_wpabuf_hex(line, buf, &bss->vendor_elements, pos))
|
||||
return 1;
|
||||
}
|
||||
len /= 2;
|
||||
if (len == 0) {
|
||||
wpabuf_free(bss->vendor_elements);
|
||||
bss->vendor_elements = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
elems = wpabuf_alloc(len);
|
||||
if (elems == NULL)
|
||||
} else if (os_strcmp(buf, "assocresp_elements") == 0) {
|
||||
if (parse_wpabuf_hex(line, buf, &bss->assocresp_elements, pos))
|
||||
return 1;
|
||||
|
||||
if (hexstr2bin(pos, wpabuf_put(elems, len), len)) {
|
||||
wpabuf_free(elems);
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: Invalid vendor_elements '%s'",
|
||||
line, pos);
|
||||
return 1;
|
||||
}
|
||||
|
||||
wpabuf_free(bss->vendor_elements);
|
||||
bss->vendor_elements = elems;
|
||||
} else if (os_strcmp(buf, "sae_anti_clogging_threshold") == 0) {
|
||||
bss->sae_anti_clogging_threshold = atoi(pos);
|
||||
} else if (os_strcmp(buf, "sae_groups") == 0) {
|
||||
@ -3391,7 +3456,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
return -1;
|
||||
}
|
||||
val = strtol(pos, &endp, 0);
|
||||
if (*endp || val < 1 || val > FST_MAX_LLT_MS) {
|
||||
if (*endp || val < 1 ||
|
||||
(unsigned long int) val > FST_MAX_LLT_MS) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: Invalid fst_llt %ld (%s) (expected 1..%u)",
|
||||
line, val, pos, FST_MAX_LLT_MS);
|
||||
@ -3409,6 +3475,22 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||
} else if (os_strcmp(buf, "no_auth_if_seen_on") == 0) {
|
||||
os_free(bss->no_auth_if_seen_on);
|
||||
bss->no_auth_if_seen_on = os_strdup(pos);
|
||||
} else if (os_strcmp(buf, "lci") == 0) {
|
||||
wpabuf_free(conf->lci);
|
||||
conf->lci = wpabuf_parse_bin(pos);
|
||||
} else if (os_strcmp(buf, "civic") == 0) {
|
||||
wpabuf_free(conf->civic);
|
||||
conf->civic = wpabuf_parse_bin(pos);
|
||||
} else if (os_strcmp(buf, "rrm_neighbor_report") == 0) {
|
||||
if (atoi(pos))
|
||||
bss->radio_measurements[0] |=
|
||||
WLAN_RRM_CAPS_NEIGHBOR_REPORT;
|
||||
} else if (os_strcmp(buf, "gas_address3") == 0) {
|
||||
bss->gas_address3 = atoi(pos);
|
||||
} else if (os_strcmp(buf, "ftm_responder") == 0) {
|
||||
bss->ftm_responder = atoi(pos);
|
||||
} else if (os_strcmp(buf, "ftm_initiator") == 0) {
|
||||
bss->ftm_initiator = atoi(pos);
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Line %d: unknown configuration item '%s'",
|
||||
@ -3429,7 +3511,7 @@ struct hostapd_config * hostapd_config_read(const char *fname)
|
||||
{
|
||||
struct hostapd_config *conf;
|
||||
FILE *f;
|
||||
char buf[512], *pos;
|
||||
char buf[4096], *pos;
|
||||
int line = 0;
|
||||
int errors = 0;
|
||||
size_t i;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -18,6 +18,9 @@ CONFIG_DRIVER_HOSTAP=y
|
||||
# Driver interface for drivers using the nl80211 kernel interface
|
||||
CONFIG_DRIVER_NL80211=y
|
||||
|
||||
# QCA vendor extensions to nl80211
|
||||
#CONFIG_DRIVER_NL80211_QCA=y
|
||||
|
||||
# driver_nl80211.c requires libnl. If you are compiling it yourself
|
||||
# you may need to point hostapd to your version of libnl.
|
||||
#
|
||||
@ -246,6 +249,9 @@ CONFIG_IPV6=y
|
||||
# Should we use epoll instead of select? Select is used by default.
|
||||
#CONFIG_ELOOP_EPOLL=y
|
||||
|
||||
# Should we use kqueue instead of select? Select is used by default.
|
||||
#CONFIG_ELOOP_KQUEUE=y
|
||||
|
||||
# Select TLS implementation
|
||||
# openssl = OpenSSL (default)
|
||||
# gnutls = GnuTLS
|
||||
@ -326,3 +332,14 @@ CONFIG_IPV6=y
|
||||
# http://wireless.kernel.org/en/users/Documentation/acs
|
||||
#
|
||||
#CONFIG_ACS=y
|
||||
|
||||
# Multiband Operation support
|
||||
# These extentions facilitate efficient use of multiple frequency bands
|
||||
# available to the AP and the devices that may associate with it.
|
||||
#CONFIG_MBO=y
|
||||
|
||||
# Client Taxonomy
|
||||
# Has the AP retain the Probe Request and (Re)Association Request frames from
|
||||
# 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
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "utils/module_tests.h"
|
||||
|
||||
int hapd_module_tests(void)
|
||||
{
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator
|
||||
* Copyright (c) 2005-2007, 2012-2013, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2005-2007, 2012-2016, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -284,7 +284,7 @@ static int read_gsm_triplets(const char *fname)
|
||||
|
||||
f = fopen(fname, "r");
|
||||
if (f == NULL) {
|
||||
printf("Could not open GSM tripler data file '%s'\n", fname);
|
||||
printf("Could not open GSM triplet data file '%s'\n", fname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -312,66 +312,40 @@ static int read_gsm_triplets(const char *fname)
|
||||
}
|
||||
|
||||
/* IMSI */
|
||||
pos2 = strchr(pos, ':');
|
||||
if (pos2 == NULL) {
|
||||
printf("%s:%d - Invalid IMSI (%s)\n",
|
||||
fname, line, pos);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
*pos2 = '\0';
|
||||
if (strlen(pos) >= sizeof(g->imsi)) {
|
||||
printf("%s:%d - Too long IMSI (%s)\n",
|
||||
fname, line, pos);
|
||||
pos2 = NULL;
|
||||
pos = str_token(buf, ":", &pos2);
|
||||
if (!pos || os_strlen(pos) >= sizeof(g->imsi)) {
|
||||
printf("%s:%d - Invalid IMSI\n", fname, line);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
os_strlcpy(g->imsi, pos, sizeof(g->imsi));
|
||||
pos = pos2 + 1;
|
||||
|
||||
/* Kc */
|
||||
pos2 = strchr(pos, ':');
|
||||
if (pos2 == NULL) {
|
||||
printf("%s:%d - Invalid Kc (%s)\n", fname, line, pos);
|
||||
pos = str_token(buf, ":", &pos2);
|
||||
if (!pos || os_strlen(pos) != 16 || hexstr2bin(pos, g->kc, 8)) {
|
||||
printf("%s:%d - Invalid Kc\n", fname, line);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
*pos2 = '\0';
|
||||
if (strlen(pos) != 16 || hexstr2bin(pos, g->kc, 8)) {
|
||||
printf("%s:%d - Invalid Kc (%s)\n", fname, line, pos);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
pos = pos2 + 1;
|
||||
|
||||
/* SRES */
|
||||
pos2 = strchr(pos, ':');
|
||||
if (pos2 == NULL) {
|
||||
printf("%s:%d - Invalid SRES (%s)\n", fname, line,
|
||||
pos);
|
||||
pos = str_token(buf, ":", &pos2);
|
||||
if (!pos || os_strlen(pos) != 8 ||
|
||||
hexstr2bin(pos, g->sres, 4)) {
|
||||
printf("%s:%d - Invalid SRES\n", fname, line);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
*pos2 = '\0';
|
||||
if (strlen(pos) != 8 || hexstr2bin(pos, g->sres, 4)) {
|
||||
printf("%s:%d - Invalid SRES (%s)\n", fname, line,
|
||||
pos);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
pos = pos2 + 1;
|
||||
|
||||
/* RAND */
|
||||
pos2 = strchr(pos, ':');
|
||||
if (pos2)
|
||||
*pos2 = '\0';
|
||||
if (strlen(pos) != 32 || hexstr2bin(pos, g->_rand, 16)) {
|
||||
printf("%s:%d - Invalid RAND (%s)\n", fname, line,
|
||||
pos);
|
||||
pos = str_token(buf, ":", &pos2);
|
||||
if (!pos || os_strlen(pos) != 32 ||
|
||||
hexstr2bin(pos, g->_rand, 16)) {
|
||||
printf("%s:%d - Invalid RAND\n", fname, line);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
pos = pos2 + 1;
|
||||
|
||||
g->next = gsm_db;
|
||||
gsm_db = g;
|
||||
@ -450,86 +424,58 @@ static int read_milenage(const char *fname)
|
||||
}
|
||||
|
||||
/* IMSI */
|
||||
pos2 = strchr(pos, ' ');
|
||||
if (pos2 == NULL) {
|
||||
printf("%s:%d - Invalid IMSI (%s)\n",
|
||||
fname, line, pos);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
*pos2 = '\0';
|
||||
if (strlen(pos) >= sizeof(m->imsi)) {
|
||||
printf("%s:%d - Too long IMSI (%s)\n",
|
||||
fname, line, pos);
|
||||
pos2 = NULL;
|
||||
pos = str_token(buf, " ", &pos2);
|
||||
if (!pos || os_strlen(pos) >= sizeof(m->imsi)) {
|
||||
printf("%s:%d - Invalid IMSI\n", fname, line);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
os_strlcpy(m->imsi, pos, sizeof(m->imsi));
|
||||
pos = pos2 + 1;
|
||||
|
||||
/* Ki */
|
||||
pos2 = strchr(pos, ' ');
|
||||
if (pos2 == NULL) {
|
||||
printf("%s:%d - Invalid Ki (%s)\n", fname, line, pos);
|
||||
pos = str_token(buf, " ", &pos2);
|
||||
if (!pos || os_strlen(pos) != 32 ||
|
||||
hexstr2bin(pos, m->ki, 16)) {
|
||||
printf("%s:%d - Invalid Ki\n", fname, line);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
*pos2 = '\0';
|
||||
if (strlen(pos) != 32 || hexstr2bin(pos, m->ki, 16)) {
|
||||
printf("%s:%d - Invalid Ki (%s)\n", fname, line, pos);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
pos = pos2 + 1;
|
||||
|
||||
/* OPc */
|
||||
pos2 = strchr(pos, ' ');
|
||||
if (pos2 == NULL) {
|
||||
printf("%s:%d - Invalid OPc (%s)\n", fname, line, pos);
|
||||
pos = str_token(buf, " ", &pos2);
|
||||
if (!pos || os_strlen(pos) != 32 ||
|
||||
hexstr2bin(pos, m->opc, 16)) {
|
||||
printf("%s:%d - Invalid OPc\n", fname, line);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
*pos2 = '\0';
|
||||
if (strlen(pos) != 32 || hexstr2bin(pos, m->opc, 16)) {
|
||||
printf("%s:%d - Invalid OPc (%s)\n", fname, line, pos);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
pos = pos2 + 1;
|
||||
|
||||
/* AMF */
|
||||
pos2 = strchr(pos, ' ');
|
||||
if (pos2 == NULL) {
|
||||
printf("%s:%d - Invalid AMF (%s)\n", fname, line, pos);
|
||||
pos = str_token(buf, " ", &pos2);
|
||||
if (!pos || os_strlen(pos) != 4 || hexstr2bin(pos, m->amf, 2)) {
|
||||
printf("%s:%d - Invalid AMF\n", fname, line);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
*pos2 = '\0';
|
||||
if (strlen(pos) != 4 || hexstr2bin(pos, m->amf, 2)) {
|
||||
printf("%s:%d - Invalid AMF (%s)\n", fname, line, pos);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
pos = pos2 + 1;
|
||||
|
||||
/* SQN */
|
||||
pos2 = strchr(pos, ' ');
|
||||
if (pos2)
|
||||
*pos2 = '\0';
|
||||
if (strlen(pos) != 12 || hexstr2bin(pos, m->sqn, 6)) {
|
||||
printf("%s:%d - Invalid SEQ (%s)\n", fname, line, pos);
|
||||
pos = str_token(buf, " ", &pos2);
|
||||
if (!pos || os_strlen(pos) != 12 ||
|
||||
hexstr2bin(pos, m->sqn, 6)) {
|
||||
printf("%s:%d - Invalid SEQ\n", fname, line);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (pos2) {
|
||||
pos = pos2 + 1;
|
||||
pos = str_token(buf, " ", &pos2);
|
||||
if (pos) {
|
||||
m->res_len = atoi(pos);
|
||||
if (m->res_len &&
|
||||
(m->res_len < EAP_AKA_RES_MIN_LEN ||
|
||||
m->res_len > EAP_AKA_RES_MAX_LEN)) {
|
||||
printf("%s:%d - Invalid RES_len (%s)\n",
|
||||
fname, line, pos);
|
||||
printf("%s:%d - Invalid RES_len\n",
|
||||
fname, line);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
@ -1027,7 +973,7 @@ static void usage(void)
|
||||
{
|
||||
printf("HLR/AuC testing gateway for hostapd EAP-SIM/AKA "
|
||||
"database/authenticator\n"
|
||||
"Copyright (c) 2005-2007, 2012-2013, Jouni Malinen <j@w1.fi>\n"
|
||||
"Copyright (c) 2005-2016, Jouni Malinen <j@w1.fi>\n"
|
||||
"\n"
|
||||
"usage:\n"
|
||||
"hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] "
|
||||
|
20
hostapd/hostapd.android.rc
Normal file
20
hostapd/hostapd.android.rc
Normal file
@ -0,0 +1,20 @@
|
||||
#
|
||||
# init.rc fragment for hostapd on Android
|
||||
# Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi>
|
||||
#
|
||||
# This software may be distributed under the terms of the BSD license.
|
||||
# See README for more details.
|
||||
#
|
||||
|
||||
on post-fs-data
|
||||
mkdir /data/misc/wifi/hostapd 0770 wifi wifi
|
||||
|
||||
service hostapd /system/bin/hostapd \
|
||||
-e /data/misc/wifi/entropy.bin \
|
||||
/data/misc/wifi/hostapd.conf
|
||||
class main
|
||||
user wifi
|
||||
writepid /data/misc/wifi/hostapd.pid
|
||||
group wifi
|
||||
disabled
|
||||
oneshot
|
@ -3,6 +3,8 @@
|
||||
|
||||
# AP netdevice name (without 'ap' postfix, i.e., wlan0 uses wlan0ap for
|
||||
# management frames with the Host AP driver); wlan0 with many nl80211 drivers
|
||||
# Note: This attribute can be overridden by the values supplied with the '-i'
|
||||
# command line parameter.
|
||||
interface=wlan0
|
||||
|
||||
# In case of atheros and nl80211 driver interfaces, an additional
|
||||
@ -125,11 +127,13 @@ ssid=test
|
||||
# ieee80211d=1 and local_pwr_constraint configured.
|
||||
#spectrum_mgmt_required=1
|
||||
|
||||
# Operation mode (a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g,
|
||||
# ad = IEEE 802.11ad (60 GHz); a/g options are used with IEEE 802.11n, too, to
|
||||
# specify band). When using ACS (see channel parameter), a special value "any"
|
||||
# can be used to indicate that any support band can be used. This special case
|
||||
# is currently supported only with drivers with which offloaded ACS is used.
|
||||
# Operation mode (a = IEEE 802.11a (5 GHz), b = IEEE 802.11b (2.4 GHz),
|
||||
# g = IEEE 802.11g (2.4 GHz), ad = IEEE 802.11ad (60 GHz); a/g options are used
|
||||
# with IEEE 802.11n (HT), too, to specify band). For IEEE 802.11ac (VHT), this
|
||||
# needs to be set to hw_mode=a. When using ACS (see channel parameter), a
|
||||
# special value "any" can be used to indicate that any support band can be used.
|
||||
# This special case is currently supported only with drivers with which
|
||||
# offloaded ACS is used.
|
||||
# Default: IEEE 802.11b
|
||||
hw_mode=g
|
||||
|
||||
@ -173,7 +177,7 @@ channel=1
|
||||
# Channel list restriction. This option allows hostapd to select one of the
|
||||
# provided channels when a channel should be automatically selected.
|
||||
# Channel list can be provided as range using hyphen ('-') or individual
|
||||
# channels can be specified by space (' ') seperated values
|
||||
# channels can be specified by space (' ') separated values
|
||||
# Default: all channels allowed in selected hw_mode
|
||||
#chanlist=100 104 108 112 116
|
||||
#chanlist=1 6 11-13
|
||||
@ -192,16 +196,16 @@ dtim_period=2
|
||||
# (default: 2007)
|
||||
max_num_sta=255
|
||||
|
||||
# RTS/CTS threshold; 2347 = disabled (default); range 0..2347
|
||||
# RTS/CTS threshold; -1 = disabled (default); range -1..65535
|
||||
# If this field is not included in hostapd.conf, hostapd will not control
|
||||
# RTS threshold and 'iwconfig wlan# rts <val>' can be used to set it.
|
||||
rts_threshold=2347
|
||||
rts_threshold=-1
|
||||
|
||||
# Fragmentation threshold; 2346 = disabled (default); range 256..2346
|
||||
# Fragmentation threshold; -1 = disabled (default); range -1, 256..2346
|
||||
# If this field is not included in hostapd.conf, hostapd will not control
|
||||
# fragmentation threshold and 'iwconfig wlan# frag <val>' can be used to set
|
||||
# it.
|
||||
fragm_threshold=2346
|
||||
fragm_threshold=-1
|
||||
|
||||
# Rate configuration
|
||||
# Default is to enable all rates supported by the hardware. This configuration
|
||||
@ -267,13 +271,27 @@ auth_algs=3
|
||||
# requests for broadcast SSID
|
||||
ignore_broadcast_ssid=0
|
||||
|
||||
# Additional vendor specfic elements for Beacon and Probe Response frames
|
||||
# Do not reply to broadcast Probe Request frames from unassociated STA if there
|
||||
# is no room for additional stations (max_num_sta). This can be used to
|
||||
# discourage a STA from trying to associate with this AP if the association
|
||||
# would be rejected due to maximum STA limit.
|
||||
# Default: 0 (disabled)
|
||||
#no_probe_resp_if_max_sta=0
|
||||
|
||||
# Additional vendor specific elements for Beacon and Probe Response frames
|
||||
# This parameter can be used to add additional vendor specific element(s) into
|
||||
# the end of the Beacon and Probe Response frames. The format for these
|
||||
# element(s) is a hexdump of the raw information elements (id+len+payload for
|
||||
# one or more elements)
|
||||
#vendor_elements=dd0411223301
|
||||
|
||||
# Additional vendor specific elements for (Re)Association Response frames
|
||||
# This parameter can be used to add additional vendor specific element(s) into
|
||||
# the end of the (Re)Association Response frames. The format for these
|
||||
# element(s) is a hexdump of the raw information elements (id+len+payload for
|
||||
# one or more elements)
|
||||
#assocresp_elements=dd0411223301
|
||||
|
||||
# TX queue parameters (EDCF / bursting)
|
||||
# tx_queue_<queue name>_<param>
|
||||
# queues: data0, data1, data2, data3, after_beacon, beacon
|
||||
@ -470,6 +488,7 @@ wmm_ac_vo_acm=0
|
||||
# 0 = disabled (default)
|
||||
# 1 = enabled
|
||||
# Note: You will also need to enable WMM for full HT functionality.
|
||||
# Note: hw_mode=g (2.4 GHz) and hw_mode=a (5 GHz) is used to specify the band.
|
||||
#ieee80211n=1
|
||||
|
||||
# ht_capab: HT capabilities (list of flags)
|
||||
@ -523,6 +542,7 @@ wmm_ac_vo_acm=0
|
||||
# 0 = disabled (default)
|
||||
# 1 = enabled
|
||||
# Note: You will also need to enable WMM for full VHT functionality.
|
||||
# Note: hw_mode=a is used to specify that 5 GHz band is used with VHT.
|
||||
#ieee80211ac=1
|
||||
|
||||
# vht_capab: VHT capabilities (list of flags)
|
||||
@ -605,9 +625,9 @@ wmm_ac_vo_acm=0
|
||||
# VHT TXOP PS: [VHT-TXOP-PS]
|
||||
# Indicates whether or not the AP supports VHT TXOP Power Save Mode
|
||||
# or whether or not the STA is in VHT TXOP Power Save mode
|
||||
# 0 = VHT AP doesnt support VHT TXOP PS mode (OR) VHT Sta not in VHT TXOP PS
|
||||
# 0 = VHT AP doesn't support VHT TXOP PS mode (OR) VHT STA not in VHT TXOP PS
|
||||
# mode
|
||||
# 1 = VHT AP supports VHT TXOP PS mode (OR) VHT Sta is in VHT TXOP power save
|
||||
# 1 = VHT AP supports VHT TXOP PS mode (OR) VHT STA is in VHT TXOP power save
|
||||
# mode
|
||||
#
|
||||
# +HTC-VHT Capable: [HTC-VHT]
|
||||
@ -665,6 +685,13 @@ wmm_ac_vo_acm=0
|
||||
#
|
||||
#vht_oper_centr_freq_seg1_idx=159
|
||||
|
||||
# Workaround to use station's nsts capability in (Re)Association Response frame
|
||||
# This may be needed with some deployed devices as an interoperability
|
||||
# workaround for beamforming if the AP's capability is greater than the
|
||||
# station's capability. This is disabled by default and can be enabled by
|
||||
# setting use_sta_nsts=1.
|
||||
#use_sta_nsts=0
|
||||
|
||||
##### IEEE 802.1X-2004 related configuration ##################################
|
||||
|
||||
# Require IEEE 802.1X authorization
|
||||
@ -788,6 +815,11 @@ eap_server=0
|
||||
# -respout /tmp/ocsp-cache.der
|
||||
#ocsp_stapling_response=/tmp/ocsp-cache.der
|
||||
|
||||
# Cached OCSP stapling response list (DER encoded OCSPResponseList)
|
||||
# This is similar to ocsp_stapling_response, but the extended version defined in
|
||||
# RFC 6961 to allow multiple OCSP responses to be provided.
|
||||
#ocsp_stapling_response_multi=/tmp/ocsp-multi-cache.der
|
||||
|
||||
# dh_file: File path to DH/DSA parameters file (in PEM format)
|
||||
# This is an optional configuration file for setting parameters for an
|
||||
# ephemeral DH key exchange. In most cases, the default RSA authentication does
|
||||
@ -825,6 +857,11 @@ eap_server=0
|
||||
#eap_sim_db=unix:/tmp/hlr_auc_gw.sock
|
||||
#eap_sim_db=unix:/tmp/hlr_auc_gw.sock db=/tmp/hostapd.db
|
||||
|
||||
# EAP-SIM DB request timeout
|
||||
# This parameter sets the maximum time to wait for a database request response.
|
||||
# The parameter value is in seconds.
|
||||
#eap_sim_db_timeout=1
|
||||
|
||||
# Encryption key for EAP-FAST PAC-Opaque values. This key must be a secret,
|
||||
# random value. It is configured as a 16-octet value in hex format. It can be
|
||||
# generated, e.g., with the following command:
|
||||
@ -888,11 +925,23 @@ eap_server=0
|
||||
# The own IP address of the access point (used as NAS-IP-Address)
|
||||
own_ip_addr=127.0.0.1
|
||||
|
||||
# Optional NAS-Identifier string for RADIUS messages. When used, this should be
|
||||
# a unique to the NAS within the scope of the RADIUS server. For example, a
|
||||
# fully qualified domain name can be used here.
|
||||
# NAS-Identifier string for RADIUS messages. When used, this should be unique
|
||||
# to the NAS within the scope of the RADIUS server. Please note that hostapd
|
||||
# uses a separate RADIUS client for each BSS and as such, a unique
|
||||
# nas_identifier value should be configured separately for each BSS. This is
|
||||
# particularly important for cases where RADIUS accounting is used
|
||||
# (Accounting-On/Off messages are interpreted as clearing all ongoing sessions
|
||||
# and that may get interpreted as applying to all BSSes if the same
|
||||
# NAS-Identifier value is used.) For example, a fully qualified domain name
|
||||
# prefixed with a unique identifier of the BSS (e.g., BSSID) can be used here.
|
||||
#
|
||||
# When using IEEE 802.11r, nas_identifier must be set and must be between 1 and
|
||||
# 48 octets long.
|
||||
#
|
||||
# It is mandatory to configure either own_ip_addr or nas_identifier to be
|
||||
# compliant with the RADIUS protocol. When using RADIUS accounting, it is
|
||||
# strongly recommended that nas_identifier is set to a unique value for each
|
||||
# BSS.
|
||||
#nas_identifier=ap.example.com
|
||||
|
||||
# RADIUS client forced local IP address for the access point
|
||||
@ -957,6 +1006,17 @@ own_ip_addr=127.0.0.1
|
||||
# 2 = required; reject authentication if RADIUS server does not include VLAN ID
|
||||
#dynamic_vlan=0
|
||||
|
||||
# Per-Station AP_VLAN interface mode
|
||||
# If enabled, each station is assigned its own AP_VLAN interface.
|
||||
# This implies per-station group keying and ebtables filtering of inter-STA
|
||||
# traffic (when passed through the AP).
|
||||
# If the sta is not assigned to any VLAN, then its AP_VLAN interface will be
|
||||
# added to the bridge given by the "bridge" configuration option (see above).
|
||||
# Otherwise, it will be added to the per-VLAN bridge.
|
||||
# 0 = disabled (default)
|
||||
# 1 = enabled
|
||||
#per_sta_vif=0
|
||||
|
||||
# VLAN interface list for dynamic VLAN mode is read from a separate text file.
|
||||
# This list is used to map VLAN ID from the RADIUS server to a network
|
||||
# interface. Each station is bound to one interface in the same way as with
|
||||
@ -1035,6 +1095,9 @@ own_ip_addr=127.0.0.1
|
||||
#
|
||||
# DAS require Event-Timestamp
|
||||
#radius_das_require_event_timestamp=1
|
||||
#
|
||||
# DAS require Message-Authenticator
|
||||
#radius_das_require_message_authenticator=1
|
||||
|
||||
##### RADIUS authentication server configuration ##############################
|
||||
|
||||
@ -1228,6 +1291,7 @@ own_ip_addr=127.0.0.1
|
||||
|
||||
# PMK-R1 Key Holder identifier (dot11FTR1KeyHolderID)
|
||||
# 6-octet identifier as a hex string.
|
||||
# Defaults to BSSID.
|
||||
#r1_key_holder=000102030405
|
||||
|
||||
# Reassociation deadline in time units (TUs / 1.024 ms; range 1000..65535)
|
||||
@ -1684,6 +1748,24 @@ own_ip_addr=127.0.0.1
|
||||
# username/password
|
||||
#nai_realm=0,example.org,13[5:6],21[2:4][5:7]
|
||||
|
||||
# Arbitrary ANQP-element configuration
|
||||
# Additional ANQP-elements with arbitrary values can be defined by specifying
|
||||
# their contents in raw format as a hexdump of the payload. Note that these
|
||||
# values will override ANQP-element contents that may have been specified in the
|
||||
# more higher layer configuration parameters listed above.
|
||||
# format: anqp_elem=<InfoID>:<hexdump of payload>
|
||||
# For example, AP Geospatial Location ANQP-element with unknown location:
|
||||
#anqp_elem=265:0000
|
||||
# For example, AP Civic Location ANQP-element with unknown location:
|
||||
#anqp_elem=266:000000
|
||||
|
||||
# GAS Address 3 behavior
|
||||
# 0 = P2P specification (Address3 = AP BSSID) workaround enabled by default
|
||||
# based on GAS request Address3
|
||||
# 1 = IEEE 802.11 standard compliant regardless of GAS request Address3
|
||||
# 2 = Force non-compliant behavior (Address3 = AP BSSID for all cases)
|
||||
#gas_address3=0
|
||||
|
||||
# QoS Map Set configuration
|
||||
#
|
||||
# Comma delimited QoS Map Set in decimal values
|
||||
@ -1823,6 +1905,27 @@ own_ip_addr=127.0.0.1
|
||||
# Transitioning between states).
|
||||
#fst_llt=100
|
||||
|
||||
##### Radio measurements / location ###########################################
|
||||
|
||||
# The content of a LCI measurement subelement
|
||||
#lci=<Hexdump of binary data of the LCI report>
|
||||
|
||||
# The content of a location civic measurement subelement
|
||||
#civic=<Hexdump of binary data of the location civic report>
|
||||
|
||||
# Enable neighbor report via radio measurements
|
||||
#rrm_neighbor_report=1
|
||||
|
||||
# Publish fine timing measurement (FTM) responder functionality
|
||||
# This parameter only controls publishing via Extended Capabilities element.
|
||||
# Actual functionality is managed outside hostapd.
|
||||
#ftm_responder=0
|
||||
|
||||
# Publish fine timing measurement (FTM) initiator functionality
|
||||
# This parameter only controls publishing via Extended Capabilities element.
|
||||
# Actual functionality is managed outside hostapd.
|
||||
#ftm_initiator=0
|
||||
|
||||
##### TESTING OPTIONS #########################################################
|
||||
#
|
||||
# The options in this section are only available when the build configuration
|
||||
@ -1844,6 +1947,10 @@ own_ip_addr=127.0.0.1
|
||||
#
|
||||
# Corrupt Key MIC in GTK rekey EAPOL-Key frames with the given probability
|
||||
#corrupt_gtk_rekey_mic_probability=0.0
|
||||
#
|
||||
# Include only ECSA IE without CSA IE where possible
|
||||
# (channel switch operating class is needed)
|
||||
#ecsa_ie_only=0
|
||||
|
||||
##### Multiple BSSID support ##################################################
|
||||
#
|
||||
@ -1866,6 +1973,10 @@ own_ip_addr=127.0.0.1
|
||||
# - is not the same as the MAC address of the radio
|
||||
# - is not the same as any other explicitly specified BSSID
|
||||
#
|
||||
# Alternatively, the 'use_driver_iface_addr' parameter can be used to request
|
||||
# hostapd to use the driver auto-generated interface address (e.g., to use the
|
||||
# exact MAC addresses allocated to the device).
|
||||
#
|
||||
# Not all drivers support multiple BSSes. The exact mechanism for determining
|
||||
# the driver capabilities is driver specific. With the current (i.e., a recent
|
||||
# kernel) drivers using nl80211, this information can be checked with "iw list"
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* hostapd - command line interface for hostapd daemon
|
||||
* Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -15,79 +15,13 @@
|
||||
#include "utils/eloop.h"
|
||||
#include "utils/edit.h"
|
||||
#include "common/version.h"
|
||||
#include "common/cli.h"
|
||||
|
||||
#ifndef CONFIG_NO_CTRL_IFACE
|
||||
|
||||
static const char *const hostapd_cli_version =
|
||||
"hostapd_cli v" VERSION_STR "\n"
|
||||
"Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> and contributors";
|
||||
|
||||
|
||||
static const char *const hostapd_cli_license =
|
||||
"This software may be distributed under the terms of the BSD license.\n"
|
||||
"See README for more details.\n";
|
||||
|
||||
static const char *const hostapd_cli_full_license =
|
||||
"This software may be distributed under the terms of the BSD license.\n"
|
||||
"\n"
|
||||
"Redistribution and use in source and binary forms, with or without\n"
|
||||
"modification, are permitted provided that the following conditions are\n"
|
||||
"met:\n"
|
||||
"\n"
|
||||
"1. Redistributions of source code must retain the above copyright\n"
|
||||
" notice, this list of conditions and the following disclaimer.\n"
|
||||
"\n"
|
||||
"2. Redistributions in binary form must reproduce the above copyright\n"
|
||||
" notice, this list of conditions and the following disclaimer in the\n"
|
||||
" documentation and/or other materials provided with the distribution.\n"
|
||||
"\n"
|
||||
"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
|
||||
" names of its contributors may be used to endorse or promote products\n"
|
||||
" derived from this software without specific prior written permission.\n"
|
||||
"\n"
|
||||
"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
|
||||
"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
|
||||
"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
|
||||
"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
|
||||
"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
|
||||
"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
|
||||
"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
|
||||
"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
|
||||
"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
|
||||
"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
|
||||
"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
|
||||
"\n";
|
||||
|
||||
static const char *const commands_help =
|
||||
"Commands:\n"
|
||||
" mib get MIB variables (dot1x, dot11, radius)\n"
|
||||
" sta <addr> get MIB variables for one station\n"
|
||||
" all_sta get MIB variables for all stations\n"
|
||||
" new_sta <addr> add a new station\n"
|
||||
" deauthenticate <addr> deauthenticate a station\n"
|
||||
" disassociate <addr> disassociate a station\n"
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
" sa_query <addr> send SA Query to a station\n"
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
#ifdef CONFIG_WPS
|
||||
" wps_pin <uuid> <pin> [timeout] [addr] add WPS Enrollee PIN\n"
|
||||
" wps_check_pin <PIN> verify PIN checksum\n"
|
||||
" wps_pbc indicate button pushed to initiate PBC\n"
|
||||
" wps_cancel cancel the pending WPS operation\n"
|
||||
#ifdef CONFIG_WPS_NFC
|
||||
" wps_nfc_tag_read <hexdump> report read NFC tag with WPS data\n"
|
||||
" wps_nfc_config_token <WPS/NDEF> build NFC configuration token\n"
|
||||
" wps_nfc_token <WPS/NDEF/enable/disable> manager NFC password token\n"
|
||||
#endif /* CONFIG_WPS_NFC */
|
||||
" wps_ap_pin <cmd> [params..] enable/disable AP PIN\n"
|
||||
" wps_config <SSID> <auth> <encr> <key> configure AP\n"
|
||||
" wps_get_status show current WPS status\n"
|
||||
#endif /* CONFIG_WPS */
|
||||
" get_config show current configuration\n"
|
||||
" help show this usage help\n"
|
||||
" interface [ifname] show interfaces/select interface\n"
|
||||
" level <debug level> change debug level\n"
|
||||
" license show full hostapd_cli license\n"
|
||||
" quit exit hostapd_cli\n";
|
||||
"Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi> and contributors";
|
||||
|
||||
static struct wpa_ctrl *ctrl_conn;
|
||||
static int hostapd_cli_quit = 0;
|
||||
@ -104,6 +38,13 @@ static const char *pid_file = NULL;
|
||||
static const char *action_file = NULL;
|
||||
static int ping_interval = 5;
|
||||
static int interactive = 0;
|
||||
static int event_handler_registered = 0;
|
||||
|
||||
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 usage(void)
|
||||
@ -128,20 +69,49 @@ static void usage(void)
|
||||
" -B run a daemon in the background\n"
|
||||
" -i<ifname> Interface to listen on (default: first "
|
||||
"interface found in the\n"
|
||||
" socket path)\n\n"
|
||||
"%s",
|
||||
commands_help);
|
||||
" socket path)\n\n");
|
||||
print_help(stderr, NULL);
|
||||
}
|
||||
|
||||
|
||||
static void register_event_handler(struct wpa_ctrl *ctrl)
|
||||
{
|
||||
if (!ctrl_conn)
|
||||
return;
|
||||
if (interactive) {
|
||||
event_handler_registered =
|
||||
!eloop_register_read_sock(wpa_ctrl_get_fd(ctrl),
|
||||
hostapd_cli_receive,
|
||||
NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void unregister_event_handler(struct wpa_ctrl *ctrl)
|
||||
{
|
||||
if (!ctrl_conn)
|
||||
return;
|
||||
if (interactive && event_handler_registered) {
|
||||
eloop_unregister_read_sock(wpa_ctrl_get_fd(ctrl));
|
||||
event_handler_registered = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
|
||||
{
|
||||
#ifndef CONFIG_CTRL_IFACE_UDP
|
||||
char *cfile;
|
||||
int flen;
|
||||
#endif /* !CONFIG_CTRL_IFACE_UDP */
|
||||
|
||||
if (ifname == NULL)
|
||||
return NULL;
|
||||
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP
|
||||
ctrl_conn = wpa_ctrl_open(ifname);
|
||||
return ctrl_conn;
|
||||
#else /* CONFIG_CTRL_IFACE_UDP */
|
||||
flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
|
||||
cfile = malloc(flen);
|
||||
if (cfile == NULL)
|
||||
@ -158,6 +128,7 @@ static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
|
||||
ctrl_conn = wpa_ctrl_open2(cfile, client_socket_dir);
|
||||
free(cfile);
|
||||
return ctrl_conn;
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP */
|
||||
}
|
||||
|
||||
|
||||
@ -166,6 +137,7 @@ static void hostapd_cli_close_connection(void)
|
||||
if (ctrl_conn == NULL)
|
||||
return;
|
||||
|
||||
unregister_event_handler(ctrl_conn);
|
||||
if (hostapd_cli_attached) {
|
||||
wpa_ctrl_detach(ctrl_conn);
|
||||
hostapd_cli_attached = 0;
|
||||
@ -215,6 +187,22 @@ static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd,
|
||||
int min_args, int argc, char *argv[])
|
||||
{
|
||||
char buf[4096];
|
||||
|
||||
if (argc < min_args) {
|
||||
printf("Invalid %s command - at least %d argument%s required.\n",
|
||||
cmd, min_args, min_args > 1 ? "s are" : " is");
|
||||
return -1;
|
||||
}
|
||||
if (write_cmd(buf, sizeof(buf), cmd, argc, argv) < 0)
|
||||
return -1;
|
||||
return wpa_ctrl_command(ctrl, buf);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
return wpa_ctrl_command(ctrl, "PING");
|
||||
@ -330,6 +318,21 @@ 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[])
|
||||
{
|
||||
@ -348,6 +351,37 @@ 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[])
|
||||
{
|
||||
char buf[64];
|
||||
|
||||
if (argc != 1) {
|
||||
printf("Invalid 'signature' command - exactly one argument, STA address, is required.\n");
|
||||
return -1;
|
||||
}
|
||||
os_snprintf(buf, sizeof(buf), "SIGNATURE %s", argv[0]);
|
||||
return wpa_ctrl_command(ctrl, buf);
|
||||
}
|
||||
#endif /* CONFIG_TAXONOMY */
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
@ -720,15 +754,30 @@ static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
|
||||
|
||||
static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
printf("%s", commands_help);
|
||||
print_help(stdout, argc > 0 ? argv[0] : NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static char ** hostapd_cli_complete_help(const char *str, int pos)
|
||||
{
|
||||
int arg = get_cmd_arg_num(str, pos);
|
||||
char **res = NULL;
|
||||
|
||||
switch (arg) {
|
||||
case 1:
|
||||
res = list_cmd_list();
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
|
||||
printf("%s\n\n%s\n", hostapd_cli_version, cli_full_license);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -839,6 +888,28 @@ static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_cli_get_interfaces(struct wpa_ctrl *ctrl,
|
||||
struct dl_list *interfaces)
|
||||
{
|
||||
struct dirent *dent;
|
||||
DIR *dir;
|
||||
|
||||
if (!ctrl || !interfaces)
|
||||
return;
|
||||
dir = opendir(ctrl_iface_dir);
|
||||
if (dir == NULL)
|
||||
return;
|
||||
|
||||
while ((dent = readdir(dir))) {
|
||||
if (strcmp(dent->d_name, ".") == 0 ||
|
||||
strcmp(dent->d_name, "..") == 0)
|
||||
continue;
|
||||
cli_txt_list_add(interfaces, dent->d_name);
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
|
||||
{
|
||||
struct dirent *dent;
|
||||
@ -880,6 +951,7 @@ static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
|
||||
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");
|
||||
@ -892,6 +964,24 @@ static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
|
||||
}
|
||||
|
||||
|
||||
static char ** hostapd_complete_interface(const char *str, int pos)
|
||||
{
|
||||
int arg = get_cmd_arg_num(str, pos);
|
||||
char **res = NULL;
|
||||
DEFINE_DL_LIST(interfaces);
|
||||
|
||||
switch (arg) {
|
||||
case 1:
|
||||
hostapd_cli_get_interfaces(ctrl_conn, &interfaces);
|
||||
res = cli_txt_list_array(&interfaces);
|
||||
cli_txt_list_flush(&interfaces);
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
char cmd[256];
|
||||
@ -1068,68 +1158,245 @@ static int hostapd_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc,
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
if (argc == 0)
|
||||
return -1;
|
||||
return hostapd_cli_cmd(ctrl, argv[0], 0, argc - 1, &argv[1]);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_pmksa(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
return wpa_ctrl_command(ctrl, "PMKSA");
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_pmksa_flush(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return wpa_ctrl_command(ctrl, "PMKSA_FLUSH");
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_set_neighbor(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
char cmd[2048];
|
||||
int res;
|
||||
|
||||
if (argc < 3 || argc > 5) {
|
||||
printf("Invalid set_neighbor command: needs 3-5 arguments\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = os_snprintf(cmd, sizeof(cmd), "SET_NEIGHBOR %s %s %s %s %s",
|
||||
argv[0], argv[1], argv[2], argc >= 4 ? argv[3] : "",
|
||||
argc == 5 ? argv[4] : "");
|
||||
if (os_snprintf_error(sizeof(cmd), res)) {
|
||||
printf("Too long SET_NEIGHBOR command.\n");
|
||||
return -1;
|
||||
}
|
||||
return wpa_ctrl_command(ctrl, cmd);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_remove_neighbor(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
char cmd[400];
|
||||
int res;
|
||||
|
||||
if (argc != 2) {
|
||||
printf("Invalid remove_neighbor command: needs 2 arguments\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = os_snprintf(cmd, sizeof(cmd), "REMOVE_NEIGHBOR %s %s",
|
||||
argv[0], argv[1]);
|
||||
if (os_snprintf_error(sizeof(cmd), res)) {
|
||||
printf("Too long REMOVE_NEIGHBOR command.\n");
|
||||
return -1;
|
||||
}
|
||||
return wpa_ctrl_command(ctrl, cmd);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_req_lci(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
char cmd[256];
|
||||
int res;
|
||||
|
||||
if (argc != 1) {
|
||||
printf("Invalid req_lci command - requires destination address\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = os_snprintf(cmd, sizeof(cmd), "REQ_LCI %s", argv[0]);
|
||||
if (os_snprintf_error(sizeof(cmd), res)) {
|
||||
printf("Too long REQ_LCI command.\n");
|
||||
return -1;
|
||||
}
|
||||
return wpa_ctrl_command(ctrl, cmd);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_req_range(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
if (argc < 4) {
|
||||
printf("Invalid req_range command: needs at least 4 arguments - dest address, randomization interval, min AP count, and 1 to 16 AP addresses\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return hostapd_cli_cmd(ctrl, "REQ_RANGE", 4, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_cli_cmd_driver_flags(struct wpa_ctrl *ctrl, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
return wpa_ctrl_command(ctrl, "DRIVER_FLAGS");
|
||||
}
|
||||
|
||||
|
||||
struct hostapd_cli_cmd {
|
||||
const char *cmd;
|
||||
int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
|
||||
char ** (*completion)(const char *str, int pos);
|
||||
const char *usage;
|
||||
};
|
||||
|
||||
static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
|
||||
{ "ping", hostapd_cli_cmd_ping },
|
||||
{ "mib", hostapd_cli_cmd_mib },
|
||||
{ "relog", hostapd_cli_cmd_relog },
|
||||
{ "status", hostapd_cli_cmd_status },
|
||||
{ "sta", hostapd_cli_cmd_sta },
|
||||
{ "all_sta", hostapd_cli_cmd_all_sta },
|
||||
{ "new_sta", hostapd_cli_cmd_new_sta },
|
||||
{ "deauthenticate", hostapd_cli_cmd_deauthenticate },
|
||||
{ "disassociate", hostapd_cli_cmd_disassociate },
|
||||
{ "ping", hostapd_cli_cmd_ping, NULL,
|
||||
"= 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,
|
||||
"<addr> = get MIB variables for one station" },
|
||||
{ "all_sta", hostapd_cli_cmd_all_sta, NULL,
|
||||
"= get MIB variables for all stations" },
|
||||
{ "new_sta", hostapd_cli_cmd_new_sta, NULL,
|
||||
"<addr> = add a new station" },
|
||||
{ "deauthenticate", hostapd_cli_cmd_deauthenticate,
|
||||
hostapd_complete_deauthenticate,
|
||||
"<addr> = deauthenticate a station" },
|
||||
{ "disassociate", hostapd_cli_cmd_disassociate,
|
||||
hostapd_complete_disassociate,
|
||||
"<addr> = disassociate a station" },
|
||||
#ifdef CONFIG_TAXONOMY
|
||||
{ "signature", hostapd_cli_cmd_signature, NULL,
|
||||
"<addr> = get taxonomy signature for a station" },
|
||||
#endif /* CONFIG_TAXONOMY */
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
{ "sa_query", hostapd_cli_cmd_sa_query },
|
||||
{ "sa_query", hostapd_cli_cmd_sa_query, NULL,
|
||||
"<addr> = send SA Query to a station" },
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
#ifdef CONFIG_WPS
|
||||
{ "wps_pin", hostapd_cli_cmd_wps_pin },
|
||||
{ "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
|
||||
{ "wps_pbc", hostapd_cli_cmd_wps_pbc },
|
||||
{ "wps_cancel", hostapd_cli_cmd_wps_cancel },
|
||||
{ "wps_pin", hostapd_cli_cmd_wps_pin, NULL,
|
||||
"<uuid> <pin> [timeout] [addr] = add WPS Enrollee PIN" },
|
||||
{ "wps_check_pin", hostapd_cli_cmd_wps_check_pin, NULL,
|
||||
"<PIN> = verify PIN checksum" },
|
||||
{ "wps_pbc", hostapd_cli_cmd_wps_pbc, NULL,
|
||||
"= indicate button pushed to initiate PBC" },
|
||||
{ "wps_cancel", hostapd_cli_cmd_wps_cancel, NULL,
|
||||
"= cancel the pending WPS operation" },
|
||||
#ifdef CONFIG_WPS_NFC
|
||||
{ "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read },
|
||||
{ "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token },
|
||||
{ "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token },
|
||||
{ "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel },
|
||||
{ "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read, NULL,
|
||||
"<hexdump> = report read NFC tag with WPS data" },
|
||||
{ "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token, NULL,
|
||||
"<WPS/NDEF> = build NFC configuration token" },
|
||||
{ "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token, NULL,
|
||||
"<WPS/NDEF/enable/disable> = manager NFC password token" },
|
||||
{ "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel, NULL,
|
||||
NULL },
|
||||
#endif /* CONFIG_WPS_NFC */
|
||||
{ "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
|
||||
{ "wps_config", hostapd_cli_cmd_wps_config },
|
||||
{ "wps_get_status", hostapd_cli_cmd_wps_get_status },
|
||||
{ "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin, NULL,
|
||||
"<cmd> [params..] = enable/disable AP PIN" },
|
||||
{ "wps_config", hostapd_cli_cmd_wps_config, NULL,
|
||||
"<SSID> <auth> <encr> <key> = configure AP" },
|
||||
{ "wps_get_status", hostapd_cli_cmd_wps_get_status, NULL,
|
||||
"= show current WPS status" },
|
||||
#endif /* CONFIG_WPS */
|
||||
{ "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent },
|
||||
{ "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
|
||||
{ "bss_tm_req", hostapd_cli_cmd_bss_tm_req },
|
||||
{ "get_config", hostapd_cli_cmd_get_config },
|
||||
{ "help", hostapd_cli_cmd_help },
|
||||
{ "interface", hostapd_cli_cmd_interface },
|
||||
{ "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 },
|
||||
{ "get_config", hostapd_cli_cmd_get_config, NULL,
|
||||
"= show current configuration" },
|
||||
{ "help", hostapd_cli_cmd_help, hostapd_cli_complete_help,
|
||||
"= show this usage help" },
|
||||
{ "interface", hostapd_cli_cmd_interface, hostapd_complete_interface,
|
||||
"[ifname] = show interfaces/select interface" },
|
||||
#ifdef CONFIG_FST
|
||||
{ "fst", hostapd_cli_cmd_fst },
|
||||
{ "fst", hostapd_cli_cmd_fst, NULL, NULL },
|
||||
#endif /* CONFIG_FST */
|
||||
{ "level", hostapd_cli_cmd_level },
|
||||
{ "license", hostapd_cli_cmd_license },
|
||||
{ "quit", hostapd_cli_cmd_quit },
|
||||
{ "set", hostapd_cli_cmd_set },
|
||||
{ "get", hostapd_cli_cmd_get },
|
||||
{ "set_qos_map_set", hostapd_cli_cmd_set_qos_map_set },
|
||||
{ "send_qos_map_conf", hostapd_cli_cmd_send_qos_map_conf },
|
||||
{ "chan_switch", hostapd_cli_cmd_chan_switch },
|
||||
{ "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif },
|
||||
{ "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req },
|
||||
{ "vendor", hostapd_cli_cmd_vendor },
|
||||
{ "enable", hostapd_cli_cmd_enable },
|
||||
{ "reload", hostapd_cli_cmd_reload },
|
||||
{ "disable", hostapd_cli_cmd_disable },
|
||||
{ "erp_flush", hostapd_cli_cmd_erp_flush },
|
||||
{ "log_level", hostapd_cli_cmd_log_level },
|
||||
{ NULL, NULL }
|
||||
{ "raw", hostapd_cli_cmd_raw, NULL, NULL },
|
||||
{ "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 },
|
||||
{ NULL, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Prints command usage, lines are padded with the specified string.
|
||||
*/
|
||||
static void print_cmd_help(FILE *stream, const struct hostapd_cli_cmd *cmd,
|
||||
const char *pad)
|
||||
{
|
||||
char c;
|
||||
size_t n;
|
||||
|
||||
if (cmd->usage == NULL)
|
||||
return;
|
||||
fprintf(stream, "%s%s ", pad, cmd->cmd);
|
||||
for (n = 0; (c = cmd->usage[n]); n++) {
|
||||
fprintf(stream, "%c", c);
|
||||
if (c == '\n')
|
||||
fprintf(stream, "%s", pad);
|
||||
}
|
||||
fprintf(stream, "\n");
|
||||
}
|
||||
|
||||
|
||||
static void print_help(FILE *stream, const char *cmd)
|
||||
{
|
||||
int n;
|
||||
|
||||
fprintf(stream, "commands:\n");
|
||||
for (n = 0; hostapd_cli_commands[n].cmd; n++) {
|
||||
if (cmd == NULL || str_starts(hostapd_cli_commands[n].cmd, cmd))
|
||||
print_cmd_help(stream, &hostapd_cli_commands[n], " ");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
{
|
||||
const struct hostapd_cli_cmd *cmd, *match = NULL;
|
||||
@ -1169,6 +1436,34 @@ static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
||||
}
|
||||
|
||||
|
||||
static void cli_event(const char *str)
|
||||
{
|
||||
const char *start, *s;
|
||||
|
||||
start = os_strchr(str, '>');
|
||||
if (start == NULL)
|
||||
return;
|
||||
|
||||
start++;
|
||||
|
||||
if (str_starts(start, AP_STA_CONNECTED)) {
|
||||
s = os_strchr(start, ' ');
|
||||
if (s == NULL)
|
||||
return;
|
||||
cli_txt_list_add(&stations, s + 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (str_starts(start, AP_STA_DISCONNECTED)) {
|
||||
s = os_strchr(start, ' ');
|
||||
if (s == NULL)
|
||||
return;
|
||||
cli_txt_list_del_addr(&stations, s + 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
|
||||
int action_monitor)
|
||||
{
|
||||
@ -1183,6 +1478,7 @@ static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
|
||||
if (action_monitor)
|
||||
hostapd_cli_action_process(buf, len);
|
||||
else {
|
||||
cli_event(buf);
|
||||
if (in_read && first)
|
||||
printf("\n");
|
||||
first = 0;
|
||||
@ -1196,35 +1492,9 @@ static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
|
||||
}
|
||||
|
||||
|
||||
#define max_args 10
|
||||
|
||||
static int tokenize_cmd(char *cmd, char *argv[])
|
||||
static void hostapd_cli_receive(int sock, void *eloop_ctx, void *sock_ctx)
|
||||
{
|
||||
char *pos;
|
||||
int argc = 0;
|
||||
|
||||
pos = cmd;
|
||||
for (;;) {
|
||||
while (*pos == ' ')
|
||||
pos++;
|
||||
if (*pos == '\0')
|
||||
break;
|
||||
argv[argc] = pos;
|
||||
argc++;
|
||||
if (argc == max_args)
|
||||
break;
|
||||
if (*pos == '"') {
|
||||
char *pos2 = os_strrchr(pos, '"');
|
||||
if (pos2)
|
||||
pos = pos2 + 1;
|
||||
}
|
||||
while (*pos != '\0' && *pos != ' ')
|
||||
pos++;
|
||||
if (*pos == ' ')
|
||||
*pos++ = '\0';
|
||||
}
|
||||
|
||||
return argc;
|
||||
hostapd_cli_recv_pending(ctrl_conn, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
@ -1240,6 +1510,7 @@ static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx)
|
||||
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");
|
||||
@ -1274,17 +1545,82 @@ static void hostapd_cli_edit_eof_cb(void *ctx)
|
||||
}
|
||||
|
||||
|
||||
static char ** list_cmd_list(void)
|
||||
{
|
||||
char **res;
|
||||
int i, count;
|
||||
|
||||
count = ARRAY_SIZE(hostapd_cli_commands);
|
||||
res = os_calloc(count + 1, sizeof(char *));
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; hostapd_cli_commands[i].cmd; i++) {
|
||||
res[i] = os_strdup(hostapd_cli_commands[i].cmd);
|
||||
if (res[i] == NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static char ** hostapd_cli_cmd_completion(const char *cmd, const char *str,
|
||||
int pos)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; hostapd_cli_commands[i].cmd; i++) {
|
||||
if (os_strcasecmp(hostapd_cli_commands[i].cmd, cmd) != 0)
|
||||
continue;
|
||||
if (hostapd_cli_commands[i].completion)
|
||||
return hostapd_cli_commands[i].completion(str, pos);
|
||||
if (!hostapd_cli_commands[i].usage)
|
||||
return NULL;
|
||||
edit_clear_line();
|
||||
printf("\r%s\n", hostapd_cli_commands[i].usage);
|
||||
edit_redraw();
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static char ** hostapd_cli_edit_completion_cb(void *ctx, const char *str,
|
||||
int pos)
|
||||
{
|
||||
char **res;
|
||||
const char *end;
|
||||
char *cmd;
|
||||
|
||||
end = os_strchr(str, ' ');
|
||||
if (end == NULL || str + pos < end)
|
||||
return list_cmd_list();
|
||||
|
||||
cmd = os_malloc(pos + 1);
|
||||
if (cmd == NULL)
|
||||
return NULL;
|
||||
os_memcpy(cmd, str, pos);
|
||||
cmd[end - str] = '\0';
|
||||
res = hostapd_cli_cmd_completion(cmd, str, pos);
|
||||
os_free(cmd);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_cli_interactive(void)
|
||||
{
|
||||
printf("\nInteractive mode\n\n");
|
||||
|
||||
eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
|
||||
edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
|
||||
NULL, NULL, NULL, NULL);
|
||||
hostapd_cli_edit_completion_cb, NULL, NULL, NULL);
|
||||
eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
|
||||
|
||||
eloop_run();
|
||||
|
||||
cli_txt_list_flush(&stations);
|
||||
edit_deinit(NULL, NULL);
|
||||
eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
|
||||
}
|
||||
@ -1388,8 +1724,7 @@ int main(int argc, char *argv[])
|
||||
interactive = (argc == optind) && (action_file == NULL);
|
||||
|
||||
if (interactive) {
|
||||
printf("%s\n\n%s\n\n", hostapd_cli_version,
|
||||
hostapd_cli_license);
|
||||
printf("%s\n\n%s\n\n", hostapd_cli_version, cli_license);
|
||||
}
|
||||
|
||||
if (eloop_init())
|
||||
@ -1437,6 +1772,7 @@ int main(int argc, char *argv[])
|
||||
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)
|
||||
@ -1444,7 +1780,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
if (daemonize && os_daemonize(pid_file))
|
||||
if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue())
|
||||
return -1;
|
||||
|
||||
if (interactive)
|
||||
@ -1454,8 +1790,18 @@ int main(int argc, char *argv[])
|
||||
else
|
||||
wpa_request(ctrl_conn, argc - optind, &argv[optind]);
|
||||
|
||||
unregister_event_handler(ctrl_conn);
|
||||
os_free(ctrl_ifname);
|
||||
eloop_destroy();
|
||||
hostapd_cli_cleanup();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* CONFIG_NO_CTRL_IFACE */
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NO_CTRL_IFACE */
|
||||
|
131
hostapd/main.c
131
hostapd/main.c
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* hostapd / main()
|
||||
* Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -171,7 +171,8 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
|
||||
|
||||
if (global.drv_priv[i] == NULL &&
|
||||
wpa_drivers[i]->global_init) {
|
||||
global.drv_priv[i] = wpa_drivers[i]->global_init();
|
||||
global.drv_priv[i] =
|
||||
wpa_drivers[i]->global_init(iface->interfaces);
|
||||
if (global.drv_priv[i] == NULL) {
|
||||
wpa_printf(MSG_ERROR, "Failed to initialize "
|
||||
"driver '%s'",
|
||||
@ -216,11 +217,20 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
|
||||
iface->drv_flags = capa.flags;
|
||||
iface->smps_modes = capa.smps_modes;
|
||||
iface->probe_resp_offloads = capa.probe_resp_offloads;
|
||||
/*
|
||||
* Use default extended capa values from per-radio information
|
||||
*/
|
||||
iface->extended_capa = capa.extended_capa;
|
||||
iface->extended_capa_mask = capa.extended_capa_mask;
|
||||
iface->extended_capa_len = capa.extended_capa_len;
|
||||
iface->drv_max_acl_mac_addrs = capa.max_acl_mac_addrs;
|
||||
|
||||
/*
|
||||
* Override extended capa with per-interface type (AP), if
|
||||
* available from the driver.
|
||||
*/
|
||||
hostapd_get_ext_capa(iface);
|
||||
|
||||
triggs = wpa_get_wowlan_triggers(conf->wowlan_triggers, &capa);
|
||||
if (triggs && hapd->driver->set_wowlan) {
|
||||
if (hapd->driver->set_wowlan(hapd->drv_priv, triggs))
|
||||
@ -241,7 +251,7 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
|
||||
* interfaces. No actiual driver operations are started.
|
||||
*/
|
||||
static struct hostapd_iface *
|
||||
hostapd_interface_init(struct hapd_interfaces *interfaces,
|
||||
hostapd_interface_init(struct hapd_interfaces *interfaces, const char *if_name,
|
||||
const char *config_fname, int debug)
|
||||
{
|
||||
struct hostapd_iface *iface;
|
||||
@ -251,6 +261,12 @@ hostapd_interface_init(struct hapd_interfaces *interfaces,
|
||||
iface = hostapd_init(interfaces, config_fname);
|
||||
if (!iface)
|
||||
return NULL;
|
||||
|
||||
if (if_name) {
|
||||
os_strlcpy(iface->conf->bss[0]->iface, if_name,
|
||||
sizeof(iface->conf->bss[0]->iface));
|
||||
}
|
||||
|
||||
iface->interfaces = interfaces;
|
||||
|
||||
for (k = 0; k < debug; k++) {
|
||||
@ -260,7 +276,8 @@ hostapd_interface_init(struct hapd_interfaces *interfaces,
|
||||
|
||||
if (iface->conf->bss[0]->iface[0] == '\0' &&
|
||||
!hostapd_drv_none(iface->bss[0])) {
|
||||
wpa_printf(MSG_ERROR, "Interface name not specified in %s",
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Interface name not specified in %s, nor by '-i' parameter",
|
||||
config_fname);
|
||||
hostapd_interface_deinit_free(iface);
|
||||
return NULL;
|
||||
@ -329,6 +346,7 @@ static int hostapd_global_init(struct hapd_interfaces *interfaces,
|
||||
wpa_printf(MSG_ERROR, "Failed to initialize event loop");
|
||||
return -1;
|
||||
}
|
||||
interfaces->eloop_initialized = 1;
|
||||
|
||||
random_init(entropy_file);
|
||||
|
||||
@ -356,7 +374,7 @@ static int hostapd_global_init(struct hapd_interfaces *interfaces,
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_global_deinit(const char *pid_file)
|
||||
static void hostapd_global_deinit(const char *pid_file, int eloop_initialized)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -374,7 +392,8 @@ static void hostapd_global_deinit(const char *pid_file)
|
||||
|
||||
random_deinit();
|
||||
|
||||
eloop_destroy();
|
||||
if (eloop_initialized)
|
||||
eloop_destroy();
|
||||
|
||||
#ifndef CONFIG_NATIVE_WINDOWS
|
||||
closelog();
|
||||
@ -408,9 +427,16 @@ static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize,
|
||||
}
|
||||
#endif /* EAP_SERVER_TNC */
|
||||
|
||||
if (daemonize && os_daemonize(pid_file)) {
|
||||
wpa_printf(MSG_ERROR, "daemon: %s", strerror(errno));
|
||||
return -1;
|
||||
if (daemonize) {
|
||||
if (os_daemonize(pid_file)) {
|
||||
wpa_printf(MSG_ERROR, "daemon: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (eloop_sock_requeue()) {
|
||||
wpa_printf(MSG_ERROR, "eloop_sock_requeue: %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
eloop_run();
|
||||
@ -425,7 +451,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-2015, Jouni Malinen <j@w1.fi> "
|
||||
"Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> "
|
||||
"and contributors\n");
|
||||
}
|
||||
|
||||
@ -437,7 +463,8 @@ static void usage(void)
|
||||
"\n"
|
||||
"usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] "
|
||||
"\\\n"
|
||||
" [-g <global ctrl_iface>] [-G <group>] \\\n"
|
||||
" [-g <global ctrl_iface>] [-G <group>]\\\n"
|
||||
" [-i <comma-separated list of interface names>]\\\n"
|
||||
" <configuration file(s)>\n"
|
||||
"\n"
|
||||
"options:\n"
|
||||
@ -456,6 +483,8 @@ static void usage(void)
|
||||
" -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"
|
||||
" -S start all the interfaces synchronously\n"
|
||||
" -t include timestamps in some debug messages\n"
|
||||
" -v show hostapd version\n");
|
||||
|
||||
@ -466,9 +495,8 @@ static void usage(void)
|
||||
static const char * hostapd_msg_ifname_cb(void *ctx)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
if (hapd && hapd->iconf && hapd->iconf->bss &&
|
||||
hapd->iconf->num_bss > 0 && hapd->iconf->bss[0])
|
||||
return hapd->iconf->bss[0]->iface;
|
||||
if (hapd && hapd->conf)
|
||||
return hapd->conf->iface;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -476,11 +504,16 @@ static const char * hostapd_msg_ifname_cb(void *ctx)
|
||||
static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces,
|
||||
const char *path)
|
||||
{
|
||||
#ifndef CONFIG_CTRL_IFACE_UDP
|
||||
char *pos;
|
||||
#endif /* !CONFIG_CTRL_IFACE_UDP */
|
||||
|
||||
os_free(interfaces->global_iface_path);
|
||||
interfaces->global_iface_path = os_strdup(path);
|
||||
if (interfaces->global_iface_path == NULL)
|
||||
return -1;
|
||||
|
||||
#ifndef CONFIG_CTRL_IFACE_UDP
|
||||
pos = os_strrchr(interfaces->global_iface_path, '/');
|
||||
if (pos == NULL) {
|
||||
wpa_printf(MSG_ERROR, "No '/' in the global control interface "
|
||||
@ -492,6 +525,7 @@ static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces,
|
||||
|
||||
*pos = '\0';
|
||||
interfaces->global_iface_name = pos + 1;
|
||||
#endif /* !CONFIG_CTRL_IFACE_UDP */
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -513,6 +547,43 @@ 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 *if_name, *tmp, **nnames;
|
||||
size_t i;
|
||||
|
||||
if (!optarg)
|
||||
return -1;
|
||||
if_name = strtok_r(optarg, ",", &tmp);
|
||||
|
||||
while (if_name) {
|
||||
nnames = os_realloc_array(*if_names, 1 + *if_names_size,
|
||||
sizeof(char *));
|
||||
if (!nnames)
|
||||
goto fail;
|
||||
*if_names = nnames;
|
||||
|
||||
(*if_names)[*if_names_size] = os_strdup(if_name);
|
||||
if (!(*if_names)[*if_names_size])
|
||||
goto fail;
|
||||
(*if_names_size)++;
|
||||
if_name = strtok_r(NULL, ",", &tmp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
for (i = 0; i < *if_names_size; i++)
|
||||
os_free((*if_names)[i]);
|
||||
os_free(*if_names);
|
||||
*if_names = NULL;
|
||||
*if_names_size = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_WPS
|
||||
static int gen_uuid(const char *txt_addr)
|
||||
{
|
||||
@ -570,6 +641,9 @@ int main(int argc, char *argv[])
|
||||
#ifdef CONFIG_DEBUG_LINUX_TRACING
|
||||
int enable_trace_dbg = 0;
|
||||
#endif /* CONFIG_DEBUG_LINUX_TRACING */
|
||||
int start_ifaces_in_sync = 0;
|
||||
char **if_names = NULL;
|
||||
size_t if_names_size = 0;
|
||||
|
||||
if (os_program_init())
|
||||
return -1;
|
||||
@ -584,10 +658,10 @@ int main(int argc, char *argv[])
|
||||
interfaces.global_iface_path = NULL;
|
||||
interfaces.global_iface_name = NULL;
|
||||
interfaces.global_ctrl_sock = -1;
|
||||
interfaces.global_ctrl_dst = NULL;
|
||||
dl_list_init(&interfaces.global_ctrl_dst);
|
||||
|
||||
for (;;) {
|
||||
c = getopt(argc, argv, "b:Bde:f:hKP:Ttu:vg:G:");
|
||||
c = getopt(argc, argv, "b:Bde:f:hi:KP:STtu:vg:G:");
|
||||
if (c < 0)
|
||||
break;
|
||||
switch (c) {
|
||||
@ -644,10 +718,18 @@ int main(int argc, char *argv[])
|
||||
bss_config = tmp_bss;
|
||||
bss_config[num_bss_configs++] = optarg;
|
||||
break;
|
||||
case 'S':
|
||||
start_ifaces_in_sync = 1;
|
||||
break;
|
||||
#ifdef CONFIG_WPS
|
||||
case 'u':
|
||||
return gen_uuid(optarg);
|
||||
#endif /* CONFIG_WPS */
|
||||
case 'i':
|
||||
if (hostapd_get_interface_names(&if_names,
|
||||
&if_names_size, optarg))
|
||||
goto out;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
@ -705,13 +787,21 @@ int main(int argc, char *argv[])
|
||||
|
||||
/* Allocate and parse configuration for full interface files */
|
||||
for (i = 0; i < interfaces.count; i++) {
|
||||
char *if_name = NULL;
|
||||
|
||||
if (i < if_names_size)
|
||||
if_name = if_names[i];
|
||||
|
||||
interfaces.iface[i] = hostapd_interface_init(&interfaces,
|
||||
if_name,
|
||||
argv[optind + i],
|
||||
debug);
|
||||
if (!interfaces.iface[i]) {
|
||||
wpa_printf(MSG_ERROR, "Failed to initialize interface");
|
||||
goto out;
|
||||
}
|
||||
if (start_ifaces_in_sync)
|
||||
interfaces.iface[i]->need_to_start_in_sync = 1;
|
||||
}
|
||||
|
||||
/* Allocate and parse configuration for per-BSS files */
|
||||
@ -787,8 +877,9 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
os_free(interfaces.iface);
|
||||
|
||||
eloop_cancel_timeout(hostapd_periodic, &interfaces, NULL);
|
||||
hostapd_global_deinit(pid_file);
|
||||
if (interfaces.eloop_initialized)
|
||||
eloop_cancel_timeout(hostapd_periodic, &interfaces, NULL);
|
||||
hostapd_global_deinit(pid_file, interfaces.eloop_initialized);
|
||||
os_free(pid_file);
|
||||
|
||||
if (log_file)
|
||||
@ -797,6 +888,10 @@ int main(int argc, char *argv[])
|
||||
|
||||
os_free(bss_config);
|
||||
|
||||
for (i = 0; i < if_names_size; i++)
|
||||
os_free(if_names[i]);
|
||||
os_free(if_names);
|
||||
|
||||
fst_global_deinit();
|
||||
|
||||
os_program_deinit();
|
||||
|
@ -4,7 +4,6 @@ INCLUDES = $(LOCAL_PATH)
|
||||
INCLUDES += $(LOCAL_PATH)/../../src/utils
|
||||
INCLUDES += $(LOCAL_PATH)/../../src/common
|
||||
INCLUDES += $(LOCAL_PATH)/../../src
|
||||
INCLUDES += external/openssl/include
|
||||
INCLUDES += external/libxml2/include
|
||||
INCLUDES += external/curl/include
|
||||
INCLUDES += external/webkit/Source/WebKit/gtk
|
||||
@ -55,6 +54,7 @@ OBJS += ../../src/crypto/crypto_internal.c
|
||||
OBJS += ../../src/crypto/md5-internal.c
|
||||
OBJS += ../../src/crypto/sha1-internal.c
|
||||
OBJS += ../../src/crypto/sha256-internal.c
|
||||
OBJS += ../../src/crypto/tls_openssl_ocsp.c
|
||||
|
||||
L_CFLAGS += -DEAP_TLS_OPENSSL
|
||||
|
||||
|
@ -76,6 +76,7 @@ LIBS += -lcurl
|
||||
endif
|
||||
|
||||
CFLAGS += -DEAP_TLS_OPENSSL
|
||||
OBJS += ../../src/crypto/tls_openssl_ocsp.o
|
||||
LIBS += -lssl -lcrypto
|
||||
|
||||
hs20-osu-client: $(OBJS)
|
||||
|
@ -16,6 +16,9 @@
|
||||
#include <openssl/asn1t.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/x509v3.h>
|
||||
#ifdef OPENSSL_IS_BORINGSSL
|
||||
#include <openssl/buf.h>
|
||||
#endif /* OPENSSL_IS_BORINGSSL */
|
||||
|
||||
#include "common.h"
|
||||
#include "utils/base64.h"
|
||||
@ -27,12 +30,28 @@
|
||||
static int pkcs7_to_cert(struct hs20_osu_client *ctx, const u8 *pkcs7,
|
||||
size_t len, char *pem_file, char *der_file)
|
||||
{
|
||||
#ifdef OPENSSL_IS_BORINGSSL
|
||||
CBS pkcs7_cbs;
|
||||
#else /* OPENSSL_IS_BORINGSSL */
|
||||
PKCS7 *p7 = NULL;
|
||||
const unsigned char *p = pkcs7;
|
||||
#endif /* OPENSSL_IS_BORINGSSL */
|
||||
STACK_OF(X509) *certs;
|
||||
int i, num, ret = -1;
|
||||
BIO *out = NULL;
|
||||
|
||||
#ifdef OPENSSL_IS_BORINGSSL
|
||||
certs = sk_X509_new_null();
|
||||
if (!certs)
|
||||
goto fail;
|
||||
CBS_init(&pkcs7_cbs, pkcs7, len);
|
||||
if (!PKCS7_get_certificates(certs, &pkcs7_cbs)) {
|
||||
wpa_printf(MSG_INFO, "Could not parse PKCS#7 object: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
write_result(ctx, "Could not parse PKCS#7 object from EST");
|
||||
goto fail;
|
||||
}
|
||||
#else /* OPENSSL_IS_BORINGSSL */
|
||||
p7 = d2i_PKCS7(NULL, &p, len);
|
||||
if (p7 == NULL) {
|
||||
wpa_printf(MSG_INFO, "Could not parse PKCS#7 object: %s",
|
||||
@ -52,6 +71,7 @@ static int pkcs7_to_cert(struct hs20_osu_client *ctx, const u8 *pkcs7,
|
||||
certs = NULL;
|
||||
break;
|
||||
}
|
||||
#endif /* OPENSSL_IS_BORINGSSL */
|
||||
|
||||
if (!certs || ((num = sk_X509_num(certs)) == 0)) {
|
||||
wpa_printf(MSG_INFO, "No certificates found in PKCS#7 object");
|
||||
@ -84,7 +104,12 @@ static int pkcs7_to_cert(struct hs20_osu_client *ctx, const u8 *pkcs7,
|
||||
ret = 0;
|
||||
|
||||
fail:
|
||||
#ifdef OPENSSL_IS_BORINGSSL
|
||||
if (certs)
|
||||
sk_X509_pop_free(certs, X509_free);
|
||||
#else /* OPENSSL_IS_BORINGSSL */
|
||||
PKCS7_free(p7);
|
||||
#endif /* OPENSSL_IS_BORINGSSL */
|
||||
if (out)
|
||||
BIO_free_all(out);
|
||||
|
||||
@ -310,6 +335,23 @@ static void add_csrattrs(struct hs20_osu_client *ctx, CsrAttrs *csrattrs,
|
||||
if (!csrattrs || ! csrattrs->attrs)
|
||||
return;
|
||||
|
||||
#ifdef OPENSSL_IS_BORINGSSL
|
||||
num = sk_num(CHECKED_CAST(_STACK *, STACK_OF(AttrOrOID) *,
|
||||
csrattrs->attrs));
|
||||
for (i = 0; i < num; i++) {
|
||||
AttrOrOID *ao = sk_value(
|
||||
CHECKED_CAST(_STACK *, const STACK_OF(AttrOrOID) *,
|
||||
csrattrs->attrs), i);
|
||||
switch (ao->type) {
|
||||
case 0:
|
||||
add_csrattrs_oid(ctx, ao->d.oid, exts);
|
||||
break;
|
||||
case 1:
|
||||
add_csrattrs_attr(ctx, ao->d.attribute, exts);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else /* OPENSSL_IS_BORINGSSL */
|
||||
num = SKM_sk_num(AttrOrOID, csrattrs->attrs);
|
||||
for (i = 0; i < num; i++) {
|
||||
AttrOrOID *ao = SKM_sk_value(AttrOrOID, csrattrs->attrs, i);
|
||||
@ -322,6 +364,7 @@ static void add_csrattrs(struct hs20_osu_client *ctx, CsrAttrs *csrattrs,
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* OPENSSL_IS_BORINGSSL */
|
||||
}
|
||||
|
||||
|
||||
@ -340,6 +383,7 @@ static int generate_csr(struct hs20_osu_client *ctx, char *key_pem,
|
||||
STACK_OF(X509_EXTENSION) *exts = NULL;
|
||||
X509_EXTENSION *ex;
|
||||
BIO *out;
|
||||
CONF *ctmp = NULL;
|
||||
|
||||
wpa_printf(MSG_INFO, "Generate RSA private key");
|
||||
write_summary(ctx, "Generate RSA private key");
|
||||
@ -421,20 +465,20 @@ static int generate_csr(struct hs20_osu_client *ctx, char *key_pem,
|
||||
if (!exts)
|
||||
goto fail;
|
||||
|
||||
ex = X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints,
|
||||
"CA:FALSE");
|
||||
ex = X509V3_EXT_nconf_nid(ctmp, NULL, NID_basic_constraints,
|
||||
"CA:FALSE");
|
||||
if (ex == NULL ||
|
||||
!sk_X509_EXTENSION_push(exts, ex))
|
||||
goto fail;
|
||||
|
||||
ex = X509V3_EXT_conf_nid(NULL, NULL, NID_key_usage,
|
||||
"nonRepudiation,digitalSignature,keyEncipherment");
|
||||
ex = X509V3_EXT_nconf_nid(ctmp, NULL, NID_key_usage,
|
||||
"nonRepudiation,digitalSignature,keyEncipherment");
|
||||
if (ex == NULL ||
|
||||
!sk_X509_EXTENSION_push(exts, ex))
|
||||
goto fail;
|
||||
|
||||
ex = X509V3_EXT_conf_nid(NULL, NULL, NID_ext_key_usage,
|
||||
"1.3.6.1.4.1.40808.1.1.2");
|
||||
ex = X509V3_EXT_nconf_nid(ctmp, NULL, NID_ext_key_usage,
|
||||
"1.3.6.1.4.1.40808.1.1.2");
|
||||
if (ex == NULL ||
|
||||
!sk_X509_EXTENSION_push(exts, ex))
|
||||
goto fail;
|
||||
@ -454,7 +498,9 @@ static int generate_csr(struct hs20_osu_client *ctx, char *key_pem,
|
||||
char *txt;
|
||||
size_t rlen;
|
||||
|
||||
#if !defined(ANDROID) || !defined(OPENSSL_IS_BORINGSSL)
|
||||
X509_REQ_print(out, req);
|
||||
#endif
|
||||
rlen = BIO_ctrl_pending(out);
|
||||
txt = os_malloc(rlen + 1);
|
||||
if (txt) {
|
||||
@ -473,7 +519,9 @@ static int generate_csr(struct hs20_osu_client *ctx, char *key_pem,
|
||||
FILE *f = fopen(csr_pem, "w");
|
||||
if (f == NULL)
|
||||
goto fail;
|
||||
#if !defined(ANDROID) || !defined(OPENSSL_IS_BORINGSSL)
|
||||
X509_REQ_print_fp(f, req);
|
||||
#endif
|
||||
if (!PEM_write_X509_REQ(f, req)) {
|
||||
fclose(f);
|
||||
goto fail;
|
||||
|
@ -2229,7 +2229,7 @@ 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_nai)
|
||||
if (last->osu_nai[0])
|
||||
fprintf(f, "NAI: %s<br>\n", last->osu_nai);
|
||||
fprintf(f, "URL: %s<br>\n"
|
||||
"methods:%s%s<br>\n"
|
||||
@ -2339,12 +2339,23 @@ static int cmd_signup(struct hs20_osu_client *ctx, int no_prod_assoc,
|
||||
return -1;
|
||||
|
||||
snprintf(fname, sizeof(fname), "%s/osu-info", dir);
|
||||
if (mkdir(fname, S_IRWXU | S_IRWXG) < 0 && errno != EEXIST) {
|
||||
if (mkdir(fname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0 &&
|
||||
errno != EEXIST) {
|
||||
wpa_printf(MSG_INFO, "mkdir(%s) failed: %s",
|
||||
fname, strerror(errno));
|
||||
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 */
|
||||
|
||||
snprintf(buf, sizeof(buf), "SET osu_dir %s", fname);
|
||||
if (wpa_command(ifname, buf) < 0) {
|
||||
wpa_printf(MSG_INFO, "Failed to configure osu_dir to wpa_supplicant");
|
||||
@ -2559,7 +2570,7 @@ static int cmd_pol_upd(struct hs20_osu_client *ctx, const char *address,
|
||||
if (!pps_fname) {
|
||||
char buf[256];
|
||||
wpa_printf(MSG_INFO, "Determining PPS file based on Home SP information");
|
||||
if (os_strncmp(address, "fqdn=", 5) == 0) {
|
||||
if (address && os_strncmp(address, "fqdn=", 5) == 0) {
|
||||
wpa_printf(MSG_INFO, "Use requested FQDN from command line");
|
||||
os_snprintf(buf, sizeof(buf), "%s", address + 5);
|
||||
address = NULL;
|
||||
@ -3122,20 +3133,12 @@ int main(int argc, char *argv[])
|
||||
usage();
|
||||
exit(0);
|
||||
}
|
||||
if (argc - optind < 2)
|
||||
wpa_printf(MSG_ERROR, "Server URL missing from command line");
|
||||
else
|
||||
ret = cmd_sub_rem(&ctx, argv[optind + 1],
|
||||
argc > optind + 2 ?
|
||||
argv[optind + 2] : NULL,
|
||||
argc > optind + 3 ?
|
||||
argv[optind + 3] : NULL);
|
||||
ret = cmd_sub_rem(&ctx, argv[optind + 1],
|
||||
argc > optind + 2 ? argv[optind + 2] : NULL,
|
||||
argc > optind + 3 ? argv[optind + 3] : NULL);
|
||||
} else if (strcmp(argv[optind], "pol_upd") == 0) {
|
||||
if (argc - optind < 2) {
|
||||
usage();
|
||||
exit(0);
|
||||
}
|
||||
ret = cmd_pol_upd(&ctx, argc > 2 ? argv[optind + 1] : NULL,
|
||||
ret = cmd_pol_upd(&ctx,
|
||||
argc > optind + 1 ? argv[optind + 1] : NULL,
|
||||
argc > optind + 2 ? argv[optind + 2] : NULL,
|
||||
argc > optind + 3 ? argv[optind + 3] : NULL);
|
||||
} else if (strcmp(argv[optind], "prov") == 0) {
|
||||
|
@ -1,397 +0,0 @@
|
||||
This patch adds support for TLS SessionTicket extension (RFC 5077) for
|
||||
the parts used by EAP-FAST (RFC 4851).
|
||||
|
||||
This is based on the patch from Alexey Kobozev <akobozev@cisco.com>
|
||||
(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
|
||||
|
||||
OpenSSL 0.9.8za does not enable TLS extension support by default, so it
|
||||
will need to be enabled by adding enable-tlsext to config script
|
||||
command line.
|
||||
|
||||
|
||||
diff -upr openssl-0.9.8za.orig/ssl/s3_clnt.c openssl-0.9.8za/ssl/s3_clnt.c
|
||||
--- openssl-0.9.8za.orig/ssl/s3_clnt.c 2014-06-05 11:09:26.000000000 +0300
|
||||
+++ openssl-0.9.8za/ssl/s3_clnt.c 2014-06-05 20:37:09.221387312 +0300
|
||||
@@ -767,6 +767,22 @@ int ssl3_get_server_hello(SSL *s)
|
||||
goto f_err;
|
||||
}
|
||||
|
||||
+#ifndef OPENSSL_NO_TLSEXT
|
||||
+ /* check if we want to resume the session based on external pre-shared secret */
|
||||
+ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
|
||||
+ {
|
||||
+ SSL_CIPHER *pref_cipher=NULL;
|
||||
+ s->session->master_key_length=sizeof(s->session->master_key);
|
||||
+ if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
|
||||
+ NULL, &pref_cipher, s->tls_session_secret_cb_arg))
|
||||
+ {
|
||||
+ s->session->cipher=pref_cipher ?
|
||||
+ pref_cipher : ssl_get_cipher_by_char(s,p+j);
|
||||
+ s->s3->flags |= SSL3_FLAGS_CCS_OK;
|
||||
+ }
|
||||
+ }
|
||||
+#endif /* OPENSSL_NO_TLSEXT */
|
||||
+
|
||||
if (j != 0 && j == s->session->session_id_length
|
||||
&& memcmp(p,s->session->session_id,j) == 0)
|
||||
{
|
||||
@@ -2745,11 +2760,8 @@ int ssl3_check_finished(SSL *s)
|
||||
{
|
||||
int ok;
|
||||
long n;
|
||||
- /* If we have no ticket or session ID is non-zero length (a match of
|
||||
- * a non-zero session length would never reach here) it cannot be a
|
||||
- * resumed session.
|
||||
- */
|
||||
- if (!s->session->tlsext_tick || s->session->session_id_length)
|
||||
+ /* If we have no ticket it cannot be a resumed session. */
|
||||
+ if (!s->session->tlsext_tick)
|
||||
return 1;
|
||||
/* this function is called when we really expect a Certificate
|
||||
* message, so permit appropriate message length */
|
||||
diff -upr openssl-0.9.8za.orig/ssl/s3_srvr.c openssl-0.9.8za/ssl/s3_srvr.c
|
||||
--- openssl-0.9.8za.orig/ssl/s3_srvr.c 2014-06-05 11:09:26.000000000 +0300
|
||||
+++ openssl-0.9.8za/ssl/s3_srvr.c 2014-06-05 20:37:09.225387312 +0300
|
||||
@@ -1011,6 +1011,59 @@ int ssl3_get_client_hello(SSL *s)
|
||||
SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
|
||||
goto err;
|
||||
}
|
||||
+
|
||||
+ /* Check if we want to use external pre-shared secret for this
|
||||
+ * handshake for not reused session only. We need to generate
|
||||
+ * server_random before calling tls_session_secret_cb in order to allow
|
||||
+ * SessionTicket processing to use it in key derivation. */
|
||||
+ {
|
||||
+ unsigned long Time;
|
||||
+ unsigned char *pos;
|
||||
+ Time=(unsigned long)time(NULL); /* Time */
|
||||
+ pos=s->s3->server_random;
|
||||
+ l2n(Time,pos);
|
||||
+ if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0)
|
||||
+ {
|
||||
+ al=SSL_AD_INTERNAL_ERROR;
|
||||
+ goto f_err;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
|
||||
+ {
|
||||
+ SSL_CIPHER *pref_cipher=NULL;
|
||||
+
|
||||
+ s->session->master_key_length=sizeof(s->session->master_key);
|
||||
+ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
|
||||
+ ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
|
||||
+ {
|
||||
+ s->hit=1;
|
||||
+ s->session->ciphers=ciphers;
|
||||
+ s->session->verify_result=X509_V_OK;
|
||||
+
|
||||
+ ciphers=NULL;
|
||||
+
|
||||
+ /* check if some cipher was preferred by call back */
|
||||
+ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
|
||||
+ if (pref_cipher == NULL)
|
||||
+ {
|
||||
+ al=SSL_AD_HANDSHAKE_FAILURE;
|
||||
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
|
||||
+ goto f_err;
|
||||
+ }
|
||||
+
|
||||
+ s->session->cipher=pref_cipher;
|
||||
+
|
||||
+ if (s->cipher_list)
|
||||
+ sk_SSL_CIPHER_free(s->cipher_list);
|
||||
+
|
||||
+ if (s->cipher_list_by_id)
|
||||
+ sk_SSL_CIPHER_free(s->cipher_list_by_id);
|
||||
+
|
||||
+ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
|
||||
+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
|
||||
+ }
|
||||
+ }
|
||||
#endif
|
||||
/* Worst case, we will use the NULL compression, but if we have other
|
||||
* options, we will now look for them. We have i-1 compression
|
||||
@@ -1161,16 +1214,22 @@ int ssl3_send_server_hello(SSL *s)
|
||||
unsigned char *buf;
|
||||
unsigned char *p,*d;
|
||||
int i,sl;
|
||||
- unsigned long l,Time;
|
||||
+ unsigned long l;
|
||||
+#ifdef OPENSSL_NO_TLSEXT
|
||||
+ unsigned long Time;
|
||||
+#endif
|
||||
|
||||
if (s->state == SSL3_ST_SW_SRVR_HELLO_A)
|
||||
{
|
||||
buf=(unsigned char *)s->init_buf->data;
|
||||
+#ifdef OPENSSL_NO_TLSEXT
|
||||
p=s->s3->server_random;
|
||||
+ /* Generate server_random if it was not needed previously */
|
||||
Time=(unsigned long)time(NULL); /* Time */
|
||||
l2n(Time,p);
|
||||
if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0)
|
||||
return -1;
|
||||
+#endif
|
||||
/* Do the message type and length last */
|
||||
d=p= &(buf[4]);
|
||||
|
||||
diff -upr openssl-0.9.8za.orig/ssl/ssl_err.c openssl-0.9.8za/ssl/ssl_err.c
|
||||
--- openssl-0.9.8za.orig/ssl/ssl_err.c 2014-06-05 11:09:08.000000000 +0300
|
||||
+++ openssl-0.9.8za/ssl/ssl_err.c 2014-06-05 20:37:09.225387312 +0300
|
||||
@@ -265,6 +265,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
|
||||
{ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"},
|
||||
{ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
|
||||
{ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"},
|
||||
+{ERR_FUNC(SSL_F_SSL_SET_SESSION_TICKET_EXT), "SSL_set_session_ticket_ext"},
|
||||
{0,NULL}
|
||||
};
|
||||
|
||||
diff -upr openssl-0.9.8za.orig/ssl/ssl.h openssl-0.9.8za/ssl/ssl.h
|
||||
--- openssl-0.9.8za.orig/ssl/ssl.h 2014-06-05 11:09:08.000000000 +0300
|
||||
+++ openssl-0.9.8za/ssl/ssl.h 2014-06-05 20:37:09.229387312 +0300
|
||||
@@ -344,6 +344,7 @@ extern "C" {
|
||||
* 'struct ssl_st *' function parameters used to prototype callbacks
|
||||
* in SSL_CTX. */
|
||||
typedef struct ssl_st *ssl_crock_st;
|
||||
+typedef struct tls_session_ticket_ext_st TLS_SESSION_TICKET_EXT;
|
||||
|
||||
/* used to hold info on the particular ciphers used */
|
||||
typedef struct ssl_cipher_st
|
||||
@@ -362,6 +363,9 @@ typedef struct ssl_cipher_st
|
||||
|
||||
DECLARE_STACK_OF(SSL_CIPHER)
|
||||
|
||||
+typedef int (*tls_session_ticket_ext_cb_fn)(SSL *s, const unsigned char *data, int len, void *arg);
|
||||
+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
|
||||
+
|
||||
/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
|
||||
typedef struct ssl_method_st
|
||||
{
|
||||
@@ -1053,6 +1057,18 @@ struct ssl_st
|
||||
|
||||
/* RFC4507 session ticket expected to be received or sent */
|
||||
int tlsext_ticket_expected;
|
||||
+
|
||||
+ /* TLS Session Ticket extension override */
|
||||
+ TLS_SESSION_TICKET_EXT *tlsext_session_ticket;
|
||||
+
|
||||
+ /* TLS Session Ticket extension callback */
|
||||
+ tls_session_ticket_ext_cb_fn tls_session_ticket_ext_cb;
|
||||
+ void *tls_session_ticket_ext_cb_arg;
|
||||
+
|
||||
+ /* TLS pre-shared secret session resumption */
|
||||
+ tls_session_secret_cb_fn tls_session_secret_cb;
|
||||
+ void *tls_session_secret_cb_arg;
|
||||
+
|
||||
SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
|
||||
#define session_ctx initial_ctx
|
||||
#else
|
||||
@@ -1668,6 +1684,15 @@ void *SSL_COMP_get_compression_methods(v
|
||||
int SSL_COMP_add_compression_method(int id,void *cm);
|
||||
#endif
|
||||
|
||||
+/* TLS extensions functions */
|
||||
+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len);
|
||||
+
|
||||
+int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
|
||||
+ void *arg);
|
||||
+
|
||||
+/* Pre-shared secret session resumption functions */
|
||||
+int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
|
||||
+
|
||||
/* BEGIN ERROR CODES */
|
||||
/* The following lines are auto generated by the script mkerr.pl. Any changes
|
||||
* made after this point may be overwritten when the script is next run.
|
||||
@@ -1872,6 +1897,7 @@ void ERR_load_SSL_strings(void);
|
||||
#define SSL_F_TLS1_ENC 210
|
||||
#define SSL_F_TLS1_SETUP_KEY_BLOCK 211
|
||||
#define SSL_F_WRITE_PENDING 212
|
||||
+#define SSL_F_SSL_SET_SESSION_TICKET_EXT 213
|
||||
|
||||
/* Reason codes. */
|
||||
#define SSL_R_APP_DATA_IN_HANDSHAKE 100
|
||||
diff -upr openssl-0.9.8za.orig/ssl/ssl_sess.c openssl-0.9.8za/ssl/ssl_sess.c
|
||||
--- openssl-0.9.8za.orig/ssl/ssl_sess.c 2014-06-05 11:09:08.000000000 +0300
|
||||
+++ openssl-0.9.8za/ssl/ssl_sess.c 2014-06-05 20:37:09.229387312 +0300
|
||||
@@ -712,6 +712,61 @@ long SSL_CTX_get_timeout(const SSL_CTX *
|
||||
return(s->session_timeout);
|
||||
}
|
||||
|
||||
+#ifndef OPENSSL_NO_TLSEXT
|
||||
+int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
|
||||
+ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
|
||||
+ {
|
||||
+ if (s == NULL) return(0);
|
||||
+ s->tls_session_secret_cb = tls_session_secret_cb;
|
||||
+ s->tls_session_secret_cb_arg = arg;
|
||||
+ return(1);
|
||||
+ }
|
||||
+
|
||||
+int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
|
||||
+ void *arg)
|
||||
+ {
|
||||
+ if (s == NULL) return(0);
|
||||
+ s->tls_session_ticket_ext_cb = cb;
|
||||
+ s->tls_session_ticket_ext_cb_arg = arg;
|
||||
+ return(1);
|
||||
+ }
|
||||
+
|
||||
+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len)
|
||||
+ {
|
||||
+ if (s->version >= TLS1_VERSION)
|
||||
+ {
|
||||
+ if (s->tlsext_session_ticket)
|
||||
+ {
|
||||
+ OPENSSL_free(s->tlsext_session_ticket);
|
||||
+ s->tlsext_session_ticket = NULL;
|
||||
+ }
|
||||
+
|
||||
+ s->tlsext_session_ticket = OPENSSL_malloc(sizeof(TLS_SESSION_TICKET_EXT) + ext_len);
|
||||
+ if (!s->tlsext_session_ticket)
|
||||
+ {
|
||||
+ SSLerr(SSL_F_SSL_SET_SESSION_TICKET_EXT, ERR_R_MALLOC_FAILURE);
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ if (ext_data)
|
||||
+ {
|
||||
+ s->tlsext_session_ticket->length = ext_len;
|
||||
+ s->tlsext_session_ticket->data = s->tlsext_session_ticket + 1;
|
||||
+ memcpy(s->tlsext_session_ticket->data, ext_data, ext_len);
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ s->tlsext_session_ticket->length = 0;
|
||||
+ s->tlsext_session_ticket->data = NULL;
|
||||
+ }
|
||||
+
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+ }
|
||||
+#endif /* OPENSSL_NO_TLSEXT */
|
||||
+
|
||||
typedef struct timeout_param_st
|
||||
{
|
||||
SSL_CTX *ctx;
|
||||
diff -upr openssl-0.9.8za.orig/ssl/t1_lib.c openssl-0.9.8za/ssl/t1_lib.c
|
||||
--- openssl-0.9.8za.orig/ssl/t1_lib.c 2014-06-05 11:09:08.000000000 +0300
|
||||
+++ openssl-0.9.8za/ssl/t1_lib.c 2014-06-05 20:37:09.229387312 +0300
|
||||
@@ -106,6 +106,12 @@ int tls1_new(SSL *s)
|
||||
|
||||
void tls1_free(SSL *s)
|
||||
{
|
||||
+#ifndef OPENSSL_NO_TLSEXT
|
||||
+ if (s->tlsext_session_ticket)
|
||||
+ {
|
||||
+ OPENSSL_free(s->tlsext_session_ticket);
|
||||
+ }
|
||||
+#endif
|
||||
ssl3_free(s);
|
||||
}
|
||||
|
||||
@@ -206,8 +212,23 @@ unsigned char *ssl_add_clienthello_tlsex
|
||||
int ticklen;
|
||||
if (!s->new_session && s->session && s->session->tlsext_tick)
|
||||
ticklen = s->session->tlsext_ticklen;
|
||||
+ else if (s->session && s->tlsext_session_ticket &&
|
||||
+ s->tlsext_session_ticket->data)
|
||||
+ {
|
||||
+ ticklen = s->tlsext_session_ticket->length;
|
||||
+ s->session->tlsext_tick = OPENSSL_malloc(ticklen);
|
||||
+ if (!s->session->tlsext_tick)
|
||||
+ return NULL;
|
||||
+ memcpy(s->session->tlsext_tick,
|
||||
+ s->tlsext_session_ticket->data,
|
||||
+ ticklen);
|
||||
+ s->session->tlsext_ticklen = ticklen;
|
||||
+ }
|
||||
else
|
||||
ticklen = 0;
|
||||
+ if (ticklen == 0 && s->tlsext_session_ticket &&
|
||||
+ s->tlsext_session_ticket->data == NULL)
|
||||
+ goto skip_ext;
|
||||
/* Check for enough room 2 for extension type, 2 for len
|
||||
* rest for ticket
|
||||
*/
|
||||
@@ -221,6 +242,7 @@ unsigned char *ssl_add_clienthello_tlsex
|
||||
ret += ticklen;
|
||||
}
|
||||
}
|
||||
+ skip_ext:
|
||||
|
||||
if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp &&
|
||||
s->version != DTLS1_VERSION)
|
||||
@@ -574,6 +596,15 @@ int ssl_parse_clienthello_tlsext(SSL *s,
|
||||
return 0;
|
||||
renegotiate_seen = 1;
|
||||
}
|
||||
+ else if (type == TLSEXT_TYPE_session_ticket)
|
||||
+ {
|
||||
+ if (s->tls_session_ticket_ext_cb &&
|
||||
+ !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg))
|
||||
+ {
|
||||
+ *al = TLS1_AD_INTERNAL_ERROR;
|
||||
+ return 0;
|
||||
+ }
|
||||
+ }
|
||||
else if (type == TLSEXT_TYPE_status_request &&
|
||||
s->version != DTLS1_VERSION && s->ctx->tlsext_status_cb)
|
||||
{
|
||||
@@ -751,6 +782,12 @@ int ssl_parse_serverhello_tlsext(SSL *s,
|
||||
}
|
||||
else if (type == TLSEXT_TYPE_session_ticket)
|
||||
{
|
||||
+ if (s->tls_session_ticket_ext_cb &&
|
||||
+ !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg))
|
||||
+ {
|
||||
+ *al = TLS1_AD_INTERNAL_ERROR;
|
||||
+ return 0;
|
||||
+ }
|
||||
if ((SSL_get_options(s) & SSL_OP_NO_TICKET)
|
||||
|| (size > 0))
|
||||
{
|
||||
@@ -1043,6 +1080,15 @@ int tls1_process_ticket(SSL *s, unsigned
|
||||
s->tlsext_ticket_expected = 1;
|
||||
return 0; /* Cache miss */
|
||||
}
|
||||
+ if (s->tls_session_secret_cb)
|
||||
+ {
|
||||
+ /* Indicate cache miss here and instead of
|
||||
+ * generating the session from ticket now,
|
||||
+ * trigger abbreviated handshake based on
|
||||
+ * external mechanism to calculate the master
|
||||
+ * secret later. */
|
||||
+ return 0;
|
||||
+ }
|
||||
return tls_decrypt_ticket(s, p, size, session_id, len,
|
||||
ret);
|
||||
}
|
||||
diff -upr openssl-0.9.8za.orig/ssl/tls1.h openssl-0.9.8za/ssl/tls1.h
|
||||
--- openssl-0.9.8za.orig/ssl/tls1.h 2014-06-05 11:09:08.000000000 +0300
|
||||
+++ openssl-0.9.8za/ssl/tls1.h 2014-06-05 20:37:09.229387312 +0300
|
||||
@@ -415,6 +415,13 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_T
|
||||
#define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/
|
||||
#endif
|
||||
|
||||
+/* TLS extension struct */
|
||||
+struct tls_session_ticket_ext_st
|
||||
+ {
|
||||
+ unsigned short length;
|
||||
+ void *data;
|
||||
+ };
|
||||
+
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
diff -upr openssl-0.9.8za.orig/util/ssleay.num openssl-0.9.8za/util/ssleay.num
|
||||
--- openssl-0.9.8za.orig/util/ssleay.num 2014-06-05 12:38:45.000000000 +0300
|
||||
+++ openssl-0.9.8za/util/ssleay.num 2014-06-05 20:37:09.229387312 +0300
|
||||
@@ -242,3 +242,5 @@ SSL_set_SSL_CTX
|
||||
SSL_get_servername 291 EXIST::FUNCTION:TLSEXT
|
||||
SSL_get_servername_type 292 EXIST::FUNCTION:TLSEXT
|
||||
SSL_CTX_set_client_cert_engine 293 EXIST::FUNCTION:ENGINE
|
||||
+SSL_set_session_ticket_ext 306 EXIST::FUNCTION:TLSEXT
|
||||
+SSL_set_session_secret_cb 307 EXIST::FUNCTION:TLSEXT
|
@ -1,398 +0,0 @@
|
||||
This patch adds support for TLS SessionTicket extension (RFC 5077) for
|
||||
the parts used by EAP-FAST (RFC 4851).
|
||||
|
||||
This is based on the patch from Alexey Kobozev <akobozev@cisco.com>
|
||||
(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
|
||||
|
||||
OpenSSL 0.9.8zf does not enable TLS extension support by default, so it
|
||||
will need to be enabled by adding enable-tlsext to config script
|
||||
command line.
|
||||
|
||||
|
||||
diff -upr openssl-0.9.8zf.orig/ssl/s3_clnt.c openssl-0.9.8zf/ssl/s3_clnt.c
|
||||
--- openssl-0.9.8zf.orig/ssl/s3_clnt.c 2015-03-19 15:46:46.000000000 +0200
|
||||
+++ openssl-0.9.8zf/ssl/s3_clnt.c 2015-03-24 16:19:14.043911769 +0200
|
||||
@@ -760,6 +760,23 @@ int ssl3_get_server_hello(SSL *s)
|
||||
goto f_err;
|
||||
}
|
||||
|
||||
+#ifndef OPENSSL_NO_TLSEXT
|
||||
+ /* check if we want to resume the session based on external pre-shared secret */
|
||||
+ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb) {
|
||||
+ SSL_CIPHER *pref_cipher = NULL;
|
||||
+
|
||||
+ s->session->master_key_length = sizeof(s->session->master_key);
|
||||
+ if (s->tls_session_secret_cb(s, s->session->master_key,
|
||||
+ &s->session->master_key_length,
|
||||
+ NULL, &pref_cipher,
|
||||
+ s->tls_session_secret_cb_arg)) {
|
||||
+ s->session->cipher = pref_cipher ?
|
||||
+ pref_cipher : ssl_get_cipher_by_char(s, p + j);
|
||||
+ s->s3->flags |= SSL3_FLAGS_CCS_OK;
|
||||
+ }
|
||||
+ }
|
||||
+#endif /* OPENSSL_NO_TLSEXT */
|
||||
+
|
||||
if (j != 0 && j == s->session->session_id_length
|
||||
&& memcmp(p, s->session->session_id, j) == 0) {
|
||||
if (s->sid_ctx_length != s->session->sid_ctx_length
|
||||
@@ -2684,12 +2701,8 @@ int ssl3_check_finished(SSL *s)
|
||||
{
|
||||
int ok;
|
||||
long n;
|
||||
- /*
|
||||
- * If we have no ticket or session ID is non-zero length (a match of a
|
||||
- * non-zero session length would never reach here) it cannot be a resumed
|
||||
- * session.
|
||||
- */
|
||||
- if (!s->session->tlsext_tick || s->session->session_id_length)
|
||||
+ /* If we have no ticket it cannot be a resumed session. */
|
||||
+ if (!s->session->tlsext_tick)
|
||||
return 1;
|
||||
/*
|
||||
* this function is called when we really expect a Certificate message,
|
||||
diff -upr openssl-0.9.8zf.orig/ssl/s3_srvr.c openssl-0.9.8zf/ssl/s3_srvr.c
|
||||
--- openssl-0.9.8zf.orig/ssl/s3_srvr.c 2015-03-19 15:46:46.000000000 +0200
|
||||
+++ openssl-0.9.8zf/ssl/s3_srvr.c 2015-03-24 16:23:34.567909681 +0200
|
||||
@@ -999,6 +999,59 @@ int ssl3_get_client_hello(SSL *s)
|
||||
SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT);
|
||||
goto err;
|
||||
}
|
||||
+
|
||||
+ /* Check if we want to use external pre-shared secret for this
|
||||
+ * handshake for not reused session only. We need to generate
|
||||
+ * server_random before calling tls_session_secret_cb in order to allow
|
||||
+ * SessionTicket processing to use it in key derivation. */
|
||||
+ {
|
||||
+ unsigned long Time;
|
||||
+ unsigned char *pos;
|
||||
+ Time = (unsigned long)time(NULL); /* Time */
|
||||
+ pos = s->s3->server_random;
|
||||
+ l2n(Time, pos);
|
||||
+ if (RAND_pseudo_bytes(pos, SSL3_RANDOM_SIZE - 4) <= 0) {
|
||||
+ al = SSL_AD_INTERNAL_ERROR;
|
||||
+ goto f_err;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb) {
|
||||
+ SSL_CIPHER *pref_cipher = NULL;
|
||||
+
|
||||
+ s->session->master_key_length = sizeof(s->session->master_key);
|
||||
+ if (s->tls_session_secret_cb(s, s->session->master_key,
|
||||
+ &s->session->master_key_length,
|
||||
+ ciphers, &pref_cipher,
|
||||
+ s->tls_session_secret_cb_arg)) {
|
||||
+ s->hit = 1;
|
||||
+ s->session->ciphers = ciphers;
|
||||
+ s->session->verify_result = X509_V_OK;
|
||||
+
|
||||
+ ciphers = NULL;
|
||||
+
|
||||
+ /* check if some cipher was preferred by call back */
|
||||
+ pref_cipher = pref_cipher ? pref_cipher :
|
||||
+ ssl3_choose_cipher(s, s->session->ciphers,
|
||||
+ SSL_get_ciphers(s));
|
||||
+ if (pref_cipher == NULL) {
|
||||
+ al = SSL_AD_HANDSHAKE_FAILURE;
|
||||
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_NO_SHARED_CIPHER);
|
||||
+ goto f_err;
|
||||
+ }
|
||||
+
|
||||
+ s->session->cipher = pref_cipher;
|
||||
+
|
||||
+ if (s->cipher_list)
|
||||
+ sk_SSL_CIPHER_free(s->cipher_list);
|
||||
+
|
||||
+ if (s->cipher_list_by_id)
|
||||
+ sk_SSL_CIPHER_free(s->cipher_list_by_id);
|
||||
+
|
||||
+ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
|
||||
+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
|
||||
+ }
|
||||
+ }
|
||||
#endif
|
||||
/*
|
||||
* Worst case, we will use the NULL compression, but if we have other
|
||||
@@ -1143,15 +1196,21 @@ int ssl3_send_server_hello(SSL *s)
|
||||
unsigned char *buf;
|
||||
unsigned char *p, *d;
|
||||
int i, sl;
|
||||
- unsigned long l, Time;
|
||||
+ unsigned long l;
|
||||
+#ifdef OPENSSL_NO_TLSEXT
|
||||
+ unsigned long Time;
|
||||
+#endif
|
||||
|
||||
if (s->state == SSL3_ST_SW_SRVR_HELLO_A) {
|
||||
buf = (unsigned char *)s->init_buf->data;
|
||||
+#ifdef OPENSSL_NO_TLSEXT
|
||||
p = s->s3->server_random;
|
||||
+ /* Generate server_random if it was not needed previously */
|
||||
Time = (unsigned long)time(NULL); /* Time */
|
||||
l2n(Time, p);
|
||||
if (RAND_pseudo_bytes(p, SSL3_RANDOM_SIZE - 4) <= 0)
|
||||
return -1;
|
||||
+#endif
|
||||
/* Do the message type and length last */
|
||||
d = p = &(buf[4]);
|
||||
|
||||
diff -upr openssl-0.9.8zf.orig/ssl/ssl_err.c openssl-0.9.8zf/ssl/ssl_err.c
|
||||
--- openssl-0.9.8zf.orig/ssl/ssl_err.c 2015-03-19 15:46:46.000000000 +0200
|
||||
+++ openssl-0.9.8zf/ssl/ssl_err.c 2015-03-24 16:35:58.627903717 +0200
|
||||
@@ -316,6 +316,7 @@ static ERR_STRING_DATA SSL_str_functs[]
|
||||
{ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"},
|
||||
{ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
|
||||
{ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"},
|
||||
+ {ERR_FUNC(SSL_F_SSL_SET_SESSION_TICKET_EXT), "SSL_set_session_ticket_ext"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
diff -upr openssl-0.9.8zf.orig/ssl/ssl.h openssl-0.9.8zf/ssl/ssl.h
|
||||
--- openssl-0.9.8zf.orig/ssl/ssl.h 2015-03-19 15:46:46.000000000 +0200
|
||||
+++ openssl-0.9.8zf/ssl/ssl.h 2015-03-24 16:25:44.339908641 +0200
|
||||
@@ -349,6 +349,7 @@ extern "C" {
|
||||
* function parameters used to prototype callbacks in SSL_CTX.
|
||||
*/
|
||||
typedef struct ssl_st *ssl_crock_st;
|
||||
+typedef struct tls_session_ticket_ext_st TLS_SESSION_TICKET_EXT;
|
||||
|
||||
/* used to hold info on the particular ciphers used */
|
||||
typedef struct ssl_cipher_st {
|
||||
@@ -366,6 +367,12 @@ typedef struct ssl_cipher_st {
|
||||
|
||||
DECLARE_STACK_OF(SSL_CIPHER)
|
||||
|
||||
+typedef int (*tls_session_ticket_ext_cb_fn)(SSL *s, const unsigned char *data,
|
||||
+ int len, void *arg);
|
||||
+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len,
|
||||
+ STACK_OF(SSL_CIPHER) *peer_ciphers,
|
||||
+ SSL_CIPHER **cipher, void *arg);
|
||||
+
|
||||
/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
|
||||
typedef struct ssl_method_st {
|
||||
int version;
|
||||
@@ -1116,6 +1123,18 @@ struct ssl_st {
|
||||
int tlsext_ocsp_resplen;
|
||||
/* RFC4507 session ticket expected to be received or sent */
|
||||
int tlsext_ticket_expected;
|
||||
+
|
||||
+ /* TLS Session Ticket extension override */
|
||||
+ TLS_SESSION_TICKET_EXT *tlsext_session_ticket;
|
||||
+
|
||||
+ /* TLS Session Ticket extension callback */
|
||||
+ tls_session_ticket_ext_cb_fn tls_session_ticket_ext_cb;
|
||||
+ void *tls_session_ticket_ext_cb_arg;
|
||||
+
|
||||
+ /* TLS pre-shared secret session resumption */
|
||||
+ tls_session_secret_cb_fn tls_session_secret_cb;
|
||||
+ void *tls_session_secret_cb_arg;
|
||||
+
|
||||
SSL_CTX *initial_ctx; /* initial ctx, used to store sessions */
|
||||
# define session_ctx initial_ctx
|
||||
# else
|
||||
@@ -1772,6 +1791,17 @@ void *SSL_COMP_get_compression_methods(v
|
||||
int SSL_COMP_add_compression_method(int id, void *cm);
|
||||
# endif
|
||||
|
||||
+/* TLS extensions functions */
|
||||
+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len);
|
||||
+
|
||||
+int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
|
||||
+ void *arg);
|
||||
+
|
||||
+/* Pre-shared secret session resumption functions */
|
||||
+int SSL_set_session_secret_cb(SSL *s,
|
||||
+ tls_session_secret_cb_fn tls_session_secret_cb,
|
||||
+ void *arg);
|
||||
+
|
||||
/* BEGIN ERROR CODES */
|
||||
/*
|
||||
* The following lines are auto generated by the script mkerr.pl. Any changes
|
||||
@@ -1977,6 +2007,7 @@ void ERR_load_SSL_strings(void);
|
||||
# define SSL_F_TLS1_ENC 210
|
||||
# define SSL_F_TLS1_SETUP_KEY_BLOCK 211
|
||||
# define SSL_F_WRITE_PENDING 212
|
||||
+#define SSL_F_SSL_SET_SESSION_TICKET_EXT 213
|
||||
|
||||
/* Reason codes. */
|
||||
# define SSL_R_APP_DATA_IN_HANDSHAKE 100
|
||||
diff -upr openssl-0.9.8zf.orig/ssl/ssl_sess.c openssl-0.9.8zf/ssl/ssl_sess.c
|
||||
--- openssl-0.9.8zf.orig/ssl/ssl_sess.c 2015-03-19 15:46:46.000000000 +0200
|
||||
+++ openssl-0.9.8zf/ssl/ssl_sess.c 2015-03-24 16:28:04.819907515 +0200
|
||||
@@ -716,6 +716,61 @@ long SSL_CTX_get_timeout(const SSL_CTX *
|
||||
return (s->session_timeout);
|
||||
}
|
||||
|
||||
+#ifndef OPENSSL_NO_TLSEXT
|
||||
+int SSL_set_session_secret_cb(
|
||||
+ SSL *s,
|
||||
+ int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
|
||||
+ STACK_OF(SSL_CIPHER) *peer_ciphers,
|
||||
+ SSL_CIPHER **cipher, void *arg), void *arg)
|
||||
+{
|
||||
+ if (s == NULL)
|
||||
+ return 0;
|
||||
+ s->tls_session_secret_cb = tls_session_secret_cb;
|
||||
+ s->tls_session_secret_cb_arg = arg;
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
|
||||
+ void *arg)
|
||||
+{
|
||||
+ if (s == NULL)
|
||||
+ return 0;
|
||||
+ s->tls_session_ticket_ext_cb = cb;
|
||||
+ s->tls_session_ticket_ext_cb_arg = arg;
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len)
|
||||
+{
|
||||
+ if (s->version >= TLS1_VERSION) {
|
||||
+ if (s->tlsext_session_ticket) {
|
||||
+ OPENSSL_free(s->tlsext_session_ticket);
|
||||
+ s->tlsext_session_ticket = NULL;
|
||||
+ }
|
||||
+
|
||||
+ s->tlsext_session_ticket = OPENSSL_malloc(
|
||||
+ sizeof(TLS_SESSION_TICKET_EXT) + ext_len);
|
||||
+ if (!s->tlsext_session_ticket) {
|
||||
+ SSLerr(SSL_F_SSL_SET_SESSION_TICKET_EXT, ERR_R_MALLOC_FAILURE);
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ if (ext_data) {
|
||||
+ s->tlsext_session_ticket->length = ext_len;
|
||||
+ s->tlsext_session_ticket->data = s->tlsext_session_ticket + 1;
|
||||
+ memcpy(s->tlsext_session_ticket->data, ext_data, ext_len);
|
||||
+ } else {
|
||||
+ s->tlsext_session_ticket->length = 0;
|
||||
+ s->tlsext_session_ticket->data = NULL;
|
||||
+ }
|
||||
+
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif /* OPENSSL_NO_TLSEXT */
|
||||
+
|
||||
typedef struct timeout_param_st {
|
||||
SSL_CTX *ctx;
|
||||
long time;
|
||||
diff -upr openssl-0.9.8zf.orig/ssl/t1_lib.c openssl-0.9.8zf/ssl/t1_lib.c
|
||||
--- openssl-0.9.8zf.orig/ssl/t1_lib.c 2015-03-19 15:46:46.000000000 +0200
|
||||
+++ openssl-0.9.8zf/ssl/t1_lib.c 2015-03-24 16:32:46.923905254 +0200
|
||||
@@ -108,6 +108,11 @@ int tls1_new(SSL *s)
|
||||
|
||||
void tls1_free(SSL *s)
|
||||
{
|
||||
+#ifndef OPENSSL_NO_TLSEXT
|
||||
+ if (s->tlsext_session_ticket) {
|
||||
+ OPENSSL_free(s->tlsext_session_ticket);
|
||||
+ }
|
||||
+#endif
|
||||
ssl3_free(s);
|
||||
}
|
||||
|
||||
@@ -206,8 +211,20 @@ unsigned char *ssl_add_clienthello_tlsex
|
||||
int ticklen;
|
||||
if (!s->new_session && s->session && s->session->tlsext_tick)
|
||||
ticklen = s->session->tlsext_ticklen;
|
||||
- else
|
||||
+ else if (s->session && s->tlsext_session_ticket &&
|
||||
+ s->tlsext_session_ticket->data) {
|
||||
+ ticklen = s->tlsext_session_ticket->length;
|
||||
+ s->session->tlsext_tick = OPENSSL_malloc(ticklen);
|
||||
+ if (!s->session->tlsext_tick)
|
||||
+ return NULL;
|
||||
+ memcpy(s->session->tlsext_tick, s->tlsext_session_ticket->data,
|
||||
+ ticklen);
|
||||
+ s->session->tlsext_ticklen = ticklen;
|
||||
+ } else
|
||||
ticklen = 0;
|
||||
+ if (ticklen == 0 && s->tlsext_session_ticket &&
|
||||
+ s->tlsext_session_ticket->data == NULL)
|
||||
+ goto skip_ext;
|
||||
/*
|
||||
* Check for enough room 2 for extension type, 2 for len rest for
|
||||
* ticket
|
||||
@@ -221,6 +238,7 @@ unsigned char *ssl_add_clienthello_tlsex
|
||||
ret += ticklen;
|
||||
}
|
||||
}
|
||||
+skip_ext:
|
||||
|
||||
if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp &&
|
||||
s->version != DTLS1_VERSION) {
|
||||
@@ -560,6 +578,14 @@ int ssl_parse_clienthello_tlsext(SSL *s,
|
||||
if (!ssl_parse_clienthello_renegotiate_ext(s, data, size, al))
|
||||
return 0;
|
||||
renegotiate_seen = 1;
|
||||
+ } else if (type == TLSEXT_TYPE_session_ticket) {
|
||||
+ if (s->tls_session_ticket_ext_cb &&
|
||||
+ !s->tls_session_ticket_ext_cb(s, data, size,
|
||||
+ s->tls_session_ticket_ext_cb_arg))
|
||||
+ {
|
||||
+ *al = TLS1_AD_INTERNAL_ERROR;
|
||||
+ return 0;
|
||||
+ }
|
||||
} else if (type == TLSEXT_TYPE_status_request &&
|
||||
s->version != DTLS1_VERSION && s->ctx->tlsext_status_cb) {
|
||||
|
||||
@@ -710,6 +736,13 @@ int ssl_parse_serverhello_tlsext(SSL *s,
|
||||
}
|
||||
tlsext_servername = 1;
|
||||
} else if (type == TLSEXT_TYPE_session_ticket) {
|
||||
+ if (s->tls_session_ticket_ext_cb &&
|
||||
+ !s->tls_session_ticket_ext_cb(
|
||||
+ s, data, size,
|
||||
+ s->tls_session_ticket_ext_cb_arg)) {
|
||||
+ *al = TLS1_AD_INTERNAL_ERROR;
|
||||
+ return 0;
|
||||
+ }
|
||||
if ((SSL_get_options(s) & SSL_OP_NO_TICKET)
|
||||
|| (size > 0)) {
|
||||
*al = TLS1_AD_UNSUPPORTED_EXTENSION;
|
||||
@@ -993,6 +1026,14 @@ int tls1_process_ticket(SSL *s, unsigned
|
||||
s->tlsext_ticket_expected = 1;
|
||||
return 0; /* Cache miss */
|
||||
}
|
||||
+ if (s->tls_session_secret_cb) {
|
||||
+ /* Indicate cache miss here and instead of
|
||||
+ * generating the session from ticket now,
|
||||
+ * trigger abbreviated handshake based on
|
||||
+ * external mechanism to calculate the master
|
||||
+ * secret later. */
|
||||
+ return 0;
|
||||
+ }
|
||||
return tls_decrypt_ticket(s, p, size, session_id, len, ret);
|
||||
}
|
||||
p += size;
|
||||
diff -upr openssl-0.9.8zf.orig/ssl/tls1.h openssl-0.9.8zf/ssl/tls1.h
|
||||
--- openssl-0.9.8zf.orig/ssl/tls1.h 2015-03-19 15:46:46.000000000 +0200
|
||||
+++ openssl-0.9.8zf/ssl/tls1.h 2015-03-24 16:33:31.855904894 +0200
|
||||
@@ -460,6 +460,12 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_T
|
||||
# define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74"
|
||||
# endif
|
||||
|
||||
+/* TLS extension struct */
|
||||
+struct tls_session_ticket_ext_st {
|
||||
+ unsigned short length;
|
||||
+ void *data;
|
||||
+};
|
||||
+
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
diff -upr openssl-0.9.8zf.orig/util/ssleay.num openssl-0.9.8zf/util/ssleay.num
|
||||
--- openssl-0.9.8zf.orig/util/ssleay.num 2015-03-19 15:47:15.000000000 +0200
|
||||
+++ openssl-0.9.8zf/util/ssleay.num 2015-03-24 16:33:51.127904739 +0200
|
||||
@@ -242,3 +242,5 @@ SSL_set_SSL_CTX
|
||||
SSL_get_servername 291 EXIST::FUNCTION:TLSEXT
|
||||
SSL_get_servername_type 292 EXIST::FUNCTION:TLSEXT
|
||||
SSL_CTX_set_client_cert_engine 293 EXIST::FUNCTION:ENGINE
|
||||
+SSL_set_session_ticket_ext 306 EXIST::FUNCTION:TLSEXT
|
||||
+SSL_set_session_secret_cb 307 EXIST::FUNCTION:TLSEXT
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* hostapd / RADIUS Accounting
|
||||
* Copyright (c) 2002-2009, 2012, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2002-2009, 2012-2015, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -41,6 +41,7 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
|
||||
size_t len;
|
||||
int i;
|
||||
struct wpabuf *b;
|
||||
struct os_time now;
|
||||
|
||||
msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST,
|
||||
radius_client_get_id(hapd->radius));
|
||||
@ -49,44 +50,24 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (sta) {
|
||||
radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta));
|
||||
|
||||
if ((hapd->conf->wpa & 2) &&
|
||||
!hapd->conf->disable_pmksa_caching &&
|
||||
sta->eapol_sm && sta->eapol_sm->acct_multi_session_id_hi) {
|
||||
os_snprintf(buf, sizeof(buf), "%08X+%08X",
|
||||
sta->eapol_sm->acct_multi_session_id_hi,
|
||||
sta->eapol_sm->acct_multi_session_id_lo);
|
||||
if (!radius_msg_add_attr(
|
||||
msg, RADIUS_ATTR_ACCT_MULTI_SESSION_ID,
|
||||
(u8 *) buf, os_strlen(buf))) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"Could not add Acct-Multi-Session-Id");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
radius_msg_make_authenticator(msg, (u8 *) hapd, sizeof(*hapd));
|
||||
}
|
||||
|
||||
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_STATUS_TYPE,
|
||||
status_type)) {
|
||||
wpa_printf(MSG_INFO, "Could not add Acct-Status-Type");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
|
||||
RADIUS_ATTR_ACCT_AUTHENTIC) &&
|
||||
!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_AUTHENTIC,
|
||||
hapd->conf->ieee802_1x ?
|
||||
RADIUS_ACCT_AUTHENTIC_RADIUS :
|
||||
RADIUS_ACCT_AUTHENTIC_LOCAL)) {
|
||||
wpa_printf(MSG_INFO, "Could not add Acct-Authentic");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (sta) {
|
||||
if (!hostapd_config_get_radius_attr(
|
||||
hapd->conf->radius_acct_req_attr,
|
||||
RADIUS_ATTR_ACCT_AUTHENTIC) &&
|
||||
!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_AUTHENTIC,
|
||||
hapd->conf->ieee802_1x ?
|
||||
RADIUS_ACCT_AUTHENTIC_RADIUS :
|
||||
RADIUS_ACCT_AUTHENTIC_LOCAL)) {
|
||||
wpa_printf(MSG_INFO, "Could not add Acct-Authentic");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Use 802.1X identity if available */
|
||||
val = ieee802_1x_get_identity(sta->eapol_sm, &len);
|
||||
|
||||
@ -147,6 +128,32 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
|
||||
wpa_printf(MSG_ERROR, "Could not add CUI from ACL");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (sta->ipaddr &&
|
||||
!radius_msg_add_attr_int32(msg,
|
||||
RADIUS_ATTR_FRAMED_IP_ADDRESS,
|
||||
be_to_host32(sta->ipaddr))) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Could not add Framed-IP-Address");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
os_get_time(&now);
|
||||
if (now.sec > 1000000000 &&
|
||||
!radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
|
||||
now.sec)) {
|
||||
wpa_printf(MSG_INFO, "Could not add Event-Timestamp");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add Acct-Delay-Time with zero value for the first transmission. This
|
||||
* will be updated within radius_client.c when retransmitting the frame.
|
||||
*/
|
||||
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_DELAY_TIME, 0)) {
|
||||
wpa_printf(MSG_INFO, "Could not add Acct-Delay-Time");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return msg;
|
||||
@ -164,19 +171,25 @@ static int accounting_sta_update_stats(struct hostapd_data *hapd,
|
||||
if (hostapd_drv_read_sta_data(hapd, data, sta->addr))
|
||||
return -1;
|
||||
|
||||
if (sta->last_rx_bytes > data->rx_bytes)
|
||||
sta->acct_input_gigawords++;
|
||||
if (sta->last_tx_bytes > data->tx_bytes)
|
||||
sta->acct_output_gigawords++;
|
||||
sta->last_rx_bytes = data->rx_bytes;
|
||||
sta->last_tx_bytes = data->tx_bytes;
|
||||
if (!data->bytes_64bit) {
|
||||
/* Extend 32-bit counters from the driver to 64-bit counters */
|
||||
if (sta->last_rx_bytes_lo > data->rx_bytes)
|
||||
sta->last_rx_bytes_hi++;
|
||||
sta->last_rx_bytes_lo = data->rx_bytes;
|
||||
|
||||
if (sta->last_tx_bytes_lo > data->tx_bytes)
|
||||
sta->last_tx_bytes_hi++;
|
||||
sta->last_tx_bytes_lo = data->tx_bytes;
|
||||
}
|
||||
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
|
||||
HOSTAPD_LEVEL_DEBUG, "updated TX/RX stats: "
|
||||
"Acct-Input-Octets=%lu Acct-Input-Gigawords=%u "
|
||||
"Acct-Output-Octets=%lu Acct-Output-Gigawords=%u",
|
||||
sta->last_rx_bytes, sta->acct_input_gigawords,
|
||||
sta->last_tx_bytes, sta->acct_output_gigawords);
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"updated TX/RX stats: rx_bytes=%llu [%u:%u] tx_bytes=%llu [%u:%u] bytes_64bit=%d",
|
||||
data->rx_bytes, sta->last_rx_bytes_hi,
|
||||
sta->last_rx_bytes_lo,
|
||||
data->tx_bytes, sta->last_tx_bytes_hi,
|
||||
sta->last_tx_bytes_lo,
|
||||
data->bytes_64bit);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -217,12 +230,14 @@ void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
|
||||
HOSTAPD_LEVEL_INFO,
|
||||
"starting accounting session %08X-%08X",
|
||||
sta->acct_session_id_hi, sta->acct_session_id_lo);
|
||||
"starting accounting session %016llX",
|
||||
(unsigned long long) sta->acct_session_id);
|
||||
|
||||
os_get_reltime(&sta->acct_session_start);
|
||||
sta->last_rx_bytes = sta->last_tx_bytes = 0;
|
||||
sta->acct_input_gigawords = sta->acct_output_gigawords = 0;
|
||||
sta->last_rx_bytes_hi = 0;
|
||||
sta->last_rx_bytes_lo = 0;
|
||||
sta->last_tx_bytes_hi = 0;
|
||||
sta->last_tx_bytes_lo = 0;
|
||||
hostapd_drv_sta_clear_stats(hapd, sta->addr);
|
||||
|
||||
if (!hapd->conf->radius->acct_server)
|
||||
@ -251,8 +266,7 @@ static void accounting_sta_report(struct hostapd_data *hapd,
|
||||
int cause = sta->acct_terminate_cause;
|
||||
struct hostap_sta_driver_data data;
|
||||
struct os_reltime now_r, diff;
|
||||
struct os_time now;
|
||||
u32 gigawords;
|
||||
u64 bytes;
|
||||
|
||||
if (!hapd->conf->radius->acct_server)
|
||||
return;
|
||||
@ -266,7 +280,6 @@ static void accounting_sta_report(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
os_get_reltime(&now_r);
|
||||
os_get_time(&now);
|
||||
os_reltime_sub(&now_r, &sta->acct_session_start, &diff);
|
||||
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_SESSION_TIME,
|
||||
diff.sec)) {
|
||||
@ -287,48 +300,42 @@ static void accounting_sta_report(struct hostapd_data *hapd,
|
||||
wpa_printf(MSG_INFO, "Could not add Acct-Output-Packets");
|
||||
goto fail;
|
||||
}
|
||||
if (data.bytes_64bit)
|
||||
bytes = data.rx_bytes;
|
||||
else
|
||||
bytes = ((u64) sta->last_rx_bytes_hi << 32) |
|
||||
sta->last_rx_bytes_lo;
|
||||
if (!radius_msg_add_attr_int32(msg,
|
||||
RADIUS_ATTR_ACCT_INPUT_OCTETS,
|
||||
data.rx_bytes)) {
|
||||
(u32) bytes)) {
|
||||
wpa_printf(MSG_INFO, "Could not add Acct-Input-Octets");
|
||||
goto fail;
|
||||
}
|
||||
gigawords = sta->acct_input_gigawords;
|
||||
#if __WORDSIZE == 64
|
||||
gigawords += data.rx_bytes >> 32;
|
||||
#endif
|
||||
if (gigawords &&
|
||||
!radius_msg_add_attr_int32(
|
||||
msg, RADIUS_ATTR_ACCT_INPUT_GIGAWORDS,
|
||||
gigawords)) {
|
||||
if (!radius_msg_add_attr_int32(msg,
|
||||
RADIUS_ATTR_ACCT_INPUT_GIGAWORDS,
|
||||
(u32) (bytes >> 32))) {
|
||||
wpa_printf(MSG_INFO, "Could not add Acct-Input-Gigawords");
|
||||
goto fail;
|
||||
}
|
||||
if (data.bytes_64bit)
|
||||
bytes = data.tx_bytes;
|
||||
else
|
||||
bytes = ((u64) sta->last_tx_bytes_hi << 32) |
|
||||
sta->last_tx_bytes_lo;
|
||||
if (!radius_msg_add_attr_int32(msg,
|
||||
RADIUS_ATTR_ACCT_OUTPUT_OCTETS,
|
||||
data.tx_bytes)) {
|
||||
(u32) bytes)) {
|
||||
wpa_printf(MSG_INFO, "Could not add Acct-Output-Octets");
|
||||
goto fail;
|
||||
}
|
||||
gigawords = sta->acct_output_gigawords;
|
||||
#if __WORDSIZE == 64
|
||||
gigawords += data.tx_bytes >> 32;
|
||||
#endif
|
||||
if (gigawords &&
|
||||
!radius_msg_add_attr_int32(
|
||||
msg, RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS,
|
||||
gigawords)) {
|
||||
if (!radius_msg_add_attr_int32(msg,
|
||||
RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS,
|
||||
(u32) (bytes >> 32))) {
|
||||
wpa_printf(MSG_INFO, "Could not add Acct-Output-Gigawords");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
|
||||
now.sec)) {
|
||||
wpa_printf(MSG_INFO, "Could not add Event-Timestamp");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (eloop_terminated())
|
||||
cause = RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_REBOOT;
|
||||
|
||||
@ -375,22 +382,17 @@ void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
eloop_cancel_timeout(accounting_interim_update, hapd, sta);
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
|
||||
HOSTAPD_LEVEL_INFO,
|
||||
"stopped accounting session %08X-%08X",
|
||||
sta->acct_session_id_hi,
|
||||
sta->acct_session_id_lo);
|
||||
"stopped accounting session %016llX",
|
||||
(unsigned long long) sta->acct_session_id);
|
||||
sta->acct_session_started = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void accounting_sta_get_id(struct hostapd_data *hapd,
|
||||
struct sta_info *sta)
|
||||
int accounting_sta_get_id(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
{
|
||||
sta->acct_session_id_lo = hapd->acct_session_id_lo++;
|
||||
if (hapd->acct_session_id_lo == 0) {
|
||||
hapd->acct_session_id_hi++;
|
||||
}
|
||||
sta->acct_session_id_hi = hapd->acct_session_id_hi;
|
||||
return radius_gen_session_id((u8 *) &sta->acct_session_id,
|
||||
sizeof(sta->acct_session_id));
|
||||
}
|
||||
|
||||
|
||||
@ -437,12 +439,14 @@ static void accounting_report_state(struct hostapd_data *hapd, int on)
|
||||
if (!msg)
|
||||
return;
|
||||
|
||||
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
|
||||
RADIUS_ACCT_TERMINATE_CAUSE_NAS_REBOOT))
|
||||
{
|
||||
wpa_printf(MSG_INFO, "Could not add Acct-Terminate-Cause");
|
||||
radius_msg_free(msg);
|
||||
return;
|
||||
if (hapd->acct_session_id) {
|
||||
char buf[20];
|
||||
|
||||
os_snprintf(buf, sizeof(buf), "%016llX",
|
||||
(unsigned long long) hapd->acct_session_id);
|
||||
if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
|
||||
(u8 *) buf, os_strlen(buf)))
|
||||
wpa_printf(MSG_ERROR, "Could not add Acct-Session-Id");
|
||||
}
|
||||
|
||||
if (radius_client_send(hapd->radius, msg, RADIUS_ACCT, NULL) < 0)
|
||||
@ -450,6 +454,63 @@ static void accounting_report_state(struct hostapd_data *hapd, int on)
|
||||
}
|
||||
|
||||
|
||||
static void accounting_interim_error_cb(const u8 *addr, void *ctx)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
struct sta_info *sta;
|
||||
unsigned int i, wait_time;
|
||||
int res;
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (!sta)
|
||||
return;
|
||||
sta->acct_interim_errors++;
|
||||
if (sta->acct_interim_errors > 10 /* RADIUS_CLIENT_MAX_RETRIES */) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Interim RADIUS accounting update failed for " MACSTR
|
||||
" - too many errors, abandon this interim accounting update",
|
||||
MAC2STR(addr));
|
||||
sta->acct_interim_errors = 0;
|
||||
/* Next update will be tried after normal update interval */
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use a shorter update interval as an improved retransmission mechanism
|
||||
* for failed interim accounting updates. This allows the statistics to
|
||||
* be updated for each retransmission.
|
||||
*
|
||||
* RADIUS client code has already waited RADIUS_CLIENT_FIRST_WAIT.
|
||||
* Schedule the first retry attempt immediately and every following one
|
||||
* with exponential backoff.
|
||||
*/
|
||||
if (sta->acct_interim_errors == 1) {
|
||||
wait_time = 0;
|
||||
} else {
|
||||
wait_time = 3; /* RADIUS_CLIENT_FIRST_WAIT */
|
||||
for (i = 1; i < sta->acct_interim_errors; i++)
|
||||
wait_time *= 2;
|
||||
}
|
||||
res = eloop_deplete_timeout(wait_time, 0, accounting_interim_update,
|
||||
hapd, sta);
|
||||
if (res == 1)
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Interim RADIUS accounting update failed for " MACSTR
|
||||
" (error count: %u) - schedule next update in %u seconds",
|
||||
MAC2STR(addr), sta->acct_interim_errors, wait_time);
|
||||
else if (res == 0)
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Interim RADIUS accounting update failed for " MACSTR
|
||||
" (error count: %u)", MAC2STR(addr),
|
||||
sta->acct_interim_errors);
|
||||
else
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Interim RADIUS accounting update failed for " MACSTR
|
||||
" (error count: %u) - no timer found", MAC2STR(addr),
|
||||
sta->acct_interim_errors);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* accounting_init: Initialize accounting
|
||||
* @hapd: hostapd BSS data
|
||||
@ -457,20 +518,15 @@ static void accounting_report_state(struct hostapd_data *hapd, int on)
|
||||
*/
|
||||
int accounting_init(struct hostapd_data *hapd)
|
||||
{
|
||||
struct os_time now;
|
||||
|
||||
/* Acct-Session-Id should be unique over reboots. Using a random number
|
||||
* is preferred. If that is not available, take the current time. Mix
|
||||
* in microseconds to make this more likely to be unique. */
|
||||
os_get_time(&now);
|
||||
if (os_get_random((u8 *) &hapd->acct_session_id_hi,
|
||||
sizeof(hapd->acct_session_id_hi)) < 0)
|
||||
hapd->acct_session_id_hi = now.sec;
|
||||
hapd->acct_session_id_hi ^= now.usec;
|
||||
if (radius_gen_session_id((u8 *) &hapd->acct_session_id,
|
||||
sizeof(hapd->acct_session_id)) < 0)
|
||||
return -1;
|
||||
|
||||
if (radius_client_register(hapd->radius, RADIUS_ACCT,
|
||||
accounting_receive, hapd))
|
||||
return -1;
|
||||
radius_client_set_interim_error_cb(hapd->radius,
|
||||
accounting_interim_error_cb, hapd);
|
||||
|
||||
accounting_report_state(hapd, 1);
|
||||
|
||||
|
@ -10,9 +10,10 @@
|
||||
#define ACCOUNTING_H
|
||||
|
||||
#ifdef CONFIG_NO_ACCOUNTING
|
||||
static inline void accounting_sta_get_id(struct hostapd_data *hapd,
|
||||
struct sta_info *sta)
|
||||
static inline int accounting_sta_get_id(struct hostapd_data *hapd,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void accounting_sta_start(struct hostapd_data *hapd,
|
||||
@ -34,7 +35,7 @@ static inline void accounting_deinit(struct hostapd_data *hapd)
|
||||
{
|
||||
}
|
||||
#else /* CONFIG_NO_ACCOUNTING */
|
||||
void accounting_sta_get_id(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
int accounting_sta_get_id(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
int accounting_init(struct hostapd_data *hapd);
|
||||
|
@ -599,8 +599,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface)
|
||||
wpa_printf(MSG_DEBUG, "ACS: Survey analysis for selected bandwidth %d MHz",
|
||||
n_chans == 1 ? 20 :
|
||||
n_chans == 2 ? 40 :
|
||||
n_chans == 4 ? 80 :
|
||||
-1);
|
||||
80);
|
||||
|
||||
for (i = 0; i < iface->current_mode->num_channels; i++) {
|
||||
double total_weight;
|
||||
@ -933,6 +932,9 @@ enum hostapd_chan_status acs_init(struct hostapd_iface *iface)
|
||||
return HOSTAPD_CHAN_ACS;
|
||||
}
|
||||
|
||||
if (!iface->current_mode)
|
||||
return HOSTAPD_CHAN_INVALID;
|
||||
|
||||
acs_cleanup(iface);
|
||||
|
||||
err = acs_request_scan(iface);
|
||||
|
@ -38,6 +38,8 @@ static void hostapd_config_free_vlan(struct hostapd_bss_config *bss)
|
||||
|
||||
void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
|
||||
{
|
||||
dl_list_init(&bss->anqp_elem);
|
||||
|
||||
bss->logger_syslog_level = HOSTAPD_LEVEL_INFO;
|
||||
bss->logger_stdout_level = HOSTAPD_LEVEL_INFO;
|
||||
bss->logger_syslog = (unsigned int) -1;
|
||||
@ -63,6 +65,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
|
||||
bss->dtim_period = 2;
|
||||
|
||||
bss->radius_server_auth_port = 1812;
|
||||
bss->eap_sim_db_timeout = 1;
|
||||
bss->ap_max_inactivity = AP_MAX_INACTIVITY;
|
||||
bss->eapol_version = EAPOL_VERSION;
|
||||
|
||||
@ -180,6 +183,7 @@ struct hostapd_config * hostapd_config_defaults(void)
|
||||
conf->ignore_assoc_probability = 0.0;
|
||||
conf->ignore_reassoc_probability = 0.0;
|
||||
conf->corrupt_gtk_rekey_mic_probability = 0.0;
|
||||
conf->ecsa_ie_only = 0;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
conf->acs = 0;
|
||||
@ -198,13 +202,6 @@ int hostapd_mac_comp(const void *a, const void *b)
|
||||
}
|
||||
|
||||
|
||||
int hostapd_mac_comp_empty(const void *a)
|
||||
{
|
||||
macaddr empty = { 0 };
|
||||
return os_memcmp(a, empty, sizeof(macaddr));
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_config_read_wpa_psk(const char *fname,
|
||||
struct hostapd_ssid *ssid)
|
||||
{
|
||||
@ -410,6 +407,19 @@ void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **l)
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_config_free_anqp_elem(struct hostapd_bss_config *conf)
|
||||
{
|
||||
struct anqp_element *elem;
|
||||
|
||||
while ((elem = dl_list_first(&conf->anqp_elem, struct anqp_element,
|
||||
list))) {
|
||||
dl_list_del(&elem->list);
|
||||
wpabuf_free(elem->payload);
|
||||
os_free(elem);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
{
|
||||
struct hostapd_eap_user *user, *prev_user;
|
||||
@ -454,6 +464,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
os_free(conf->private_key);
|
||||
os_free(conf->private_key_passwd);
|
||||
os_free(conf->ocsp_stapling_response);
|
||||
os_free(conf->ocsp_stapling_response_multi);
|
||||
os_free(conf->dh_file);
|
||||
os_free(conf->openssl_ciphers);
|
||||
os_free(conf->pac_opaque_encr_key);
|
||||
@ -523,6 +534,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
os_free(conf->network_auth_type);
|
||||
os_free(conf->anqp_3gpp_cell_net);
|
||||
os_free(conf->domain_name);
|
||||
hostapd_config_free_anqp_elem(conf);
|
||||
|
||||
#ifdef CONFIG_RADIUS_TEST
|
||||
os_free(conf->dump_msk_file);
|
||||
@ -555,6 +567,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
wpabuf_free(conf->vendor_elements);
|
||||
wpabuf_free(conf->assocresp_elements);
|
||||
|
||||
os_free(conf->sae_groups);
|
||||
|
||||
@ -594,6 +607,8 @@ void hostapd_config_free(struct hostapd_config *conf)
|
||||
#ifdef CONFIG_ACS
|
||||
os_free(conf->acs_chan_bias);
|
||||
#endif /* CONFIG_ACS */
|
||||
wpabuf_free(conf->lci);
|
||||
wpabuf_free(conf->civic);
|
||||
|
||||
os_free(conf);
|
||||
}
|
||||
@ -610,7 +625,7 @@ void hostapd_config_free(struct hostapd_config *conf)
|
||||
* Perform a binary search for given MAC address from a pre-sorted list.
|
||||
*/
|
||||
int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries,
|
||||
const u8 *addr, int *vlan_id)
|
||||
const u8 *addr, struct vlan_description *vlan_id)
|
||||
{
|
||||
int start, end, middle, res;
|
||||
|
||||
@ -650,11 +665,26 @@ int hostapd_rate_found(int *list, int rate)
|
||||
}
|
||||
|
||||
|
||||
int hostapd_vlan_id_valid(struct hostapd_vlan *vlan, int vlan_id)
|
||||
int hostapd_vlan_valid(struct hostapd_vlan *vlan,
|
||||
struct vlan_description *vlan_desc)
|
||||
{
|
||||
struct hostapd_vlan *v = vlan;
|
||||
int i;
|
||||
|
||||
if (!vlan_desc->notempty || vlan_desc->untagged < 0 ||
|
||||
vlan_desc->untagged > MAX_VLAN_ID)
|
||||
return 0;
|
||||
for (i = 0; i < MAX_NUM_TAGGED_VLAN; i++) {
|
||||
if (vlan_desc->tagged[i] < 0 ||
|
||||
vlan_desc->tagged[i] > MAX_VLAN_ID)
|
||||
return 0;
|
||||
}
|
||||
if (!vlan_desc->untagged && !vlan_desc->tagged[0])
|
||||
return 0;
|
||||
|
||||
while (v) {
|
||||
if (v->vlan_id == vlan_id || v->vlan_id == VLAN_ID_WILDCARD)
|
||||
if (!vlan_compare(&v->vlan_desc, vlan_desc) ||
|
||||
v->vlan_id == VLAN_ID_WILDCARD)
|
||||
return 1;
|
||||
v = v->next;
|
||||
}
|
||||
@ -756,7 +786,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (full_config && hostapd_mac_comp_empty(bss->bssid) != 0) {
|
||||
if (full_config && !is_zero_ether_addr(bss->bssid)) {
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < conf->num_bss; i++) {
|
||||
@ -811,6 +841,15 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
|
||||
#ifdef CONFIG_IEEE80211AC
|
||||
if (full_config && conf->ieee80211ac &&
|
||||
bss->ssid.security_policy == SECURITY_STATIC_WEP) {
|
||||
bss->disable_11ac = 1;
|
||||
wpa_printf(MSG_ERROR,
|
||||
"VHT (IEEE 802.11ac) with WEP is not allowed, disabling VHT capabilities");
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
|
||||
#ifdef CONFIG_WPS
|
||||
if (full_config && bss->wps_state && bss->ignore_broadcast_ssid) {
|
||||
wpa_printf(MSG_INFO, "WPS: ignore_broadcast_ssid "
|
||||
@ -847,6 +886,15 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
|
||||
}
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
if (full_config && bss->mbo_enabled && (bss->wpa & 2) &&
|
||||
bss->ieee80211w == NO_MGMT_FRAME_PROTECTION) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"MBO: PMF needs to be enabled whenever using WPA2 with MBO");
|
||||
return -1;
|
||||
}
|
||||
#endif /* CONFIG_MBO */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -10,12 +10,14 @@
|
||||
#define HOSTAPD_CONFIG_H
|
||||
|
||||
#include "common/defs.h"
|
||||
#include "utils/list.h"
|
||||
#include "ip_addr.h"
|
||||
#include "common/wpa_common.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/ieee802_11_common.h"
|
||||
#include "wps/wps.h"
|
||||
#include "fst/fst.h"
|
||||
#include "vlan.h"
|
||||
|
||||
/**
|
||||
* mesh_conf - local MBSS state and settings
|
||||
@ -39,6 +41,10 @@ struct mesh_conf {
|
||||
#define MESH_CONF_SEC_AUTH BIT(1)
|
||||
#define MESH_CONF_SEC_AMPE BIT(2)
|
||||
unsigned int security;
|
||||
enum mfp_options ieee80211w;
|
||||
unsigned int pairwise_cipher;
|
||||
unsigned int group_cipher;
|
||||
unsigned int mgmt_group_cipher;
|
||||
int dot11MeshMaxRetries;
|
||||
int dot11MeshRetryTimeout; /* msec */
|
||||
int dot11MeshConfirmTimeout; /* msec */
|
||||
@ -52,7 +58,7 @@ typedef u8 macaddr[ETH_ALEN];
|
||||
|
||||
struct mac_acl_entry {
|
||||
macaddr addr;
|
||||
int vlan_id;
|
||||
struct vlan_description vlan_id;
|
||||
};
|
||||
|
||||
struct hostapd_radius_servers;
|
||||
@ -102,6 +108,7 @@ struct hostapd_ssid {
|
||||
#define DYNAMIC_VLAN_NAMING_WITH_DEVICE 1
|
||||
#define DYNAMIC_VLAN_NAMING_END 2
|
||||
int vlan_naming;
|
||||
int per_sta_vif;
|
||||
#ifdef CONFIG_FULL_DYNAMIC_VLAN
|
||||
char *vlan_tagged_interface;
|
||||
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
|
||||
@ -113,6 +120,7 @@ struct hostapd_ssid {
|
||||
struct hostapd_vlan {
|
||||
struct hostapd_vlan *next;
|
||||
int vlan_id; /* VLAN ID or -1 (VLAN_ID_WILDCARD) for wildcard entry */
|
||||
struct vlan_description vlan_desc;
|
||||
char ifname[IFNAMSIZ + 1];
|
||||
int configured;
|
||||
int dynamic_vlan;
|
||||
@ -124,9 +132,14 @@ struct hostapd_vlan {
|
||||
};
|
||||
|
||||
#define PMK_LEN 32
|
||||
#define MIN_PASSPHRASE_LEN 8
|
||||
#define MAX_PASSPHRASE_LEN 63
|
||||
struct hostapd_sta_wpa_psk_short {
|
||||
struct hostapd_sta_wpa_psk_short *next;
|
||||
unsigned int is_passphrase:1;
|
||||
u8 psk[PMK_LEN];
|
||||
char passphrase[MAX_PASSPHRASE_LEN + 1];
|
||||
int ref; /* (number of references held) - 1 */
|
||||
};
|
||||
|
||||
struct hostapd_wpa_psk {
|
||||
@ -205,6 +218,13 @@ struct hostapd_nai_realm_data {
|
||||
} eap_method[MAX_NAI_EAP_METHODS];
|
||||
};
|
||||
|
||||
struct anqp_element {
|
||||
struct dl_list list;
|
||||
u16 infoid;
|
||||
struct wpabuf *payload;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* struct hostapd_bss_config - Per-BSS configuration
|
||||
*/
|
||||
@ -231,6 +251,7 @@ struct hostapd_bss_config {
|
||||
struct hostapd_eap_user *eap_user;
|
||||
char *eap_user_sqlite;
|
||||
char *eap_sim_db;
|
||||
unsigned int eap_sim_db_timeout;
|
||||
int eap_server_erp; /* Whether ERP is enabled on internal EAP server */
|
||||
struct hostapd_ip_addr own_ip_addr;
|
||||
char *nas_identifier;
|
||||
@ -242,6 +263,7 @@ struct hostapd_bss_config {
|
||||
int radius_das_port;
|
||||
unsigned int radius_das_time_window;
|
||||
int radius_das_require_event_timestamp;
|
||||
int radius_das_require_message_authenticator;
|
||||
struct hostapd_ip_addr radius_das_client_addr;
|
||||
u8 *radius_das_shared_secret;
|
||||
size_t radius_das_shared_secret_len;
|
||||
@ -332,6 +354,7 @@ struct hostapd_bss_config {
|
||||
int check_crl;
|
||||
unsigned int tls_session_lifetime;
|
||||
char *ocsp_stapling_response;
|
||||
char *ocsp_stapling_response_multi;
|
||||
char *dh_file;
|
||||
char *openssl_ciphers;
|
||||
u8 *pac_opaque_encr_key;
|
||||
@ -358,6 +381,7 @@ struct hostapd_bss_config {
|
||||
|
||||
int ap_max_inactivity;
|
||||
int ignore_broadcast_ssid;
|
||||
int no_probe_resp_if_max_sta;
|
||||
|
||||
int wmm_enabled;
|
||||
int wmm_uapsd;
|
||||
@ -481,8 +505,11 @@ struct hostapd_bss_config {
|
||||
unsigned int nai_realm_count;
|
||||
struct hostapd_nai_realm_data *nai_realm_data;
|
||||
|
||||
struct dl_list anqp_elem; /* list of struct anqp_element */
|
||||
|
||||
u16 gas_comeback_delay;
|
||||
int gas_frag_limit;
|
||||
int gas_address3;
|
||||
|
||||
u8 qos_map_set[16 + 2 * 21];
|
||||
unsigned int qos_map_set_len;
|
||||
@ -536,6 +563,7 @@ struct hostapd_bss_config {
|
||||
#endif /* CONFIG_RADIUS_TEST */
|
||||
|
||||
struct wpabuf *vendor_elements;
|
||||
struct wpabuf *assocresp_elements;
|
||||
|
||||
unsigned int sae_anti_clogging_threshold;
|
||||
int *sae_groups;
|
||||
@ -551,12 +579,22 @@ struct hostapd_bss_config {
|
||||
#define MESH_ENABLED BIT(0)
|
||||
int mesh;
|
||||
|
||||
int radio_measurements;
|
||||
u8 radio_measurements[RRM_CAPABILITIES_IE_LEN];
|
||||
|
||||
int vendor_vht;
|
||||
int use_sta_nsts;
|
||||
|
||||
char *no_probe_resp_if_seen_on;
|
||||
char *no_auth_if_seen_on;
|
||||
|
||||
int pbss;
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
int mbo_enabled;
|
||||
#endif /* CONFIG_MBO */
|
||||
|
||||
int ftm_responder;
|
||||
int ftm_initiator;
|
||||
};
|
||||
|
||||
|
||||
@ -638,6 +676,9 @@ struct hostapd_config {
|
||||
u8 vht_oper_centr_freq_seg0_idx;
|
||||
u8 vht_oper_centr_freq_seg1_idx;
|
||||
|
||||
/* Use driver-generated interface addresses when adding multiple BSSs */
|
||||
u8 use_driver_iface_addr;
|
||||
|
||||
#ifdef CONFIG_FST
|
||||
struct fst_iface_cfg fst_cfg;
|
||||
#endif /* CONFIG_FST */
|
||||
@ -652,6 +693,7 @@ struct hostapd_config {
|
||||
double ignore_assoc_probability;
|
||||
double ignore_reassoc_probability;
|
||||
double corrupt_gtk_rekey_mic_probability;
|
||||
int ecsa_ie_only;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
#ifdef CONFIG_ACS
|
||||
@ -662,11 +704,13 @@ struct hostapd_config {
|
||||
} *acs_chan_bias;
|
||||
unsigned int num_acs_chan_bias;
|
||||
#endif /* CONFIG_ACS */
|
||||
|
||||
struct wpabuf *lci;
|
||||
struct wpabuf *civic;
|
||||
};
|
||||
|
||||
|
||||
int hostapd_mac_comp(const void *a, const void *b);
|
||||
int hostapd_mac_comp_empty(const void *a);
|
||||
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);
|
||||
@ -674,13 +718,14 @@ 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);
|
||||
int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries,
|
||||
const u8 *addr, int *vlan_id);
|
||||
const u8 *addr, struct vlan_description *vlan_id);
|
||||
int hostapd_rate_found(int *list, int rate);
|
||||
const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
|
||||
const u8 *addr, const u8 *p2p_dev_addr,
|
||||
const u8 *prev_psk);
|
||||
int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf);
|
||||
int hostapd_vlan_id_valid(struct hostapd_vlan *vlan, int vlan_id);
|
||||
int hostapd_vlan_valid(struct hostapd_vlan *vlan,
|
||||
struct vlan_description *vlan_desc);
|
||||
const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan,
|
||||
int vlan_id);
|
||||
struct hostapd_radius_attr *
|
||||
|
@ -33,10 +33,36 @@ u32 hostapd_sta_flags_to_drv(u32 flags)
|
||||
res |= WPA_STA_SHORT_PREAMBLE;
|
||||
if (flags & WLAN_STA_MFP)
|
||||
res |= WPA_STA_MFP;
|
||||
if (flags & WLAN_STA_AUTH)
|
||||
res |= WPA_STA_AUTHENTICATED;
|
||||
if (flags & WLAN_STA_ASSOC)
|
||||
res |= WPA_STA_ASSOCIATED;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static int add_buf(struct wpabuf **dst, const struct wpabuf *src)
|
||||
{
|
||||
if (!src)
|
||||
return 0;
|
||||
if (wpabuf_resize(dst, wpabuf_len(src)) != 0)
|
||||
return -1;
|
||||
wpabuf_put_buf(*dst, src);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int add_buf_data(struct wpabuf **dst, const u8 *data, size_t len)
|
||||
{
|
||||
if (!data || !len)
|
||||
return 0;
|
||||
if (wpabuf_resize(dst, len) != 0)
|
||||
return -1;
|
||||
wpabuf_put_data(*dst, data, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
|
||||
struct wpabuf **beacon_ret,
|
||||
struct wpabuf **proberesp_ret,
|
||||
@ -49,82 +75,38 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
|
||||
|
||||
pos = buf;
|
||||
pos = hostapd_eid_time_adv(hapd, pos);
|
||||
if (pos != buf) {
|
||||
if (wpabuf_resize(&beacon, pos - buf) != 0)
|
||||
goto fail;
|
||||
wpabuf_put_data(beacon, buf, pos - buf);
|
||||
}
|
||||
if (add_buf_data(&beacon, buf, pos - buf) < 0)
|
||||
goto fail;
|
||||
pos = hostapd_eid_time_zone(hapd, pos);
|
||||
if (pos != buf) {
|
||||
if (wpabuf_resize(&proberesp, pos - buf) != 0)
|
||||
goto fail;
|
||||
wpabuf_put_data(proberesp, buf, pos - buf);
|
||||
}
|
||||
if (add_buf_data(&proberesp, buf, pos - buf) < 0)
|
||||
goto fail;
|
||||
|
||||
pos = buf;
|
||||
pos = hostapd_eid_ext_capab(hapd, pos);
|
||||
if (pos != buf) {
|
||||
if (wpabuf_resize(&assocresp, pos - buf) != 0)
|
||||
goto fail;
|
||||
wpabuf_put_data(assocresp, buf, pos - buf);
|
||||
}
|
||||
if (add_buf_data(&assocresp, buf, pos - buf) < 0)
|
||||
goto fail;
|
||||
pos = hostapd_eid_interworking(hapd, pos);
|
||||
pos = hostapd_eid_adv_proto(hapd, pos);
|
||||
pos = hostapd_eid_roaming_consortium(hapd, pos);
|
||||
if (pos != buf) {
|
||||
if (wpabuf_resize(&beacon, pos - buf) != 0)
|
||||
goto fail;
|
||||
wpabuf_put_data(beacon, buf, pos - buf);
|
||||
|
||||
if (wpabuf_resize(&proberesp, pos - buf) != 0)
|
||||
goto fail;
|
||||
wpabuf_put_data(proberesp, buf, pos - buf);
|
||||
}
|
||||
if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
|
||||
add_buf_data(&proberesp, buf, pos - buf) < 0)
|
||||
goto fail;
|
||||
|
||||
#ifdef CONFIG_FST
|
||||
if (hapd->iface->fst_ies) {
|
||||
size_t add = wpabuf_len(hapd->iface->fst_ies);
|
||||
|
||||
if (wpabuf_resize(&beacon, add) < 0)
|
||||
goto fail;
|
||||
wpabuf_put_buf(beacon, hapd->iface->fst_ies);
|
||||
if (wpabuf_resize(&proberesp, add) < 0)
|
||||
goto fail;
|
||||
wpabuf_put_buf(proberesp, hapd->iface->fst_ies);
|
||||
if (wpabuf_resize(&assocresp, add) < 0)
|
||||
goto fail;
|
||||
wpabuf_put_buf(assocresp, hapd->iface->fst_ies);
|
||||
}
|
||||
if (add_buf(&beacon, hapd->iface->fst_ies) < 0 ||
|
||||
add_buf(&proberesp, hapd->iface->fst_ies) < 0 ||
|
||||
add_buf(&assocresp, hapd->iface->fst_ies) < 0)
|
||||
goto fail;
|
||||
#endif /* CONFIG_FST */
|
||||
|
||||
if (hapd->wps_beacon_ie) {
|
||||
if (wpabuf_resize(&beacon, wpabuf_len(hapd->wps_beacon_ie)) <
|
||||
0)
|
||||
goto fail;
|
||||
wpabuf_put_buf(beacon, hapd->wps_beacon_ie);
|
||||
}
|
||||
|
||||
if (hapd->wps_probe_resp_ie) {
|
||||
if (wpabuf_resize(&proberesp,
|
||||
wpabuf_len(hapd->wps_probe_resp_ie)) < 0)
|
||||
goto fail;
|
||||
wpabuf_put_buf(proberesp, hapd->wps_probe_resp_ie);
|
||||
}
|
||||
if (add_buf(&beacon, hapd->wps_beacon_ie) < 0 ||
|
||||
add_buf(&proberesp, hapd->wps_probe_resp_ie) < 0)
|
||||
goto fail;
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
if (hapd->p2p_beacon_ie) {
|
||||
if (wpabuf_resize(&beacon, wpabuf_len(hapd->p2p_beacon_ie)) <
|
||||
0)
|
||||
goto fail;
|
||||
wpabuf_put_buf(beacon, hapd->p2p_beacon_ie);
|
||||
}
|
||||
|
||||
if (hapd->p2p_probe_resp_ie) {
|
||||
if (wpabuf_resize(&proberesp,
|
||||
wpabuf_len(hapd->p2p_probe_resp_ie)) < 0)
|
||||
goto fail;
|
||||
wpabuf_put_buf(proberesp, hapd->p2p_probe_resp_ie);
|
||||
}
|
||||
if (add_buf(&beacon, hapd->p2p_beacon_ie) < 0 ||
|
||||
add_buf(&proberesp, hapd->p2p_probe_resp_ie) < 0)
|
||||
goto fail;
|
||||
#endif /* CONFIG_P2P */
|
||||
|
||||
#ifdef CONFIG_P2P_MANAGER
|
||||
@ -148,8 +130,7 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
|
||||
#ifdef CONFIG_WPS
|
||||
if (hapd->conf->wps_state) {
|
||||
struct wpabuf *a = wps_build_assoc_resp_ie();
|
||||
if (a && wpabuf_resize(&assocresp, wpabuf_len(a)) == 0)
|
||||
wpabuf_put_buf(assocresp, a);
|
||||
add_buf(&assocresp, a);
|
||||
wpabuf_free(a);
|
||||
}
|
||||
#endif /* CONFIG_WPS */
|
||||
@ -169,44 +150,36 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
|
||||
if (hapd->p2p_group) {
|
||||
struct wpabuf *a;
|
||||
a = p2p_group_assoc_resp_ie(hapd->p2p_group, P2P_SC_SUCCESS);
|
||||
if (a && wpabuf_resize(&assocresp, wpabuf_len(a)) == 0)
|
||||
wpabuf_put_buf(assocresp, a);
|
||||
add_buf(&assocresp, a);
|
||||
wpabuf_free(a);
|
||||
}
|
||||
#endif /* CONFIG_WIFI_DISPLAY */
|
||||
|
||||
#ifdef CONFIG_HS20
|
||||
pos = buf;
|
||||
pos = hostapd_eid_hs20_indication(hapd, pos);
|
||||
if (pos != buf) {
|
||||
if (wpabuf_resize(&beacon, pos - buf) != 0)
|
||||
goto fail;
|
||||
wpabuf_put_data(beacon, buf, pos - buf);
|
||||
|
||||
if (wpabuf_resize(&proberesp, pos - buf) != 0)
|
||||
goto fail;
|
||||
wpabuf_put_data(proberesp, buf, pos - buf);
|
||||
}
|
||||
pos = hostapd_eid_hs20_indication(hapd, buf);
|
||||
if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
|
||||
add_buf_data(&proberesp, buf, pos - buf) < 0)
|
||||
goto fail;
|
||||
|
||||
pos = hostapd_eid_osen(hapd, buf);
|
||||
if (pos != buf) {
|
||||
if (wpabuf_resize(&beacon, pos - buf) != 0)
|
||||
goto fail;
|
||||
wpabuf_put_data(beacon, buf, pos - buf);
|
||||
|
||||
if (wpabuf_resize(&proberesp, pos - buf) != 0)
|
||||
goto fail;
|
||||
wpabuf_put_data(proberesp, buf, pos - buf);
|
||||
}
|
||||
if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
|
||||
add_buf_data(&proberesp, buf, pos - buf) < 0)
|
||||
goto fail;
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
if (hapd->conf->vendor_elements) {
|
||||
size_t add = wpabuf_len(hapd->conf->vendor_elements);
|
||||
if (wpabuf_resize(&beacon, add) == 0)
|
||||
wpabuf_put_buf(beacon, hapd->conf->vendor_elements);
|
||||
if (wpabuf_resize(&proberesp, add) == 0)
|
||||
wpabuf_put_buf(proberesp, hapd->conf->vendor_elements);
|
||||
#ifdef CONFIG_MBO
|
||||
if (hapd->conf->mbo_enabled) {
|
||||
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 ||
|
||||
add_buf_data(&assocresp, buf, pos - buf) < 0)
|
||||
goto fail;
|
||||
}
|
||||
#endif /* CONFIG_MBO */
|
||||
|
||||
add_buf(&beacon, hapd->conf->vendor_elements);
|
||||
add_buf(&proberesp, hapd->conf->vendor_elements);
|
||||
add_buf(&assocresp, hapd->conf->assocresp_elements);
|
||||
|
||||
*beacon_ret = beacon;
|
||||
*proberesp_ret = proberesp;
|
||||
@ -390,7 +363,8 @@ int hostapd_sta_add(struct hostapd_data *hapd,
|
||||
u16 listen_interval,
|
||||
const struct ieee80211_ht_capabilities *ht_capab,
|
||||
const struct ieee80211_vht_capabilities *vht_capab,
|
||||
u32 flags, u8 qosinfo, u8 vht_opmode)
|
||||
u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
|
||||
int set)
|
||||
{
|
||||
struct hostapd_sta_add_params params;
|
||||
|
||||
@ -412,6 +386,8 @@ int hostapd_sta_add(struct hostapd_data *hapd,
|
||||
params.vht_opmode = vht_opmode;
|
||||
params.flags = hostapd_sta_flags_to_drv(flags);
|
||||
params.qosinfo = qosinfo;
|
||||
params.support_p2p_ps = supp_p2p_ps;
|
||||
params.set = set;
|
||||
return hapd->driver->sta_add(hapd->drv_priv, ¶ms);
|
||||
}
|
||||
|
||||
@ -468,7 +444,7 @@ int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
|
||||
return -1;
|
||||
return hapd->driver->if_add(hapd->drv_priv, type, ifname, addr,
|
||||
bss_ctx, drv_priv, force_ifname, if_addr,
|
||||
bridge, use_existing);
|
||||
bridge, use_existing, 1);
|
||||
}
|
||||
|
||||
|
||||
@ -646,17 +622,29 @@ int hostapd_drv_set_key(const char *ifname, struct hostapd_data *hapd,
|
||||
|
||||
int hostapd_drv_send_mlme(struct hostapd_data *hapd,
|
||||
const void *msg, size_t len, int noack)
|
||||
{
|
||||
if (!hapd->driver || !hapd->driver->send_mlme || !hapd->drv_priv)
|
||||
return 0;
|
||||
return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0,
|
||||
NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_drv_send_mlme_csa(struct hostapd_data *hapd,
|
||||
const void *msg, size_t len, int noack,
|
||||
const u16 *csa_offs, size_t csa_offs_len)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->send_mlme == NULL)
|
||||
return 0;
|
||||
return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0);
|
||||
return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0,
|
||||
csa_offs, csa_offs_len);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
|
||||
const u8 *addr, int reason)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->sta_deauth == NULL)
|
||||
if (!hapd->driver || !hapd->driver->sta_deauth || !hapd->drv_priv)
|
||||
return 0;
|
||||
return hapd->driver->sta_deauth(hapd->drv_priv, hapd->own_addr, addr,
|
||||
reason);
|
||||
@ -666,7 +654,7 @@ int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
|
||||
int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
|
||||
const u8 *addr, int reason)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->sta_disassoc == NULL)
|
||||
if (!hapd->driver || !hapd->driver->sta_disassoc || !hapd->drv_priv)
|
||||
return 0;
|
||||
return hapd->driver->sta_disassoc(hapd->drv_priv, hapd->own_addr, addr,
|
||||
reason);
|
||||
@ -686,6 +674,36 @@ int hostapd_drv_wnm_oper(struct hostapd_data *hapd, enum wnm_oper oper,
|
||||
int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
|
||||
unsigned int wait, const u8 *dst, const u8 *data,
|
||||
size_t len)
|
||||
{
|
||||
const u8 *bssid;
|
||||
const u8 wildcard_bssid[ETH_ALEN] = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
||||
};
|
||||
|
||||
if (!hapd->driver || !hapd->driver->send_action || !hapd->drv_priv)
|
||||
return 0;
|
||||
bssid = hapd->own_addr;
|
||||
if (!is_multicast_ether_addr(dst) &&
|
||||
len > 0 && data[0] == WLAN_ACTION_PUBLIC) {
|
||||
struct sta_info *sta;
|
||||
|
||||
/*
|
||||
* Public Action frames to a STA that is not a member of the BSS
|
||||
* shall use wildcard BSSID value.
|
||||
*/
|
||||
sta = ap_get_sta(hapd, dst);
|
||||
if (!sta || !(sta->flags & WLAN_STA_ASSOC))
|
||||
bssid = wildcard_bssid;
|
||||
}
|
||||
return hapd->driver->send_action(hapd->drv_priv, freq, wait, dst,
|
||||
hapd->own_addr, bssid, data, len, 0);
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->send_action == NULL)
|
||||
return 0;
|
||||
@ -736,7 +754,7 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
|
||||
int hostapd_drv_set_qos_map(struct hostapd_data *hapd,
|
||||
const u8 *qos_map_set, u8 qos_map_set_len)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->set_qos_map == NULL)
|
||||
if (!hapd->driver || !hapd->driver->set_qos_map || !hapd->drv_priv)
|
||||
return 0;
|
||||
return hapd->driver->set_qos_map(hapd->drv_priv, qos_map_set,
|
||||
qos_map_set_len);
|
||||
@ -762,6 +780,20 @@ static void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
void hostapd_get_ext_capa(struct hostapd_iface *iface)
|
||||
{
|
||||
struct hostapd_data *hapd = iface->bss[0];
|
||||
|
||||
if (!hapd->driver || !hapd->driver->get_ext_capab)
|
||||
return;
|
||||
|
||||
hapd->driver->get_ext_capab(hapd->drv_priv, WPA_IF_AP_BSS,
|
||||
&iface->extended_capa,
|
||||
&iface->extended_capa_mask,
|
||||
&iface->extended_capa_len);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_drv_do_acs(struct hostapd_data *hapd)
|
||||
{
|
||||
struct drv_acs_params params;
|
||||
|
@ -41,7 +41,8 @@ int hostapd_sta_add(struct hostapd_data *hapd,
|
||||
u16 listen_interval,
|
||||
const struct ieee80211_ht_capabilities *ht_capab,
|
||||
const struct ieee80211_vht_capabilities *vht_capab,
|
||||
u32 flags, u8 qosinfo, u8 vht_opmode);
|
||||
u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
|
||||
int set);
|
||||
int hostapd_set_privacy(struct hostapd_data *hapd, int enabled);
|
||||
int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem,
|
||||
size_t elem_len);
|
||||
@ -88,6 +89,9 @@ int hostapd_drv_set_key(const char *ifname,
|
||||
const u8 *key, size_t key_len);
|
||||
int hostapd_drv_send_mlme(struct hostapd_data *hapd,
|
||||
const void *msg, size_t len, int noack);
|
||||
int hostapd_drv_send_mlme_csa(struct hostapd_data *hapd,
|
||||
const void *msg, size_t len, int noack,
|
||||
const u16 *csa_offs, size_t csa_offs_len);
|
||||
int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
|
||||
const u8 *addr, int reason);
|
||||
int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
|
||||
@ -95,6 +99,10 @@ int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
|
||||
int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
|
||||
unsigned int wait, const u8 *dst, const u8 *data,
|
||||
size_t len);
|
||||
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);
|
||||
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,
|
||||
@ -120,6 +128,8 @@ int hostapd_drv_wnm_oper(struct hostapd_data *hapd,
|
||||
int hostapd_drv_set_qos_map(struct hostapd_data *hapd, const u8 *qos_map_set,
|
||||
u8 qos_map_set_len);
|
||||
|
||||
void hostapd_get_ext_capa(struct hostapd_iface *iface);
|
||||
|
||||
static inline int hostapd_drv_set_countermeasures(struct hostapd_data *hapd,
|
||||
int enabled)
|
||||
{
|
||||
@ -150,7 +160,7 @@ static inline int hostapd_drv_get_inact_sec(struct hostapd_data *hapd,
|
||||
static inline int hostapd_drv_sta_remove(struct hostapd_data *hapd,
|
||||
const u8 *addr)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->sta_remove == NULL)
|
||||
if (!hapd->driver || !hapd->driver->sta_remove || !hapd->drv_priv)
|
||||
return 0;
|
||||
return hapd->driver->sta_remove(hapd->drv_priv, addr);
|
||||
}
|
||||
@ -273,7 +283,7 @@ static inline int hostapd_drv_switch_channel(struct hostapd_data *hapd,
|
||||
static inline int hostapd_drv_status(struct hostapd_data *hapd, char *buf,
|
||||
size_t buflen)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->status == NULL)
|
||||
if (!hapd->driver || !hapd->driver->status || !hapd->drv_priv)
|
||||
return -1;
|
||||
return hapd->driver->status(hapd->drv_priv, buf, buflen);
|
||||
}
|
||||
@ -332,7 +342,7 @@ static inline int hostapd_drv_vendor_cmd(struct hostapd_data *hapd,
|
||||
|
||||
static inline int hostapd_drv_stop_ap(struct hostapd_data *hapd)
|
||||
{
|
||||
if (hapd->driver == NULL || hapd->driver->stop_ap == NULL)
|
||||
if (!hapd->driver || !hapd->driver->stop_ap || !hapd->drv_priv)
|
||||
return 0;
|
||||
return hapd->driver->stop_ap(hapd->drv_priv);
|
||||
}
|
||||
|
@ -59,6 +59,7 @@ void mlme_authenticate_indication(struct hostapd_data *hapd,
|
||||
MAC2STR(sta->addr), mlme_auth_alg_str(sta->auth_alg));
|
||||
if (sta->auth_alg != WLAN_AUTH_FT && !(sta->flags & WLAN_STA_MFP))
|
||||
mlme_deletekeys_request(hapd, sta);
|
||||
ap_sta_clear_disconnect_timeouts(hapd, sta);
|
||||
}
|
||||
|
||||
|
||||
@ -106,6 +107,7 @@ void mlme_associate_indication(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
MAC2STR(sta->addr));
|
||||
if (sta->auth_alg != WLAN_AUTH_FT)
|
||||
mlme_deletekeys_request(hapd, sta);
|
||||
ap_sta_clear_disconnect_timeouts(hapd, sta);
|
||||
}
|
||||
|
||||
|
||||
@ -130,6 +132,7 @@ void mlme_reassociate_indication(struct hostapd_data *hapd,
|
||||
MAC2STR(sta->addr));
|
||||
if (sta->auth_alg != WLAN_AUTH_FT)
|
||||
mlme_deletekeys_request(hapd, sta);
|
||||
ap_sta_clear_disconnect_timeouts(hapd, sta);
|
||||
}
|
||||
|
||||
|
||||
|
@ -173,6 +173,8 @@ int authsrv_init(struct hostapd_data *hapd)
|
||||
params.openssl_ciphers = hapd->conf->openssl_ciphers;
|
||||
params.ocsp_stapling_response =
|
||||
hapd->conf->ocsp_stapling_response;
|
||||
params.ocsp_stapling_response_multi =
|
||||
hapd->conf->ocsp_stapling_response_multi;
|
||||
|
||||
if (tls_global_set_params(hapd->ssl_ctx, ¶ms)) {
|
||||
wpa_printf(MSG_ERROR, "Failed to set TLS parameters");
|
||||
@ -193,6 +195,7 @@ int authsrv_init(struct hostapd_data *hapd)
|
||||
if (hapd->conf->eap_sim_db) {
|
||||
hapd->eap_sim_db_priv =
|
||||
eap_sim_db_init(hapd->conf->eap_sim_db,
|
||||
hapd->conf->eap_sim_db_timeout,
|
||||
hostapd_sim_db_cb, hapd);
|
||||
if (hapd->eap_sim_db_priv == NULL) {
|
||||
wpa_printf(MSG_ERROR, "Failed to initialize EAP-SIM "
|
||||
|
242
src/ap/beacon.c
242
src/ap/beacon.c
@ -29,6 +29,7 @@
|
||||
#include "beacon.h"
|
||||
#include "hs20.h"
|
||||
#include "dfs.h"
|
||||
#include "taxonomy.h"
|
||||
|
||||
|
||||
#ifdef NEED_AP_MLME
|
||||
@ -36,18 +37,21 @@
|
||||
static u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
|
||||
size_t len)
|
||||
{
|
||||
if (!hapd->conf->radio_measurements || len < 2 + 4)
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) {
|
||||
if (hapd->conf->radio_measurements[i])
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == RRM_CAPABILITIES_IE_LEN || len < 2 + RRM_CAPABILITIES_IE_LEN)
|
||||
return eid;
|
||||
|
||||
*eid++ = WLAN_EID_RRM_ENABLED_CAPABILITIES;
|
||||
*eid++ = 5;
|
||||
*eid++ = (hapd->conf->radio_measurements & BIT(0)) ?
|
||||
WLAN_RRM_CAPS_NEIGHBOR_REPORT : 0x00;
|
||||
*eid++ = 0x00;
|
||||
*eid++ = 0x00;
|
||||
*eid++ = 0x00;
|
||||
*eid++ = 0x00;
|
||||
return eid;
|
||||
*eid++ = RRM_CAPABILITIES_IE_LEN;
|
||||
os_memcpy(eid, hapd->conf->radio_measurements, RRM_CAPABILITIES_IE_LEN);
|
||||
|
||||
return eid + RRM_CAPABILITIES_IE_LEN;
|
||||
}
|
||||
|
||||
|
||||
@ -297,65 +301,65 @@ static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len)
|
||||
|
||||
static u8 * hostapd_eid_csa(struct hostapd_data *hapd, u8 *eid)
|
||||
{
|
||||
u8 chan;
|
||||
|
||||
if (!hapd->cs_freq_params.freq)
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
if (hapd->iface->cs_oper_class && hapd->iconf->ecsa_ie_only)
|
||||
return eid;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
if (ieee80211_freq_to_chan(hapd->cs_freq_params.freq, &chan) ==
|
||||
NUM_HOSTAPD_MODES)
|
||||
if (!hapd->cs_freq_params.channel)
|
||||
return eid;
|
||||
|
||||
*eid++ = WLAN_EID_CHANNEL_SWITCH;
|
||||
*eid++ = 3;
|
||||
*eid++ = hapd->cs_block_tx;
|
||||
*eid++ = chan;
|
||||
*eid++ = hapd->cs_freq_params.channel;
|
||||
*eid++ = hapd->cs_count;
|
||||
|
||||
return eid;
|
||||
}
|
||||
|
||||
|
||||
static u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid)
|
||||
static u8 * hostapd_eid_ecsa(struct hostapd_data *hapd, u8 *eid)
|
||||
{
|
||||
u8 sec_ch;
|
||||
|
||||
if (!hapd->cs_freq_params.sec_channel_offset)
|
||||
if (!hapd->cs_freq_params.channel || !hapd->iface->cs_oper_class)
|
||||
return eid;
|
||||
|
||||
if (hapd->cs_freq_params.sec_channel_offset == -1)
|
||||
sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW;
|
||||
else if (hapd->cs_freq_params.sec_channel_offset == 1)
|
||||
sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE;
|
||||
else
|
||||
return eid;
|
||||
|
||||
*eid++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET;
|
||||
*eid++ = 1;
|
||||
*eid++ = sec_ch;
|
||||
*eid++ = WLAN_EID_EXT_CHANSWITCH_ANN;
|
||||
*eid++ = 4;
|
||||
*eid++ = hapd->cs_block_tx;
|
||||
*eid++ = hapd->iface->cs_oper_class;
|
||||
*eid++ = hapd->cs_freq_params.channel;
|
||||
*eid++ = hapd->cs_count;
|
||||
|
||||
return eid;
|
||||
}
|
||||
|
||||
|
||||
static u8 * hostapd_add_csa_elems(struct hostapd_data *hapd, u8 *pos,
|
||||
u8 *start, unsigned int *csa_counter_off)
|
||||
static u8 * hostapd_eid_supported_op_classes(struct hostapd_data *hapd, u8 *eid)
|
||||
{
|
||||
u8 *old_pos = pos;
|
||||
u8 op_class, channel;
|
||||
|
||||
if (!csa_counter_off)
|
||||
return pos;
|
||||
if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA) ||
|
||||
!hapd->iface->freq)
|
||||
return eid;
|
||||
|
||||
*csa_counter_off = 0;
|
||||
pos = hostapd_eid_csa(hapd, pos);
|
||||
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 eid;
|
||||
|
||||
if (pos != old_pos) {
|
||||
/* save an offset to the counter - should be last byte */
|
||||
*csa_counter_off = pos - start - 1;
|
||||
pos = hostapd_eid_secondary_channel(hapd, pos);
|
||||
}
|
||||
*eid++ = WLAN_EID_SUPPORTED_OPERATING_CLASSES;
|
||||
*eid++ = 2;
|
||||
|
||||
return pos;
|
||||
/* Current Operating Class */
|
||||
*eid++ = op_class;
|
||||
|
||||
/* TODO: Advertise all the supported operating classes */
|
||||
*eid++ = 0;
|
||||
|
||||
return eid;
|
||||
}
|
||||
|
||||
|
||||
@ -364,7 +368,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
|
||||
int is_p2p, size_t *resp_len)
|
||||
{
|
||||
struct ieee80211_mgmt *resp;
|
||||
u8 *pos, *epos;
|
||||
u8 *pos, *epos, *csa_pos;
|
||||
size_t buflen;
|
||||
|
||||
#define MAX_PROBERESP_LEN 768
|
||||
@ -387,6 +391,9 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
|
||||
buflen += 5 + 2 + sizeof(struct ieee80211_vht_capabilities) +
|
||||
2 + sizeof(struct ieee80211_vht_operation);
|
||||
}
|
||||
|
||||
buflen += hostapd_mbo_ie_len(hapd);
|
||||
|
||||
resp = os_zalloc(buflen);
|
||||
if (resp == NULL)
|
||||
return NULL;
|
||||
@ -424,6 +431,12 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
|
||||
/* Power Constraint element */
|
||||
pos = hostapd_eid_pwr_constraint(hapd, pos);
|
||||
|
||||
/* CSA IE */
|
||||
csa_pos = hostapd_eid_csa(hapd, pos);
|
||||
if (csa_pos != pos)
|
||||
hapd->cs_c_off_proberesp = csa_pos - (u8 *) resp - 1;
|
||||
pos = csa_pos;
|
||||
|
||||
/* ERP Information element */
|
||||
pos = hostapd_eid_erp_info(hapd, pos);
|
||||
|
||||
@ -437,7 +450,19 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
|
||||
|
||||
pos = hostapd_eid_rm_enabled_capab(hapd, pos, epos - pos);
|
||||
|
||||
/* eCSA IE */
|
||||
csa_pos = hostapd_eid_ecsa(hapd, pos);
|
||||
if (csa_pos != pos)
|
||||
hapd->cs_c_off_ecsa_proberesp = csa_pos - (u8 *) resp - 1;
|
||||
pos = csa_pos;
|
||||
|
||||
pos = hostapd_eid_supported_op_classes(hapd, pos);
|
||||
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
/* Secondary Channel Offset element */
|
||||
/* TODO: The standard doesn't specify a position for this element. */
|
||||
pos = hostapd_eid_secondary_channel(hapd, pos);
|
||||
|
||||
pos = hostapd_eid_ht_capabilities(hapd, pos);
|
||||
pos = hostapd_eid_ht_operation(hapd, pos);
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
@ -451,9 +476,6 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
|
||||
pos = hostapd_eid_adv_proto(hapd, pos);
|
||||
pos = hostapd_eid_roaming_consortium(hapd, pos);
|
||||
|
||||
pos = hostapd_add_csa_elems(hapd, pos, (u8 *)resp,
|
||||
&hapd->cs_c_off_proberesp);
|
||||
|
||||
#ifdef CONFIG_FST
|
||||
if (hapd->iface->fst_ies) {
|
||||
os_memcpy(pos, wpabuf_head(hapd->iface->fst_ies),
|
||||
@ -464,8 +486,10 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
|
||||
|
||||
#ifdef CONFIG_IEEE80211AC
|
||||
if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
|
||||
pos = hostapd_eid_vht_capabilities(hapd, pos);
|
||||
pos = hostapd_eid_vht_capabilities(hapd, pos, 0);
|
||||
pos = hostapd_eid_vht_operation(hapd, pos);
|
||||
pos = hostapd_eid_txpower_envelope(hapd, pos);
|
||||
pos = hostapd_eid_wb_chsw_wrapper(hapd, pos);
|
||||
}
|
||||
if (hapd->conf->vendor_vht)
|
||||
pos = hostapd_eid_vendor_vht(hapd, pos);
|
||||
@ -501,6 +525,8 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
|
||||
pos = hostapd_eid_osen(hapd, pos);
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
pos = hostapd_eid_mbo(hapd, pos, (u8 *) resp + buflen - pos);
|
||||
|
||||
if (hapd->conf->vendor_elements) {
|
||||
os_memcpy(pos, wpabuf_head(hapd->conf->vendor_elements),
|
||||
wpabuf_len(hapd->conf->vendor_elements));
|
||||
@ -537,8 +563,8 @@ static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
|
||||
|
||||
pos = ssid_list;
|
||||
end = ssid_list + ssid_list_len;
|
||||
while (pos + 1 <= end) {
|
||||
if (pos + 2 + pos[1] > end)
|
||||
while (end - pos >= 1) {
|
||||
if (2 + pos[1] > end - pos)
|
||||
break;
|
||||
if (pos[1] == 0)
|
||||
wildcard = 1;
|
||||
@ -574,7 +600,7 @@ void sta_track_expire(struct hostapd_iface *iface, int force)
|
||||
MAC2STR(info->addr));
|
||||
dl_list_del(&info->list);
|
||||
iface->num_sta_seen--;
|
||||
os_free(info);
|
||||
sta_track_del(info);
|
||||
}
|
||||
}
|
||||
|
||||
@ -607,6 +633,8 @@ void sta_track_add(struct hostapd_iface *iface, const u8 *addr)
|
||||
|
||||
/* Add a new entry */
|
||||
info = os_zalloc(sizeof(*info));
|
||||
if (info == NULL)
|
||||
return;
|
||||
os_memcpy(info->addr, addr, ETH_ALEN);
|
||||
os_get_reltime(&info->last_seen);
|
||||
|
||||
@ -648,6 +676,23 @@ sta_track_seen_on(struct hostapd_iface *iface, const u8 *addr,
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_TAXONOMY
|
||||
void sta_track_claim_taxonomy_info(struct hostapd_iface *iface, const u8 *addr,
|
||||
struct wpabuf **probe_ie_taxonomy)
|
||||
{
|
||||
struct hostapd_sta_info *info;
|
||||
|
||||
info = sta_track_get(iface, addr);
|
||||
if (!info)
|
||||
return;
|
||||
|
||||
wpabuf_free(*probe_ie_taxonomy);
|
||||
*probe_ie_taxonomy = info->probe_ie_taxonomy;
|
||||
info->probe_ie_taxonomy = NULL;
|
||||
}
|
||||
#endif /* CONFIG_TAXONOMY */
|
||||
|
||||
|
||||
void handle_probe_req(struct hostapd_data *hapd,
|
||||
const struct ieee80211_mgmt *mgmt, size_t len,
|
||||
int ssi_signal)
|
||||
@ -659,13 +704,16 @@ void handle_probe_req(struct hostapd_data *hapd,
|
||||
size_t i, resp_len;
|
||||
int noack;
|
||||
enum ssid_match_result res;
|
||||
int ret;
|
||||
u16 csa_offs[2];
|
||||
size_t csa_offs_len;
|
||||
|
||||
ie = mgmt->u.probe_req.variable;
|
||||
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
|
||||
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);
|
||||
ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
|
||||
ie_len = len - IEEE80211_HDRLEN;
|
||||
|
||||
for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++)
|
||||
if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
|
||||
@ -711,7 +759,7 @@ void handle_probe_req(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
if (hapd->p2p && elems.wps_ie) {
|
||||
if (hapd->p2p && hapd->p2p_group && elems.wps_ie) {
|
||||
struct wpabuf *wps;
|
||||
wps = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA);
|
||||
if (wps && !p2p_group_match_dev_type(hapd->p2p_group, wps)) {
|
||||
@ -724,7 +772,7 @@ void handle_probe_req(struct hostapd_data *hapd,
|
||||
wpabuf_free(wps);
|
||||
}
|
||||
|
||||
if (hapd->p2p && elems.p2p) {
|
||||
if (hapd->p2p && hapd->p2p_group && elems.p2p) {
|
||||
struct wpabuf *p2p;
|
||||
p2p = ieee802_11_vendor_ie_concat(ie, ie_len, P2P_IE_VENDOR_TYPE);
|
||||
if (p2p && !p2p_group_match_dev_id(hapd->p2p_group, p2p)) {
|
||||
@ -754,6 +802,21 @@ void handle_probe_req(struct hostapd_data *hapd,
|
||||
}
|
||||
#endif /* CONFIG_P2P */
|
||||
|
||||
#ifdef CONFIG_TAXONOMY
|
||||
{
|
||||
struct sta_info *sta;
|
||||
struct hostapd_sta_info *info;
|
||||
|
||||
if ((sta = ap_get_sta(hapd, mgmt->sa)) != NULL) {
|
||||
taxonomy_sta_info_probe_req(hapd, sta, ie, ie_len);
|
||||
} else if ((info = sta_track_get(hapd->iface,
|
||||
mgmt->sa)) != NULL) {
|
||||
taxonomy_hostapd_sta_info_probe_req(hapd, info,
|
||||
ie, ie_len);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_TAXONOMY */
|
||||
|
||||
res = ssid_match(hapd, elems.ssid, elems.ssid_len,
|
||||
elems.ssid_list, elems.ssid_list_len);
|
||||
if (res == NO_SSID_MATCH) {
|
||||
@ -825,6 +888,17 @@ void handle_probe_req(struct hostapd_data *hapd,
|
||||
return;
|
||||
}
|
||||
|
||||
if (hapd->conf->no_probe_resp_if_max_sta &&
|
||||
is_multicast_ether_addr(mgmt->da) &&
|
||||
is_multicast_ether_addr(mgmt->bssid) &&
|
||||
hapd->num_sta >= hapd->conf->max_num_sta &&
|
||||
!ap_get_sta(hapd, mgmt->sa)) {
|
||||
wpa_printf(MSG_MSGDUMP, "%s: Ignore Probe Request from " MACSTR
|
||||
" since no room for additional STA",
|
||||
hapd->conf->iface, MAC2STR(mgmt->sa));
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TESTING_OPTIONS
|
||||
if (hapd->iconf->ignore_probe_probability > 0.0 &&
|
||||
drand48() < hapd->iconf->ignore_probe_probability) {
|
||||
@ -847,7 +921,22 @@ void handle_probe_req(struct hostapd_data *hapd,
|
||||
noack = !!(res == WILDCARD_SSID_MATCH &&
|
||||
is_broadcast_ether_addr(mgmt->da));
|
||||
|
||||
if (hostapd_drv_send_mlme(hapd, resp, resp_len, noack) < 0)
|
||||
csa_offs_len = 0;
|
||||
if (hapd->csa_in_progress) {
|
||||
if (hapd->cs_c_off_proberesp)
|
||||
csa_offs[csa_offs_len++] =
|
||||
hapd->cs_c_off_proberesp;
|
||||
|
||||
if (hapd->cs_c_off_ecsa_proberesp)
|
||||
csa_offs[csa_offs_len++] =
|
||||
hapd->cs_c_off_ecsa_proberesp;
|
||||
}
|
||||
|
||||
ret = hostapd_drv_send_mlme_csa(hapd, resp, resp_len, noack,
|
||||
csa_offs_len ? csa_offs : NULL,
|
||||
csa_offs_len);
|
||||
|
||||
if (ret < 0)
|
||||
wpa_printf(MSG_INFO, "handle_probe_req: send failed");
|
||||
|
||||
os_free(resp);
|
||||
@ -896,6 +985,16 @@ static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd,
|
||||
#endif /* NEED_AP_MLME */
|
||||
|
||||
|
||||
void sta_track_del(struct hostapd_sta_info *info)
|
||||
{
|
||||
#ifdef CONFIG_TAXONOMY
|
||||
wpabuf_free(info->probe_ie_taxonomy);
|
||||
info->probe_ie_taxonomy = NULL;
|
||||
#endif /* CONFIG_TAXONOMY */
|
||||
os_free(info);
|
||||
}
|
||||
|
||||
|
||||
int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
struct wpa_driver_ap_params *params)
|
||||
{
|
||||
@ -906,7 +1005,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
size_t resp_len = 0;
|
||||
#ifdef NEED_AP_MLME
|
||||
u16 capab_info;
|
||||
u8 *pos, *tailpos;
|
||||
u8 *pos, *tailpos, *csa_pos;
|
||||
|
||||
#define BEACON_HEAD_BUF_SIZE 256
|
||||
#define BEACON_TAIL_BUF_SIZE 512
|
||||
@ -934,6 +1033,8 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211AC */
|
||||
|
||||
tail_len += hostapd_mbo_ie_len(hapd);
|
||||
|
||||
tailpos = tail = os_malloc(tail_len);
|
||||
if (head == NULL || tail == NULL) {
|
||||
wpa_printf(MSG_ERROR, "Failed to set beacon data");
|
||||
@ -987,6 +1088,12 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
/* Power Constraint element */
|
||||
tailpos = hostapd_eid_pwr_constraint(hapd, tailpos);
|
||||
|
||||
/* CSA IE */
|
||||
csa_pos = hostapd_eid_csa(hapd, tailpos);
|
||||
if (csa_pos != tailpos)
|
||||
hapd->cs_c_off_beacon = csa_pos - tail - 1;
|
||||
tailpos = csa_pos;
|
||||
|
||||
/* ERP Information element */
|
||||
tailpos = hostapd_eid_erp_info(hapd, tailpos);
|
||||
|
||||
@ -1004,7 +1111,19 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
tailpos = hostapd_eid_bss_load(hapd, tailpos,
|
||||
tail + BEACON_TAIL_BUF_SIZE - tailpos);
|
||||
|
||||
/* eCSA IE */
|
||||
csa_pos = hostapd_eid_ecsa(hapd, tailpos);
|
||||
if (csa_pos != tailpos)
|
||||
hapd->cs_c_off_ecsa_beacon = csa_pos - tail - 1;
|
||||
tailpos = csa_pos;
|
||||
|
||||
tailpos = hostapd_eid_supported_op_classes(hapd, tailpos);
|
||||
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
/* Secondary Channel Offset element */
|
||||
/* TODO: The standard doesn't specify a position for this element. */
|
||||
tailpos = hostapd_eid_secondary_channel(hapd, tailpos);
|
||||
|
||||
tailpos = hostapd_eid_ht_capabilities(hapd, tailpos);
|
||||
tailpos = hostapd_eid_ht_operation(hapd, tailpos);
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
@ -1020,8 +1139,6 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
tailpos = hostapd_eid_interworking(hapd, tailpos);
|
||||
tailpos = hostapd_eid_adv_proto(hapd, tailpos);
|
||||
tailpos = hostapd_eid_roaming_consortium(hapd, tailpos);
|
||||
tailpos = hostapd_add_csa_elems(hapd, tailpos, tail,
|
||||
&hapd->cs_c_off_beacon);
|
||||
|
||||
#ifdef CONFIG_FST
|
||||
if (hapd->iface->fst_ies) {
|
||||
@ -1033,8 +1150,10 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
|
||||
#ifdef CONFIG_IEEE80211AC
|
||||
if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
|
||||
tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
|
||||
tailpos = hostapd_eid_vht_capabilities(hapd, tailpos, 0);
|
||||
tailpos = hostapd_eid_vht_operation(hapd, tailpos);
|
||||
tailpos = hostapd_eid_txpower_envelope(hapd, tailpos);
|
||||
tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos);
|
||||
}
|
||||
if (hapd->conf->vendor_vht)
|
||||
tailpos = hostapd_eid_vendor_vht(hapd, tailpos);
|
||||
@ -1069,6 +1188,8 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
tailpos = hostapd_eid_osen(hapd, tailpos);
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
tailpos = hostapd_eid_mbo(hapd, tailpos, tail + tail_len - tailpos);
|
||||
|
||||
if (hapd->conf->vendor_elements) {
|
||||
os_memcpy(tailpos, wpabuf_head(hapd->conf->vendor_elements),
|
||||
wpabuf_len(hapd->conf->vendor_elements));
|
||||
@ -1153,6 +1274,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
|
||||
params->osen = 1;
|
||||
}
|
||||
#endif /* CONFIG_HS20 */
|
||||
params->pbss = hapd->conf->pbss;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -22,9 +22,12 @@ 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_del(struct hostapd_sta_info *info);
|
||||
void sta_track_expire(struct hostapd_iface *iface, int force);
|
||||
struct hostapd_data *
|
||||
sta_track_seen_on(struct hostapd_iface *iface, const u8 *addr,
|
||||
const char *ifname);
|
||||
void sta_track_claim_taxonomy_info(struct hostapd_iface *iface, const u8 *addr,
|
||||
struct wpabuf **probe_ie_taxonomy);
|
||||
|
||||
#endif /* BEACON_H */
|
||||
|
@ -22,6 +22,8 @@
|
||||
#include "p2p_hostapd.h"
|
||||
#include "ctrl_iface_ap.h"
|
||||
#include "ap_drv_ops.h"
|
||||
#include "mbo_ap.h"
|
||||
#include "taxonomy.h"
|
||||
|
||||
|
||||
static int hostapd_get_sta_tx_rx(struct hostapd_data *hapd,
|
||||
@ -35,9 +37,9 @@ static int hostapd_get_sta_tx_rx(struct hostapd_data *hapd,
|
||||
return 0;
|
||||
|
||||
ret = os_snprintf(buf, buflen, "rx_packets=%lu\ntx_packets=%lu\n"
|
||||
"rx_bytes=%lu\ntx_bytes=%lu\n",
|
||||
"rx_bytes=%llu\ntx_bytes=%llu\ninactive_msec=%lu\n",
|
||||
data.rx_packets, data.tx_packets,
|
||||
data.rx_bytes, data.tx_bytes);
|
||||
data.rx_bytes, data.tx_bytes, data.inactive_msec);
|
||||
if (os_snprintf_error(buflen, ret))
|
||||
return 0;
|
||||
return ret;
|
||||
@ -161,6 +163,19 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
|
||||
len += res;
|
||||
}
|
||||
|
||||
res = mbo_ap_get_info(sta, buf + len, buflen - len);
|
||||
if (res >= 0)
|
||||
len += res;
|
||||
|
||||
if (sta->supp_op_classes &&
|
||||
buflen - len > (unsigned) (17 + 2 * sta->supp_op_classes[0])) {
|
||||
len += os_snprintf(buf + len, buflen - len, "supp_op_classes=");
|
||||
len += wpa_snprintf_hex(buf + len, buflen - len,
|
||||
sta->supp_op_classes + 1,
|
||||
sta->supp_op_classes[0]);
|
||||
len += os_snprintf(buf + len, buflen - len, "\n");
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
@ -244,7 +259,7 @@ static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
|
||||
int ret;
|
||||
u8 *pos;
|
||||
|
||||
if (hapd->driver->send_frame == NULL)
|
||||
if (!hapd->drv_priv || !hapd->driver->send_frame)
|
||||
return -1;
|
||||
|
||||
mgmt = os_zalloc(sizeof(*mgmt) + 100);
|
||||
@ -255,7 +270,7 @@ static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
|
||||
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
|
||||
" with minor reason code %u (stype=%u (%s))",
|
||||
MAC2STR(addr), minor_reason_code, stype,
|
||||
fc2str(mgmt->frame_control));
|
||||
fc2str(le_to_host16(mgmt->frame_control)));
|
||||
|
||||
os_memcpy(mgmt->da, addr, ETH_ALEN);
|
||||
os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
|
||||
@ -311,7 +326,7 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
|
||||
if (pos) {
|
||||
struct ieee80211_mgmt mgmt;
|
||||
int encrypt;
|
||||
if (hapd->driver->send_frame == NULL)
|
||||
if (!hapd->drv_priv || !hapd->driver->send_frame)
|
||||
return -1;
|
||||
pos += 6;
|
||||
encrypt = atoi(pos);
|
||||
@ -338,7 +353,10 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
|
||||
}
|
||||
#endif /* CONFIG_P2P_MANAGER */
|
||||
|
||||
hostapd_drv_sta_deauth(hapd, addr, reason);
|
||||
if (os_strstr(txtaddr, " tx=0"))
|
||||
hostapd_drv_sta_remove(hapd, addr);
|
||||
else
|
||||
hostapd_drv_sta_deauth(hapd, addr, reason);
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (sta)
|
||||
ap_sta_deauthenticate(hapd, sta, reason);
|
||||
@ -371,7 +389,7 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
|
||||
if (pos) {
|
||||
struct ieee80211_mgmt mgmt;
|
||||
int encrypt;
|
||||
if (hapd->driver->send_frame == NULL)
|
||||
if (!hapd->drv_priv || !hapd->driver->send_frame)
|
||||
return -1;
|
||||
pos += 6;
|
||||
encrypt = atoi(pos);
|
||||
@ -398,7 +416,10 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
|
||||
}
|
||||
#endif /* CONFIG_P2P_MANAGER */
|
||||
|
||||
hostapd_drv_sta_disassoc(hapd, addr, reason);
|
||||
if (os_strstr(txtaddr, " tx=0"))
|
||||
hostapd_drv_sta_remove(hapd, addr);
|
||||
else
|
||||
hostapd_drv_sta_disassoc(hapd, addr, reason);
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (sta)
|
||||
ap_sta_disassociate(hapd, sta, reason);
|
||||
@ -409,6 +430,49 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_TAXONOMY
|
||||
int hostapd_ctrl_iface_signature(struct hostapd_data *hapd,
|
||||
const char *txtaddr,
|
||||
char *buf, size_t buflen)
|
||||
{
|
||||
u8 addr[ETH_ALEN];
|
||||
struct sta_info *sta;
|
||||
|
||||
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE SIGNATURE %s", txtaddr);
|
||||
|
||||
if (hwaddr_aton(txtaddr, addr))
|
||||
return -1;
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (!sta)
|
||||
return -1;
|
||||
|
||||
return retrieve_sta_taxonomy(hapd, sta, buf, buflen);
|
||||
}
|
||||
#endif /* CONFIG_TAXONOMY */
|
||||
|
||||
|
||||
int hostapd_ctrl_iface_poll_sta(struct hostapd_data *hapd,
|
||||
const char *txtaddr)
|
||||
{
|
||||
u8 addr[ETH_ALEN];
|
||||
struct sta_info *sta;
|
||||
|
||||
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE POLL_STA %s", txtaddr);
|
||||
|
||||
if (hwaddr_aton(txtaddr, addr))
|
||||
return -1;
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (!sta)
|
||||
return -1;
|
||||
|
||||
hostapd_drv_poll_client(hapd, hapd->own_addr, addr,
|
||||
sta->flags & WLAN_STA_WMM);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
|
||||
size_t buflen)
|
||||
{
|
||||
@ -473,20 +537,28 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
|
||||
"channel=%u\n"
|
||||
"secondary_channel=%d\n"
|
||||
"ieee80211n=%d\n"
|
||||
"ieee80211ac=%d\n"
|
||||
"vht_oper_chwidth=%d\n"
|
||||
"vht_oper_centr_freq_seg0_idx=%d\n"
|
||||
"vht_oper_centr_freq_seg1_idx=%d\n",
|
||||
"ieee80211ac=%d\n",
|
||||
iface->conf->channel,
|
||||
iface->conf->secondary_channel,
|
||||
iface->conf->ieee80211n,
|
||||
iface->conf->ieee80211ac,
|
||||
iface->conf->vht_oper_chwidth,
|
||||
iface->conf->vht_oper_centr_freq_seg0_idx,
|
||||
iface->conf->vht_oper_centr_freq_seg1_idx);
|
||||
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);
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac) {
|
||||
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",
|
||||
iface->conf->vht_oper_chwidth,
|
||||
iface->conf->vht_oper_centr_freq_seg0_idx,
|
||||
iface->conf->vht_oper_centr_freq_seg1_idx);
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < iface->num_bss; i++) {
|
||||
struct hostapd_data *bss = iface->bss[i];
|
||||
@ -554,3 +626,16 @@ int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd)
|
||||
{
|
||||
return hostapd_drv_stop_ap(hapd);
|
||||
}
|
||||
|
||||
|
||||
int hostapd_ctrl_iface_pmksa_list(struct hostapd_data *hapd, char *buf,
|
||||
size_t len)
|
||||
{
|
||||
return wpa_auth_pmksa_list(hapd->wpa_auth, buf, len);
|
||||
}
|
||||
|
||||
|
||||
void hostapd_ctrl_iface_pmksa_flush(struct hostapd_data *hapd)
|
||||
{
|
||||
wpa_auth_pmksa_flush(hapd->wpa_auth);
|
||||
}
|
||||
|
@ -19,10 +19,18 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
|
||||
const char *txtaddr);
|
||||
int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
|
||||
const char *txtaddr);
|
||||
int hostapd_ctrl_iface_signature(struct hostapd_data *hapd,
|
||||
const char *txtaddr,
|
||||
char *buf, size_t buflen);
|
||||
int hostapd_ctrl_iface_poll_sta(struct hostapd_data *hapd,
|
||||
const char *txtaddr);
|
||||
int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
|
||||
size_t buflen);
|
||||
int hostapd_parse_csa_settings(const char *pos,
|
||||
struct csa_settings *settings);
|
||||
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);
|
||||
|
||||
#endif /* CTRL_IFACE_AP_H */
|
||||
|
26
src/ap/dfs.c
26
src/ap/dfs.c
@ -450,7 +450,7 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
|
||||
return NULL;
|
||||
|
||||
if (os_get_random((u8 *) &_rand, sizeof(_rand)) < 0)
|
||||
_rand = os_random();
|
||||
return NULL;
|
||||
chan_idx = _rand % num_available_chandefs;
|
||||
dfs_find_channel(iface, &chan, chan_idx, skip_radar);
|
||||
|
||||
@ -704,7 +704,8 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
|
||||
skip_radar);
|
||||
if (!channel) {
|
||||
wpa_printf(MSG_ERROR, "could not get valid channel");
|
||||
return -1;
|
||||
hostapd_set_state(iface, HAPD_IFACE_DFS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
iface->freq = channel->freq;
|
||||
@ -793,7 +794,6 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
|
||||
|
||||
if (!channel) {
|
||||
wpa_printf(MSG_ERROR, "No valid channel available");
|
||||
hostapd_setup_interface_complete(iface, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -817,16 +817,6 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_csa_in_progress(struct hostapd_iface *iface)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < iface->num_bss; i++)
|
||||
if (iface->bss[i]->csa_in_progress)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
|
||||
{
|
||||
struct hostapd_channel_data *channel;
|
||||
@ -868,8 +858,9 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
|
||||
&vht_oper_centr_freq_seg1_idx,
|
||||
skip_radar);
|
||||
if (!channel) {
|
||||
/* FIXME: Wait for channel(s) to become available */
|
||||
hostapd_disable_iface(iface);
|
||||
wpa_printf(MSG_INFO,
|
||||
"%s: no DFS channels left, waiting for NOP to finish",
|
||||
__func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -992,6 +983,11 @@ int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq,
|
||||
/* TODO add correct implementation here */
|
||||
set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
|
||||
cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
|
||||
|
||||
/* Handle cases where all channels were initially unavailable */
|
||||
if (iface->state == HAPD_IFACE_DFS && !iface->cac_started)
|
||||
hostapd_handle_dfs(iface);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -121,7 +121,8 @@ static void handle_dhcp(void *ctx, const u8 *src_addr, const u8 *buf,
|
||||
|
||||
wpa_printf(MSG_DEBUG, "dhcp_snoop: Found DHCPACK for " MACSTR
|
||||
" @ IPv4 address %s/%d",
|
||||
MAC2STR(sta->addr), ipaddr_str(ntohl(b->your_ip)),
|
||||
MAC2STR(sta->addr),
|
||||
ipaddr_str(be_to_host32(b->your_ip)),
|
||||
prefixlen);
|
||||
|
||||
if (sta->ipaddr == b->your_ip)
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "wnm_ap.h"
|
||||
#include "hostapd.h"
|
||||
#include "ieee802_11.h"
|
||||
#include "ieee802_11_auth.h"
|
||||
#include "sta_info.h"
|
||||
#include "accounting.h"
|
||||
#include "tkip_countermeasures.h"
|
||||
@ -33,6 +34,7 @@
|
||||
#include "hw_features.h"
|
||||
#include "dfs.h"
|
||||
#include "beacon.h"
|
||||
#include "mbo_ap.h"
|
||||
|
||||
|
||||
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
@ -114,6 +116,21 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
}
|
||||
sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
|
||||
|
||||
/*
|
||||
* ACL configurations to the drivers (implementing AP SME and ACL
|
||||
* offload) without hostapd's knowledge, can result in a disconnection
|
||||
* though the driver accepts the connection. Skip the hostapd check for
|
||||
* ACL if the driver supports ACL offload to avoid potentially
|
||||
* conflicting ACL rules.
|
||||
*/
|
||||
if (hapd->iface->drv_max_acl_mac_addrs == 0 &&
|
||||
hostapd_check_acl(hapd, addr, NULL) != HOSTAPD_ACL_ACCEPT) {
|
||||
wpa_printf(MSG_INFO, "STA " MACSTR " not allowed to connect",
|
||||
MAC2STR(addr));
|
||||
reason = WLAN_REASON_UNSPECIFIED;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_P2P
|
||||
if (elems.p2p) {
|
||||
wpabuf_free(sta->p2p_ie);
|
||||
@ -164,6 +181,11 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
sta->mb_ies = NULL;
|
||||
#endif /* CONFIG_FST */
|
||||
|
||||
mbo_ap_check_sta_assoc(hapd, sta, &elems);
|
||||
|
||||
ap_copy_sta_supp_op_classes(sta, elems.supp_op_classes,
|
||||
elems.supp_op_classes_len);
|
||||
|
||||
if (hapd->conf->wpa) {
|
||||
if (ie == NULL || ielen == 0) {
|
||||
#ifdef CONFIG_WPS
|
||||
@ -338,6 +360,17 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
|
||||
return WLAN_STATUS_INVALID_IE;
|
||||
#endif /* CONFIG_HS20 */
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) &&
|
||||
elems.mbo && sta->cell_capa && !(sta->flags & WLAN_STA_MFP) &&
|
||||
hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"MBO: Reject WPA2 association without PMF");
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
}
|
||||
#endif /* CONFIG_MBO */
|
||||
|
||||
#ifdef CONFIG_WPS
|
||||
skip_wpa_check:
|
||||
#endif /* CONFIG_WPS */
|
||||
@ -447,7 +480,8 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
|
||||
int offset, int width, int cf1, int cf2)
|
||||
{
|
||||
#ifdef NEED_AP_MLME
|
||||
int channel, chwidth, seg0_idx = 0, seg1_idx = 0, is_dfs;
|
||||
int channel, chwidth, is_dfs;
|
||||
u8 seg0_idx = 0, seg1_idx = 0;
|
||||
|
||||
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_INFO,
|
||||
@ -491,8 +525,8 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
|
||||
seg1_idx = (cf2 - 5000) / 5;
|
||||
break;
|
||||
default:
|
||||
seg0_idx = hostapd_hw_get_channel(hapd, cf1);
|
||||
seg1_idx = hostapd_hw_get_channel(hapd, cf2);
|
||||
ieee80211_freq_to_chan(cf1, &seg0_idx);
|
||||
ieee80211_freq_to_chan(cf2, &seg1_idx);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -539,10 +573,11 @@ void hostapd_event_connect_failed_reason(struct hostapd_data *hapd,
|
||||
|
||||
|
||||
#ifdef CONFIG_ACS
|
||||
static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
|
||||
struct acs_selected_channels *acs_res)
|
||||
void hostapd_acs_channel_selected(struct hostapd_data *hapd,
|
||||
struct acs_selected_channels *acs_res)
|
||||
{
|
||||
int ret, i;
|
||||
int err = 0;
|
||||
|
||||
if (hapd->iconf->channel) {
|
||||
wpa_printf(MSG_INFO, "ACS: Channel was already set to %d",
|
||||
@ -564,7 +599,8 @@ static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
|
||||
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_WARNING,
|
||||
"driver selected to bad hw_mode");
|
||||
return;
|
||||
err = 1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
@ -574,7 +610,8 @@ static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
|
||||
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_WARNING,
|
||||
"driver switched to bad channel");
|
||||
return;
|
||||
err = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
hapd->iconf->channel = acs_res->pri_channel;
|
||||
@ -588,7 +625,8 @@ static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
|
||||
hapd->iconf->secondary_channel = 1;
|
||||
else {
|
||||
wpa_printf(MSG_ERROR, "Invalid secondary channel!");
|
||||
return;
|
||||
err = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (hapd->iface->conf->ieee80211ac) {
|
||||
@ -617,7 +655,8 @@ static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
|
||||
}
|
||||
}
|
||||
|
||||
ret = hostapd_acs_completed(hapd->iface, 0);
|
||||
out:
|
||||
ret = hostapd_acs_completed(hapd->iface, err);
|
||||
if (ret) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"ACS: Possibly channel configuration is invalid");
|
||||
@ -884,11 +923,24 @@ static void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf,
|
||||
size_t len, u16 stype, int ok)
|
||||
{
|
||||
struct ieee80211_hdr *hdr;
|
||||
struct hostapd_data *orig_hapd = hapd;
|
||||
|
||||
hdr = (struct ieee80211_hdr *) buf;
|
||||
hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
|
||||
if (hapd == NULL || hapd == HAPD_BROADCAST)
|
||||
if (!hapd)
|
||||
return;
|
||||
if (hapd == HAPD_BROADCAST) {
|
||||
if (stype != WLAN_FC_STYPE_ACTION || len <= 25 ||
|
||||
buf[24] != WLAN_ACTION_PUBLIC)
|
||||
return;
|
||||
hapd = get_hapd_bssid(orig_hapd->iface, hdr->addr2);
|
||||
if (!hapd || hapd == HAPD_BROADCAST)
|
||||
return;
|
||||
/*
|
||||
* Allow processing of TX status for a Public Action frame that
|
||||
* used wildcard BBSID.
|
||||
*/
|
||||
}
|
||||
ieee802_11_mgmt_cb(hapd, buf, len, stype, ok);
|
||||
}
|
||||
|
||||
@ -935,6 +987,8 @@ static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
|
||||
ieee802_1x_receive(hapd, src, data, data_len);
|
||||
}
|
||||
|
||||
#endif /* HOSTAPD */
|
||||
|
||||
|
||||
static struct hostapd_channel_data * hostapd_get_mode_channel(
|
||||
struct hostapd_iface *iface, unsigned int freq)
|
||||
@ -944,8 +998,6 @@ static struct hostapd_channel_data * hostapd_get_mode_channel(
|
||||
|
||||
for (i = 0; i < iface->current_mode->num_channels; i++) {
|
||||
chan = &iface->current_mode->channels[i];
|
||||
if (!chan)
|
||||
return NULL;
|
||||
if ((unsigned int) chan->freq == freq)
|
||||
return chan;
|
||||
}
|
||||
@ -1009,10 +1061,9 @@ static void hostapd_single_channel_get_survey(struct hostapd_iface *iface,
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_event_get_survey(struct hostapd_data *hapd,
|
||||
struct survey_results *survey_results)
|
||||
void hostapd_event_get_survey(struct hostapd_iface *iface,
|
||||
struct survey_results *survey_results)
|
||||
{
|
||||
struct hostapd_iface *iface = hapd->iface;
|
||||
struct freq_survey *survey, *tmp;
|
||||
struct hostapd_channel_data *chan;
|
||||
|
||||
@ -1044,6 +1095,7 @@ static void hostapd_event_get_survey(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
#ifdef HOSTAPD
|
||||
#ifdef NEED_AP_MLME
|
||||
|
||||
static void hostapd_event_iface_unavailable(struct hostapd_data *hapd)
|
||||
@ -1251,7 +1303,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||
data->connect_failed_reason.code);
|
||||
break;
|
||||
case EVENT_SURVEY:
|
||||
hostapd_event_get_survey(hapd, &data->survey_results);
|
||||
hostapd_event_get_survey(hapd->iface, &data->survey_results);
|
||||
break;
|
||||
#ifdef NEED_AP_MLME
|
||||
case EVENT_INTERFACE_UNAVAILABLE:
|
||||
@ -1321,4 +1373,31 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event,
|
||||
union wpa_event_data *data)
|
||||
{
|
||||
struct hapd_interfaces *interfaces = ctx;
|
||||
struct hostapd_data *hapd;
|
||||
|
||||
if (event != EVENT_INTERFACE_STATUS)
|
||||
return;
|
||||
|
||||
hapd = hostapd_get_iface(interfaces, data->interface_status.ifname);
|
||||
if (hapd && hapd->driver && hapd->driver->get_ifindex &&
|
||||
hapd->drv_priv) {
|
||||
unsigned int ifindex;
|
||||
|
||||
ifindex = hapd->driver->get_ifindex(hapd->drv_priv);
|
||||
if (ifindex != data->interface_status.ifindex) {
|
||||
wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
|
||||
"interface status ifindex %d mismatch (%d)",
|
||||
ifindex, data->interface_status.ifindex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (hapd)
|
||||
wpa_supplicant_event(hapd, event, data);
|
||||
}
|
||||
|
||||
#endif /* HOSTAPD */
|
||||
|
@ -101,6 +101,7 @@ gas_serv_dialog_find(struct hostapd_data *hapd, const u8 *addr,
|
||||
if (sta->gas_dialog[i].dialog_token != dialog_token ||
|
||||
!sta->gas_dialog[i].valid)
|
||||
continue;
|
||||
ap_sta_replenish_timeout(hapd, sta, 5);
|
||||
return &sta->gas_dialog[i];
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "ANQP: Could not find dialog for "
|
||||
@ -167,27 +168,107 @@ static void anqp_add_hs_capab_list(struct hostapd_data *hapd,
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
|
||||
static struct anqp_element * get_anqp_elem(struct hostapd_data *hapd,
|
||||
u16 infoid)
|
||||
{
|
||||
struct anqp_element *elem;
|
||||
|
||||
dl_list_for_each(elem, &hapd->conf->anqp_elem, struct anqp_element,
|
||||
list) {
|
||||
if (elem->infoid == infoid)
|
||||
return elem;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void anqp_add_elem(struct hostapd_data *hapd, struct wpabuf *buf,
|
||||
u16 infoid)
|
||||
{
|
||||
struct anqp_element *elem;
|
||||
|
||||
elem = get_anqp_elem(hapd, infoid);
|
||||
if (!elem)
|
||||
return;
|
||||
if (wpabuf_tailroom(buf) < 2 + 2 + wpabuf_len(elem->payload)) {
|
||||
wpa_printf(MSG_DEBUG, "ANQP: No room for InfoID %u payload",
|
||||
infoid);
|
||||
return;
|
||||
}
|
||||
|
||||
wpabuf_put_le16(buf, infoid);
|
||||
wpabuf_put_le16(buf, wpabuf_len(elem->payload));
|
||||
wpabuf_put_buf(buf, elem->payload);
|
||||
}
|
||||
|
||||
|
||||
static int anqp_add_override(struct hostapd_data *hapd, struct wpabuf *buf,
|
||||
u16 infoid)
|
||||
{
|
||||
if (get_anqp_elem(hapd, infoid)) {
|
||||
anqp_add_elem(hapd, buf, infoid);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void anqp_add_capab_list(struct hostapd_data *hapd,
|
||||
struct wpabuf *buf)
|
||||
{
|
||||
u8 *len;
|
||||
u16 id;
|
||||
|
||||
if (anqp_add_override(hapd, buf, ANQP_CAPABILITY_LIST))
|
||||
return;
|
||||
|
||||
len = gas_anqp_add_element(buf, ANQP_CAPABILITY_LIST);
|
||||
wpabuf_put_le16(buf, ANQP_CAPABILITY_LIST);
|
||||
if (hapd->conf->venue_name)
|
||||
if (hapd->conf->venue_name || get_anqp_elem(hapd, ANQP_VENUE_NAME))
|
||||
wpabuf_put_le16(buf, ANQP_VENUE_NAME);
|
||||
if (hapd->conf->network_auth_type)
|
||||
if (get_anqp_elem(hapd, ANQP_EMERGENCY_CALL_NUMBER))
|
||||
wpabuf_put_le16(buf, ANQP_EMERGENCY_CALL_NUMBER);
|
||||
if (hapd->conf->network_auth_type ||
|
||||
get_anqp_elem(hapd, ANQP_NETWORK_AUTH_TYPE))
|
||||
wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE);
|
||||
if (hapd->conf->roaming_consortium)
|
||||
if (hapd->conf->roaming_consortium ||
|
||||
get_anqp_elem(hapd, ANQP_ROAMING_CONSORTIUM))
|
||||
wpabuf_put_le16(buf, ANQP_ROAMING_CONSORTIUM);
|
||||
if (hapd->conf->ipaddr_type_configured)
|
||||
if (hapd->conf->ipaddr_type_configured ||
|
||||
get_anqp_elem(hapd, ANQP_IP_ADDR_TYPE_AVAILABILITY))
|
||||
wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY);
|
||||
if (hapd->conf->nai_realm_data)
|
||||
if (hapd->conf->nai_realm_data ||
|
||||
get_anqp_elem(hapd, ANQP_NAI_REALM))
|
||||
wpabuf_put_le16(buf, ANQP_NAI_REALM);
|
||||
if (hapd->conf->anqp_3gpp_cell_net)
|
||||
if (hapd->conf->anqp_3gpp_cell_net ||
|
||||
get_anqp_elem(hapd, ANQP_3GPP_CELLULAR_NETWORK))
|
||||
wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK);
|
||||
if (hapd->conf->domain_name)
|
||||
if (get_anqp_elem(hapd, ANQP_AP_GEOSPATIAL_LOCATION))
|
||||
wpabuf_put_le16(buf, ANQP_AP_GEOSPATIAL_LOCATION);
|
||||
if (get_anqp_elem(hapd, ANQP_AP_CIVIC_LOCATION))
|
||||
wpabuf_put_le16(buf, ANQP_AP_CIVIC_LOCATION);
|
||||
if (get_anqp_elem(hapd, ANQP_AP_LOCATION_PUBLIC_URI))
|
||||
wpabuf_put_le16(buf, ANQP_AP_LOCATION_PUBLIC_URI);
|
||||
if (hapd->conf->domain_name || get_anqp_elem(hapd, ANQP_DOMAIN_NAME))
|
||||
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_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))
|
||||
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);
|
||||
#ifdef CONFIG_HS20
|
||||
anqp_add_hs_capab_list(hapd, buf);
|
||||
#endif /* CONFIG_HS20 */
|
||||
@ -197,6 +278,9 @@ static void anqp_add_capab_list(struct hostapd_data *hapd,
|
||||
|
||||
static void anqp_add_venue_name(struct hostapd_data *hapd, struct wpabuf *buf)
|
||||
{
|
||||
if (anqp_add_override(hapd, buf, ANQP_VENUE_NAME))
|
||||
return;
|
||||
|
||||
if (hapd->conf->venue_name) {
|
||||
u8 *len;
|
||||
unsigned int i;
|
||||
@ -218,6 +302,9 @@ static void anqp_add_venue_name(struct hostapd_data *hapd, struct wpabuf *buf)
|
||||
static void anqp_add_network_auth_type(struct hostapd_data *hapd,
|
||||
struct wpabuf *buf)
|
||||
{
|
||||
if (anqp_add_override(hapd, buf, ANQP_NETWORK_AUTH_TYPE))
|
||||
return;
|
||||
|
||||
if (hapd->conf->network_auth_type) {
|
||||
wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE);
|
||||
wpabuf_put_le16(buf, hapd->conf->network_auth_type_len);
|
||||
@ -233,6 +320,9 @@ static void anqp_add_roaming_consortium(struct hostapd_data *hapd,
|
||||
unsigned int i;
|
||||
u8 *len;
|
||||
|
||||
if (anqp_add_override(hapd, buf, ANQP_ROAMING_CONSORTIUM))
|
||||
return;
|
||||
|
||||
len = gas_anqp_add_element(buf, ANQP_ROAMING_CONSORTIUM);
|
||||
for (i = 0; i < hapd->conf->roaming_consortium_count; i++) {
|
||||
struct hostapd_roaming_consortium *rc;
|
||||
@ -247,6 +337,9 @@ static void anqp_add_roaming_consortium(struct hostapd_data *hapd,
|
||||
static void anqp_add_ip_addr_type_availability(struct hostapd_data *hapd,
|
||||
struct wpabuf *buf)
|
||||
{
|
||||
if (anqp_add_override(hapd, buf, ANQP_IP_ADDR_TYPE_AVAILABILITY))
|
||||
return;
|
||||
|
||||
if (hapd->conf->ipaddr_type_configured) {
|
||||
wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY);
|
||||
wpabuf_put_le16(buf, 1);
|
||||
@ -309,7 +402,7 @@ static int hs20_add_nai_home_realm_matches(struct hostapd_data *hapd,
|
||||
|
||||
pos = home_realm;
|
||||
end = pos + home_realm_len;
|
||||
if (pos + 1 > end) {
|
||||
if (end - pos < 1) {
|
||||
wpa_hexdump(MSG_DEBUG, "Too short NAI Home Realm Query",
|
||||
home_realm, home_realm_len);
|
||||
return -1;
|
||||
@ -317,7 +410,7 @@ static int hs20_add_nai_home_realm_matches(struct hostapd_data *hapd,
|
||||
num_realms = *pos++;
|
||||
|
||||
for (i = 0; i < num_realms && num_matching < 10; i++) {
|
||||
if (pos + 2 > end) {
|
||||
if (end - pos < 2) {
|
||||
wpa_hexdump(MSG_DEBUG,
|
||||
"Truncated NAI Home Realm Query",
|
||||
home_realm, home_realm_len);
|
||||
@ -325,7 +418,7 @@ static int hs20_add_nai_home_realm_matches(struct hostapd_data *hapd,
|
||||
}
|
||||
encoding = *pos++;
|
||||
realm_len = *pos++;
|
||||
if (pos + realm_len > end) {
|
||||
if (realm_len > end - pos) {
|
||||
wpa_hexdump(MSG_DEBUG,
|
||||
"Truncated NAI Home Realm Query",
|
||||
home_realm, home_realm_len);
|
||||
@ -391,6 +484,10 @@ static void anqp_add_nai_realm(struct hostapd_data *hapd, struct wpabuf *buf,
|
||||
const u8 *home_realm, size_t home_realm_len,
|
||||
int nai_realm, int nai_home_realm)
|
||||
{
|
||||
if (nai_realm && !nai_home_realm &&
|
||||
anqp_add_override(hapd, buf, ANQP_NAI_REALM))
|
||||
return;
|
||||
|
||||
if (nai_realm && hapd->conf->nai_realm_data) {
|
||||
u8 *len;
|
||||
unsigned int i, j;
|
||||
@ -424,6 +521,9 @@ static void anqp_add_nai_realm(struct hostapd_data *hapd, struct wpabuf *buf,
|
||||
static void anqp_add_3gpp_cellular_network(struct hostapd_data *hapd,
|
||||
struct wpabuf *buf)
|
||||
{
|
||||
if (anqp_add_override(hapd, buf, ANQP_3GPP_CELLULAR_NETWORK))
|
||||
return;
|
||||
|
||||
if (hapd->conf->anqp_3gpp_cell_net) {
|
||||
wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK);
|
||||
wpabuf_put_le16(buf,
|
||||
@ -436,6 +536,9 @@ static void anqp_add_3gpp_cellular_network(struct hostapd_data *hapd,
|
||||
|
||||
static void anqp_add_domain_name(struct hostapd_data *hapd, struct wpabuf *buf)
|
||||
{
|
||||
if (anqp_add_override(hapd, buf, ANQP_DOMAIN_NAME))
|
||||
return;
|
||||
|
||||
if (hapd->conf->domain_name) {
|
||||
wpabuf_put_le16(buf, ANQP_DOMAIN_NAME);
|
||||
wpabuf_put_le16(buf, hapd->conf->domain_name_len);
|
||||
@ -683,20 +786,42 @@ static void anqp_add_icon_binary_file(struct hostapd_data *hapd,
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
|
||||
static size_t anqp_get_required_len(struct hostapd_data *hapd,
|
||||
const u16 *infoid,
|
||||
unsigned int num_infoid)
|
||||
{
|
||||
size_t len = 0;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < num_infoid; i++) {
|
||||
struct anqp_element *elem = get_anqp_elem(hapd, infoid[i]);
|
||||
|
||||
if (elem)
|
||||
len += 2 + 2 + wpabuf_len(elem->payload);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static struct wpabuf *
|
||||
gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
|
||||
unsigned int request,
|
||||
const u8 *home_realm, size_t home_realm_len,
|
||||
const u8 *icon_name, size_t icon_name_len)
|
||||
const u8 *icon_name, size_t icon_name_len,
|
||||
const u16 *extra_req,
|
||||
unsigned int num_extra_req)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
size_t len;
|
||||
unsigned int i;
|
||||
|
||||
len = 1400;
|
||||
if (request & (ANQP_REQ_NAI_REALM | ANQP_REQ_NAI_HOME_REALM))
|
||||
len += 1000;
|
||||
if (request & ANQP_REQ_ICON_REQUEST)
|
||||
len += 65536;
|
||||
len += anqp_get_required_len(hapd, extra_req, num_extra_req);
|
||||
|
||||
buf = wpabuf_alloc(len);
|
||||
if (buf == NULL)
|
||||
@ -706,6 +831,8 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
|
||||
anqp_add_capab_list(hapd, buf);
|
||||
if (request & ANQP_REQ_VENUE_NAME)
|
||||
anqp_add_venue_name(hapd, buf);
|
||||
if (request & ANQP_REQ_EMERGENCY_CALL_NUMBER)
|
||||
anqp_add_elem(hapd, buf, ANQP_EMERGENCY_CALL_NUMBER);
|
||||
if (request & ANQP_REQ_NETWORK_AUTH_TYPE)
|
||||
anqp_add_network_auth_type(hapd, buf);
|
||||
if (request & ANQP_REQ_ROAMING_CONSORTIUM)
|
||||
@ -718,8 +845,23 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
|
||||
request & ANQP_REQ_NAI_HOME_REALM);
|
||||
if (request & ANQP_REQ_3GPP_CELLULAR_NETWORK)
|
||||
anqp_add_3gpp_cellular_network(hapd, buf);
|
||||
if (request & ANQP_REQ_AP_GEOSPATIAL_LOCATION)
|
||||
anqp_add_elem(hapd, buf, ANQP_AP_GEOSPATIAL_LOCATION);
|
||||
if (request & ANQP_REQ_AP_CIVIC_LOCATION)
|
||||
anqp_add_elem(hapd, buf, ANQP_AP_CIVIC_LOCATION);
|
||||
if (request & ANQP_REQ_AP_LOCATION_PUBLIC_URI)
|
||||
anqp_add_elem(hapd, buf, ANQP_AP_LOCATION_PUBLIC_URI);
|
||||
if (request & ANQP_REQ_DOMAIN_NAME)
|
||||
anqp_add_domain_name(hapd, buf);
|
||||
if (request & ANQP_REQ_EMERGENCY_ALERT_URI)
|
||||
anqp_add_elem(hapd, buf, ANQP_EMERGENCY_ALERT_URI);
|
||||
if (request & ANQP_REQ_TDLS_CAPABILITY)
|
||||
anqp_add_elem(hapd, buf, ANQP_TDLS_CAPABILITY);
|
||||
if (request & ANQP_REQ_EMERGENCY_NAI)
|
||||
anqp_add_elem(hapd, buf, ANQP_EMERGENCY_NAI);
|
||||
|
||||
for (i = 0; i < num_extra_req; i++)
|
||||
anqp_add_elem(hapd, buf, extra_req[i]);
|
||||
|
||||
#ifdef CONFIG_HS20
|
||||
if (request & ANQP_REQ_HS_CAPABILITY_LIST)
|
||||
@ -742,6 +884,8 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
#define ANQP_MAX_EXTRA_REQ 20
|
||||
|
||||
struct anqp_query_info {
|
||||
unsigned int request;
|
||||
const u8 *home_realm_query;
|
||||
@ -749,6 +893,8 @@ struct anqp_query_info {
|
||||
const u8 *icon_name;
|
||||
size_t icon_name_len;
|
||||
int p2p_sd;
|
||||
u16 extra_req[ANQP_MAX_EXTRA_REQ];
|
||||
unsigned int num_extra_req;
|
||||
};
|
||||
|
||||
|
||||
@ -776,6 +922,11 @@ static void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id,
|
||||
set_anqp_req(ANQP_REQ_VENUE_NAME, "Venue Name",
|
||||
hapd->conf->venue_name != NULL, qi);
|
||||
break;
|
||||
case ANQP_EMERGENCY_CALL_NUMBER:
|
||||
set_anqp_req(ANQP_REQ_EMERGENCY_CALL_NUMBER,
|
||||
"Emergency Call Number",
|
||||
get_anqp_elem(hapd, info_id) != NULL, qi);
|
||||
break;
|
||||
case ANQP_NETWORK_AUTH_TYPE:
|
||||
set_anqp_req(ANQP_REQ_NETWORK_AUTH_TYPE, "Network Auth Type",
|
||||
hapd->conf->network_auth_type != NULL, qi);
|
||||
@ -798,13 +949,55 @@ static void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id,
|
||||
"3GPP Cellular Network",
|
||||
hapd->conf->anqp_3gpp_cell_net != NULL, qi);
|
||||
break;
|
||||
case ANQP_AP_GEOSPATIAL_LOCATION:
|
||||
set_anqp_req(ANQP_REQ_AP_GEOSPATIAL_LOCATION,
|
||||
"AP Geospatial Location",
|
||||
get_anqp_elem(hapd, info_id) != NULL, qi);
|
||||
break;
|
||||
case ANQP_AP_CIVIC_LOCATION:
|
||||
set_anqp_req(ANQP_REQ_AP_CIVIC_LOCATION,
|
||||
"AP Civic Location",
|
||||
get_anqp_elem(hapd, info_id) != NULL, qi);
|
||||
break;
|
||||
case ANQP_AP_LOCATION_PUBLIC_URI:
|
||||
set_anqp_req(ANQP_REQ_AP_LOCATION_PUBLIC_URI,
|
||||
"AP Location Public URI",
|
||||
get_anqp_elem(hapd, info_id) != NULL, qi);
|
||||
break;
|
||||
case ANQP_DOMAIN_NAME:
|
||||
set_anqp_req(ANQP_REQ_DOMAIN_NAME, "Domain Name",
|
||||
hapd->conf->domain_name != NULL, qi);
|
||||
break;
|
||||
case ANQP_EMERGENCY_ALERT_URI:
|
||||
set_anqp_req(ANQP_REQ_EMERGENCY_ALERT_URI,
|
||||
"Emergency Alert URI",
|
||||
get_anqp_elem(hapd, info_id) != NULL, qi);
|
||||
break;
|
||||
case ANQP_TDLS_CAPABILITY:
|
||||
set_anqp_req(ANQP_REQ_TDLS_CAPABILITY,
|
||||
"TDLS Capability",
|
||||
get_anqp_elem(hapd, info_id) != NULL, qi);
|
||||
break;
|
||||
case ANQP_EMERGENCY_NAI:
|
||||
set_anqp_req(ANQP_REQ_EMERGENCY_NAI,
|
||||
"Emergency NAI",
|
||||
get_anqp_elem(hapd, info_id) != NULL, qi);
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u",
|
||||
info_id);
|
||||
if (!get_anqp_elem(hapd, info_id)) {
|
||||
wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u",
|
||||
info_id);
|
||||
break;
|
||||
}
|
||||
if (qi->num_extra_req == ANQP_MAX_EXTRA_REQ) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"ANQP: No more room for extra requests - ignore Info Id %u",
|
||||
info_id);
|
||||
break;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "ANQP: Info Id %u (local)", info_id);
|
||||
qi->extra_req[qi->num_extra_req] = info_id;
|
||||
qi->num_extra_req++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -817,7 +1010,7 @@ static void rx_anqp_query_list(struct hostapd_data *hapd,
|
||||
wpa_printf(MSG_DEBUG, "ANQP: %u Info IDs requested in Query list",
|
||||
(unsigned int) (end - pos) / 2);
|
||||
|
||||
while (pos + 2 <= end) {
|
||||
while (end - pos >= 2) {
|
||||
rx_anqp_query_list_id(hapd, WPA_GET_LE16(pos), qi);
|
||||
pos += 2;
|
||||
}
|
||||
@ -906,7 +1099,7 @@ static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
|
||||
u32 oui;
|
||||
u8 subtype;
|
||||
|
||||
if (pos + 4 > end) {
|
||||
if (end - pos < 4) {
|
||||
wpa_printf(MSG_DEBUG, "ANQP: Too short vendor specific ANQP "
|
||||
"Query element");
|
||||
return;
|
||||
@ -942,7 +1135,7 @@ static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
|
||||
}
|
||||
pos++;
|
||||
|
||||
if (pos + 1 >= end)
|
||||
if (end - pos <= 1)
|
||||
return;
|
||||
|
||||
subtype = *pos++;
|
||||
@ -973,14 +1166,16 @@ static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
|
||||
|
||||
static void gas_serv_req_local_processing(struct hostapd_data *hapd,
|
||||
const u8 *sa, u8 dialog_token,
|
||||
struct anqp_query_info *qi, int prot)
|
||||
struct anqp_query_info *qi, int prot,
|
||||
int std_addr3)
|
||||
{
|
||||
struct wpabuf *buf, *tx_buf;
|
||||
|
||||
buf = gas_serv_build_gas_resp_payload(hapd, qi->request,
|
||||
qi->home_realm_query,
|
||||
qi->home_realm_query_len,
|
||||
qi->icon_name, qi->icon_name_len);
|
||||
qi->icon_name, qi->icon_name_len,
|
||||
qi->extra_req, qi->num_extra_req);
|
||||
wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Locally generated ANQP responses",
|
||||
buf);
|
||||
if (!buf)
|
||||
@ -1033,15 +1228,22 @@ static void gas_serv_req_local_processing(struct hostapd_data *hapd,
|
||||
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));
|
||||
if (std_addr3)
|
||||
hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
|
||||
wpabuf_head(tx_buf),
|
||||
wpabuf_len(tx_buf));
|
||||
else
|
||||
hostapd_drv_send_action_addr3_ap(hapd, hapd->iface->freq, 0, sa,
|
||||
wpabuf_head(tx_buf),
|
||||
wpabuf_len(tx_buf));
|
||||
wpabuf_free(tx_buf);
|
||||
}
|
||||
|
||||
|
||||
static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
|
||||
const u8 *sa,
|
||||
const u8 *data, size_t len, int prot)
|
||||
const u8 *data, size_t len, int prot,
|
||||
int std_addr3)
|
||||
{
|
||||
const u8 *pos = data;
|
||||
const u8 *end = data + len;
|
||||
@ -1069,12 +1271,12 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
|
||||
adv_proto = pos++;
|
||||
|
||||
slen = *pos++;
|
||||
next = pos + slen;
|
||||
if (next > end || slen < 2) {
|
||||
if (slen > end - pos || slen < 2) {
|
||||
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
|
||||
"GAS: Invalid IE in GAS Initial Request");
|
||||
return;
|
||||
}
|
||||
next = pos + slen;
|
||||
pos++; /* skip QueryRespLenLimit and PAME-BI */
|
||||
|
||||
if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
|
||||
@ -1093,19 +1295,26 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
|
||||
wpabuf_put_le16(buf, 0); /* Query Response Length */
|
||||
if (prot)
|
||||
convert_to_protected_dual(buf);
|
||||
hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
|
||||
wpabuf_head(buf), wpabuf_len(buf));
|
||||
if (std_addr3)
|
||||
hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
|
||||
wpabuf_head(buf),
|
||||
wpabuf_len(buf));
|
||||
else
|
||||
hostapd_drv_send_action_addr3_ap(hapd,
|
||||
hapd->iface->freq, 0,
|
||||
sa, wpabuf_head(buf),
|
||||
wpabuf_len(buf));
|
||||
wpabuf_free(buf);
|
||||
return;
|
||||
}
|
||||
|
||||
pos = next;
|
||||
/* Query Request */
|
||||
if (pos + 2 > end)
|
||||
if (end - pos < 2)
|
||||
return;
|
||||
slen = WPA_GET_LE16(pos);
|
||||
pos += 2;
|
||||
if (pos + slen > end)
|
||||
if (slen > end - pos)
|
||||
return;
|
||||
end = pos + slen;
|
||||
|
||||
@ -1113,7 +1322,7 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
|
||||
while (pos < end) {
|
||||
u16 info_id, elen;
|
||||
|
||||
if (pos + 4 > end)
|
||||
if (end - pos < 4)
|
||||
return;
|
||||
|
||||
info_id = WPA_GET_LE16(pos);
|
||||
@ -1121,7 +1330,7 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
|
||||
elen = WPA_GET_LE16(pos);
|
||||
pos += 2;
|
||||
|
||||
if (pos + elen > end) {
|
||||
if (elen > end - pos) {
|
||||
wpa_printf(MSG_DEBUG, "ANQP: Invalid Query Request");
|
||||
return;
|
||||
}
|
||||
@ -1144,13 +1353,15 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
|
||||
pos += elen;
|
||||
}
|
||||
|
||||
gas_serv_req_local_processing(hapd, sa, dialog_token, &qi, prot);
|
||||
gas_serv_req_local_processing(hapd, sa, dialog_token, &qi, prot,
|
||||
std_addr3);
|
||||
}
|
||||
|
||||
|
||||
static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
|
||||
const u8 *sa,
|
||||
const u8 *data, size_t len, int prot)
|
||||
const u8 *data, size_t len, int prot,
|
||||
int std_addr3)
|
||||
{
|
||||
struct gas_dialog_info *dialog;
|
||||
struct wpabuf *buf, *tx_buf;
|
||||
@ -1226,8 +1437,14 @@ static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
|
||||
send_resp:
|
||||
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));
|
||||
if (std_addr3)
|
||||
hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
|
||||
wpabuf_head(tx_buf),
|
||||
wpabuf_len(tx_buf));
|
||||
else
|
||||
hostapd_drv_send_action_addr3_ap(hapd, hapd->iface->freq, 0, sa,
|
||||
wpabuf_head(tx_buf),
|
||||
wpabuf_len(tx_buf));
|
||||
wpabuf_free(tx_buf);
|
||||
}
|
||||
|
||||
@ -1238,7 +1455,7 @@ static void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len,
|
||||
struct hostapd_data *hapd = ctx;
|
||||
const struct ieee80211_mgmt *mgmt;
|
||||
const u8 *sa, *data;
|
||||
int prot;
|
||||
int prot, std_addr3;
|
||||
|
||||
mgmt = (const struct ieee80211_mgmt *) buf;
|
||||
if (len < IEEE80211_HDRLEN + 2)
|
||||
@ -1253,14 +1470,22 @@ static void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len,
|
||||
*/
|
||||
prot = mgmt->u.action.category == WLAN_ACTION_PROTECTED_DUAL;
|
||||
sa = mgmt->sa;
|
||||
if (hapd->conf->gas_address3 == 1)
|
||||
std_addr3 = 1;
|
||||
else if (hapd->conf->gas_address3 == 2)
|
||||
std_addr3 = 0;
|
||||
else
|
||||
std_addr3 = is_broadcast_ether_addr(mgmt->bssid);
|
||||
len -= IEEE80211_HDRLEN + 1;
|
||||
data = buf + IEEE80211_HDRLEN + 1;
|
||||
switch (data[0]) {
|
||||
case WLAN_PA_GAS_INITIAL_REQ:
|
||||
gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1, prot);
|
||||
gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1, prot,
|
||||
std_addr3);
|
||||
break;
|
||||
case WLAN_PA_GAS_COMEBACK_REQ:
|
||||
gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1, prot);
|
||||
gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1, prot,
|
||||
std_addr3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -9,10 +9,13 @@
|
||||
#ifndef GAS_SERV_H
|
||||
#define GAS_SERV_H
|
||||
|
||||
/* First 16 ANQP InfoIDs can be included in the optimized bitmap */
|
||||
#define ANQP_REQ_CAPABILITY_LIST \
|
||||
(1 << (ANQP_CAPABILITY_LIST - ANQP_QUERY_LIST))
|
||||
#define ANQP_REQ_VENUE_NAME \
|
||||
(1 << (ANQP_VENUE_NAME - ANQP_QUERY_LIST))
|
||||
#define ANQP_REQ_EMERGENCY_CALL_NUMBER \
|
||||
(1 << (ANQP_EMERGENCY_CALL_NUMBER - ANQP_QUERY_LIST))
|
||||
#define ANQP_REQ_NETWORK_AUTH_TYPE \
|
||||
(1 << (ANQP_NETWORK_AUTH_TYPE - ANQP_QUERY_LIST))
|
||||
#define ANQP_REQ_ROAMING_CONSORTIUM \
|
||||
@ -23,8 +26,24 @@
|
||||
(1 << (ANQP_NAI_REALM - ANQP_QUERY_LIST))
|
||||
#define ANQP_REQ_3GPP_CELLULAR_NETWORK \
|
||||
(1 << (ANQP_3GPP_CELLULAR_NETWORK - ANQP_QUERY_LIST))
|
||||
#define ANQP_REQ_AP_GEOSPATIAL_LOCATION \
|
||||
(1 << (ANQP_AP_GEOSPATIAL_LOCATION - ANQP_QUERY_LIST))
|
||||
#define ANQP_REQ_AP_CIVIC_LOCATION \
|
||||
(1 << (ANQP_AP_CIVIC_LOCATION - ANQP_QUERY_LIST))
|
||||
#define ANQP_REQ_AP_LOCATION_PUBLIC_URI \
|
||||
(1 << (ANQP_AP_LOCATION_PUBLIC_URI - ANQP_QUERY_LIST))
|
||||
#define ANQP_REQ_DOMAIN_NAME \
|
||||
(1 << (ANQP_DOMAIN_NAME - ANQP_QUERY_LIST))
|
||||
#define ANQP_REQ_EMERGENCY_ALERT_URI \
|
||||
(1 << (ANQP_EMERGENCY_ALERT_URI - ANQP_QUERY_LIST))
|
||||
#define ANQP_REQ_TDLS_CAPABILITY \
|
||||
(1 << (ANQP_TDLS_CAPABILITY - ANQP_QUERY_LIST))
|
||||
#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
|
||||
* optimized bitmap.
|
||||
*/
|
||||
#define ANQP_REQ_HS_CAPABILITY_LIST \
|
||||
(0x10000 << HS20_STYPE_CAPABILITY_LIST)
|
||||
#define ANQP_REQ_OPERATOR_FRIENDLY_NAME \
|
||||
|
424
src/ap/hostapd.c
424
src/ap/hostapd.c
@ -12,6 +12,7 @@
|
||||
#include "utils/eloop.h"
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/wpa_ctrl.h"
|
||||
#include "common/hw_features_common.h"
|
||||
#include "radius/radius_client.h"
|
||||
#include "radius/radius_das.h"
|
||||
#include "eap_server/tncs.h"
|
||||
@ -42,6 +43,8 @@
|
||||
#include "x_snoop.h"
|
||||
#include "dhcp_snoop.h"
|
||||
#include "ndisc_snoop.h"
|
||||
#include "neighbor_db.h"
|
||||
#include "rrm.h"
|
||||
|
||||
|
||||
static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
|
||||
@ -203,10 +206,12 @@ int hostapd_reload_config(struct hostapd_iface *iface)
|
||||
|
||||
|
||||
static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
|
||||
char *ifname)
|
||||
const char *ifname)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!ifname)
|
||||
return;
|
||||
for (i = 0; i < NUM_WEP_KEYS; i++) {
|
||||
if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i,
|
||||
0, NULL, 0, NULL, 0)) {
|
||||
@ -334,6 +339,8 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
|
||||
wpabuf_free(hapd->mesh_pending_auth);
|
||||
hapd->mesh_pending_auth = NULL;
|
||||
#endif /* CONFIG_MESH */
|
||||
|
||||
hostapd_clean_rrm(hapd);
|
||||
}
|
||||
|
||||
|
||||
@ -367,7 +374,7 @@ static void sta_track_deinit(struct hostapd_iface *iface)
|
||||
list))) {
|
||||
dl_list_del(&info->list);
|
||||
iface->num_sta_seen--;
|
||||
os_free(info);
|
||||
sta_track_del(info);
|
||||
}
|
||||
}
|
||||
|
||||
@ -511,6 +518,9 @@ static int hostapd_validate_bssid_configuration(struct hostapd_iface *iface)
|
||||
if (hostapd_drv_none(hapd))
|
||||
return 0;
|
||||
|
||||
if (iface->conf->use_driver_iface_addr)
|
||||
return 0;
|
||||
|
||||
/* Generate BSSID mask that is large enough to cover the BSSIDs. */
|
||||
|
||||
/* Determine the bits necessary to cover the number of BSSIDs. */
|
||||
@ -520,7 +530,7 @@ static int hostapd_validate_bssid_configuration(struct hostapd_iface *iface)
|
||||
/* Determine the bits necessary to any configured BSSIDs,
|
||||
if they are higher than the number of BSSIDs. */
|
||||
for (j = 0; j < iface->conf->num_bss; j++) {
|
||||
if (hostapd_mac_comp_empty(iface->conf->bss[j]->bssid) == 0) {
|
||||
if (is_zero_ether_addr(iface->conf->bss[j]->bssid)) {
|
||||
if (j)
|
||||
auto_addr++;
|
||||
continue;
|
||||
@ -672,7 +682,7 @@ static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,
|
||||
|
||||
if (attr->acct_session_id) {
|
||||
num_attr++;
|
||||
if (attr->acct_session_id_len != 17) {
|
||||
if (attr->acct_session_id_len != 16) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"RADIUS DAS: Acct-Session-Id cannot match");
|
||||
return NULL;
|
||||
@ -682,10 +692,9 @@ static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,
|
||||
for (sta = hapd->sta_list; sta; sta = sta->next) {
|
||||
if (!sta->radius_das_match)
|
||||
continue;
|
||||
os_snprintf(buf, sizeof(buf), "%08X-%08X",
|
||||
sta->acct_session_id_hi,
|
||||
sta->acct_session_id_lo);
|
||||
if (os_memcmp(attr->acct_session_id, buf, 17) != 0)
|
||||
os_snprintf(buf, sizeof(buf), "%016llX",
|
||||
(unsigned long long) sta->acct_session_id);
|
||||
if (os_memcmp(attr->acct_session_id, buf, 16) != 0)
|
||||
sta->radius_das_match = 0;
|
||||
else
|
||||
count++;
|
||||
@ -701,7 +710,7 @@ static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,
|
||||
|
||||
if (attr->acct_multi_session_id) {
|
||||
num_attr++;
|
||||
if (attr->acct_multi_session_id_len != 17) {
|
||||
if (attr->acct_multi_session_id_len != 16) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"RADIUS DAS: Acct-Multi-Session-Id cannot match");
|
||||
return NULL;
|
||||
@ -712,14 +721,14 @@ static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,
|
||||
if (!sta->radius_das_match)
|
||||
continue;
|
||||
if (!sta->eapol_sm ||
|
||||
!sta->eapol_sm->acct_multi_session_id_hi) {
|
||||
!sta->eapol_sm->acct_multi_session_id) {
|
||||
sta->radius_das_match = 0;
|
||||
continue;
|
||||
}
|
||||
os_snprintf(buf, sizeof(buf), "%08X+%08X",
|
||||
sta->eapol_sm->acct_multi_session_id_hi,
|
||||
sta->eapol_sm->acct_multi_session_id_lo);
|
||||
if (os_memcmp(attr->acct_multi_session_id, buf, 17) !=
|
||||
os_snprintf(buf, sizeof(buf), "%016llX",
|
||||
(unsigned long long)
|
||||
sta->eapol_sm->acct_multi_session_id);
|
||||
if (os_memcmp(attr->acct_multi_session_id, buf, 16) !=
|
||||
0)
|
||||
sta->radius_das_match = 0;
|
||||
else
|
||||
@ -905,12 +914,9 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
|
||||
hapd->started = 1;
|
||||
|
||||
if (!first || first == -1) {
|
||||
if (hostapd_mac_comp_empty(conf->bssid) == 0) {
|
||||
/* Allocate the next available BSSID. */
|
||||
do {
|
||||
inc_byte_array(hapd->own_addr, ETH_ALEN);
|
||||
} while (mac_in_conf(hapd->iconf, hapd->own_addr));
|
||||
} else {
|
||||
u8 *addr = hapd->own_addr;
|
||||
|
||||
if (!is_zero_ether_addr(conf->bssid)) {
|
||||
/* Allocate the configured BSSID. */
|
||||
os_memcpy(hapd->own_addr, conf->bssid, ETH_ALEN);
|
||||
|
||||
@ -922,11 +928,18 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
|
||||
"the radio", conf->iface);
|
||||
return -1;
|
||||
}
|
||||
} else if (hapd->iconf->use_driver_iface_addr) {
|
||||
addr = NULL;
|
||||
} else {
|
||||
/* Allocate the next available BSSID. */
|
||||
do {
|
||||
inc_byte_array(hapd->own_addr, ETH_ALEN);
|
||||
} while (mac_in_conf(hapd->iconf, hapd->own_addr));
|
||||
}
|
||||
|
||||
hapd->interface_added = 1;
|
||||
if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS,
|
||||
conf->iface, hapd->own_addr, hapd,
|
||||
conf->iface, addr, hapd,
|
||||
&hapd->drv_priv, force_ifname, if_addr,
|
||||
conf->bridge[0] ? conf->bridge : NULL,
|
||||
first == -1)) {
|
||||
@ -935,11 +948,19 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
|
||||
hapd->interface_added = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!addr)
|
||||
os_memcpy(hapd->own_addr, if_addr, ETH_ALEN);
|
||||
}
|
||||
|
||||
if (conf->wmm_enabled < 0)
|
||||
conf->wmm_enabled = hapd->iconf->ieee80211n;
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
if (is_zero_ether_addr(conf->r1_key_holder))
|
||||
os_memcpy(conf->r1_key_holder, hapd->own_addr, ETH_ALEN);
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
|
||||
#ifdef CONFIG_MESH
|
||||
if (hapd->iface->mconf == NULL)
|
||||
flush_old_stations = 0;
|
||||
@ -1022,6 +1043,8 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
|
||||
das_conf.time_window = conf->radius_das_time_window;
|
||||
das_conf.require_event_timestamp =
|
||||
conf->radius_das_require_event_timestamp;
|
||||
das_conf.require_message_authenticator =
|
||||
conf->radius_das_require_message_authenticator;
|
||||
das_conf.ctx = hapd;
|
||||
das_conf.disconnect = hostapd_das_disconnect;
|
||||
hapd->radius_das = radius_das_init(&das_conf);
|
||||
@ -1509,15 +1532,128 @@ void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd,
|
||||
#endif /* CONFIG_FST */
|
||||
|
||||
|
||||
/**
|
||||
* hostapd_setup_interface_complete - Complete interface setup
|
||||
*
|
||||
* This function is called when previous steps in the interface setup has been
|
||||
* completed. This can also start operations, e.g., DFS, that will require
|
||||
* additional processing before interface is ready to be enabled. Such
|
||||
* operations will call this function from eloop callbacks when finished.
|
||||
*/
|
||||
int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
|
||||
#ifdef NEED_AP_MLME
|
||||
static enum nr_chan_width hostapd_get_nr_chan_width(struct hostapd_data *hapd,
|
||||
int ht, int vht)
|
||||
{
|
||||
if (!ht && !vht)
|
||||
return NR_CHAN_WIDTH_20;
|
||||
if (!hapd->iconf->secondary_channel)
|
||||
return NR_CHAN_WIDTH_20;
|
||||
if (!vht || hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_USE_HT)
|
||||
return NR_CHAN_WIDTH_40;
|
||||
if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80MHZ)
|
||||
return NR_CHAN_WIDTH_80;
|
||||
if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_160MHZ)
|
||||
return NR_CHAN_WIDTH_160;
|
||||
if (hapd->iconf->vht_oper_chwidth == VHT_CHANWIDTH_80P80MHZ)
|
||||
return NR_CHAN_WIDTH_80P80;
|
||||
return NR_CHAN_WIDTH_20;
|
||||
}
|
||||
#endif /* NEED_AP_MLME */
|
||||
|
||||
|
||||
static void hostapd_set_own_neighbor_report(struct hostapd_data *hapd)
|
||||
{
|
||||
#ifdef NEED_AP_MLME
|
||||
u16 capab = hostapd_own_capab_info(hapd);
|
||||
int ht = hapd->iconf->ieee80211n && !hapd->conf->disable_11n;
|
||||
int vht = hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac;
|
||||
struct wpa_ssid_value ssid;
|
||||
u8 channel, op_class;
|
||||
int center_freq1 = 0, center_freq2 = 0;
|
||||
enum nr_chan_width width;
|
||||
u32 bssid_info;
|
||||
struct wpabuf *nr;
|
||||
|
||||
if (!(hapd->conf->radio_measurements[0] &
|
||||
WLAN_RRM_CAPS_NEIGHBOR_REPORT))
|
||||
return;
|
||||
|
||||
bssid_info = 3; /* AP is reachable */
|
||||
bssid_info |= NEI_REP_BSSID_INFO_SECURITY; /* "same as the AP" */
|
||||
bssid_info |= NEI_REP_BSSID_INFO_KEY_SCOPE; /* "same as the AP" */
|
||||
|
||||
if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT)
|
||||
bssid_info |= NEI_REP_BSSID_INFO_SPECTRUM_MGMT;
|
||||
|
||||
bssid_info |= NEI_REP_BSSID_INFO_RM; /* RRM is supported */
|
||||
|
||||
if (hapd->conf->wmm_enabled) {
|
||||
bssid_info |= NEI_REP_BSSID_INFO_QOS;
|
||||
|
||||
if (hapd->conf->wmm_uapsd &&
|
||||
(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_UAPSD))
|
||||
bssid_info |= NEI_REP_BSSID_INFO_APSD;
|
||||
}
|
||||
|
||||
if (ht) {
|
||||
bssid_info |= NEI_REP_BSSID_INFO_HT |
|
||||
NEI_REP_BSSID_INFO_DELAYED_BA;
|
||||
|
||||
/* VHT bit added in IEEE P802.11-REVmc/D4.3 */
|
||||
if (vht)
|
||||
bssid_info |= NEI_REP_BSSID_INFO_VHT;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
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);
|
||||
if (width == NR_CHAN_WIDTH_80P80)
|
||||
center_freq2 = ieee80211_chan_to_freq(
|
||||
NULL, op_class,
|
||||
hapd->iconf->vht_oper_centr_freq_seg1_idx);
|
||||
} else if (ht) {
|
||||
center_freq1 = hapd->iface->freq +
|
||||
10 * hapd->iconf->secondary_channel;
|
||||
}
|
||||
|
||||
ssid.ssid_len = hapd->conf->ssid.ssid_len;
|
||||
os_memcpy(ssid.ssid, hapd->conf->ssid.ssid, ssid.ssid_len);
|
||||
|
||||
/*
|
||||
* Neighbor Report element size = BSSID + BSSID info + op_class + chan +
|
||||
* phy type + wide bandwidth channel subelement.
|
||||
*/
|
||||
nr = wpabuf_alloc(ETH_ALEN + 4 + 1 + 1 + 1 + 5);
|
||||
if (!nr)
|
||||
return;
|
||||
|
||||
wpabuf_put_data(nr, hapd->own_addr, ETH_ALEN);
|
||||
wpabuf_put_le32(nr, bssid_info);
|
||||
wpabuf_put_u8(nr, op_class);
|
||||
wpabuf_put_u8(nr, channel);
|
||||
wpabuf_put_u8(nr, ieee80211_get_phy_type(hapd->iface->freq, ht, vht));
|
||||
|
||||
/*
|
||||
* Wide Bandwidth Channel subelement may be needed to allow the
|
||||
* receiving STA to send packets to the AP. See IEEE P802.11-REVmc/D5.0
|
||||
* Figure 9-301.
|
||||
*/
|
||||
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);
|
||||
|
||||
hostapd_neighbor_set(hapd, hapd->own_addr, &ssid, nr, hapd->iconf->lci,
|
||||
hapd->iconf->civic);
|
||||
|
||||
wpabuf_free(nr);
|
||||
#endif /* NEED_AP_MLME */
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
|
||||
int err)
|
||||
{
|
||||
struct hostapd_data *hapd = iface->bss[0];
|
||||
size_t j;
|
||||
@ -1633,7 +1769,7 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
|
||||
} while (j-- > 0);
|
||||
goto fail;
|
||||
}
|
||||
if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0)
|
||||
if (is_zero_ether_addr(hapd->conf->bssid))
|
||||
prev_addr = hapd->own_addr;
|
||||
}
|
||||
hapd = iface->bss[0];
|
||||
@ -1641,7 +1777,6 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
|
||||
hostapd_tx_queue_params(iface);
|
||||
|
||||
ap_list_init(iface);
|
||||
dl_list_init(&iface->sta_seen);
|
||||
|
||||
hostapd_set_acl(hapd);
|
||||
|
||||
@ -1701,6 +1836,9 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
|
||||
if (iface->interfaces && iface->interfaces->terminate_on_error > 0)
|
||||
iface->interfaces->terminate_on_error--;
|
||||
|
||||
for (j = 0; j < iface->num_bss; j++)
|
||||
hostapd_set_own_neighbor_report(iface->bss[j]);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
@ -1719,6 +1857,89 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hostapd_setup_interface_complete - Complete interface setup
|
||||
*
|
||||
* This function is called when previous steps in the interface setup has been
|
||||
* completed. This can also start operations, e.g., DFS, that will require
|
||||
* additional processing before interface is ready to be enabled. Such
|
||||
* operations will call this function from eloop callbacks when finished.
|
||||
*/
|
||||
int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
|
||||
{
|
||||
struct hapd_interfaces *interfaces = iface->interfaces;
|
||||
struct hostapd_data *hapd = iface->bss[0];
|
||||
unsigned int i;
|
||||
int not_ready_in_sync_ifaces = 0;
|
||||
|
||||
if (!iface->need_to_start_in_sync)
|
||||
return hostapd_setup_interface_complete_sync(iface, err);
|
||||
|
||||
if (err) {
|
||||
wpa_printf(MSG_ERROR, "Interface initialization failed");
|
||||
hostapd_set_state(iface, HAPD_IFACE_DISABLED);
|
||||
iface->need_to_start_in_sync = 0;
|
||||
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
|
||||
if (interfaces && interfaces->terminate_on_error)
|
||||
eloop_terminate();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (iface->ready_to_start_in_sync) {
|
||||
/* Already in ready and waiting. should never happpen */
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < interfaces->count; i++) {
|
||||
if (interfaces->iface[i]->need_to_start_in_sync &&
|
||||
!interfaces->iface[i]->ready_to_start_in_sync)
|
||||
not_ready_in_sync_ifaces++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if this is the last interface, if yes then start all the other
|
||||
* waiting interfaces. If not, add this interface to the waiting list.
|
||||
*/
|
||||
if (not_ready_in_sync_ifaces > 1 && iface->state == HAPD_IFACE_DFS) {
|
||||
/*
|
||||
* If this interface went through CAC, do not synchronize, just
|
||||
* start immediately.
|
||||
*/
|
||||
iface->need_to_start_in_sync = 0;
|
||||
wpa_printf(MSG_INFO,
|
||||
"%s: Finished CAC - bypass sync and start interface",
|
||||
iface->bss[0]->conf->iface);
|
||||
return hostapd_setup_interface_complete_sync(iface, err);
|
||||
}
|
||||
|
||||
if (not_ready_in_sync_ifaces > 1) {
|
||||
/* need to wait as there are other interfaces still coming up */
|
||||
iface->ready_to_start_in_sync = 1;
|
||||
wpa_printf(MSG_INFO,
|
||||
"%s: Interface waiting to sync with other interfaces",
|
||||
iface->bss[0]->conf->iface);
|
||||
return 0;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_INFO,
|
||||
"%s: Last interface to sync - starting all interfaces",
|
||||
iface->bss[0]->conf->iface);
|
||||
iface->need_to_start_in_sync = 0;
|
||||
hostapd_setup_interface_complete_sync(iface, err);
|
||||
for (i = 0; i < interfaces->count; i++) {
|
||||
if (interfaces->iface[i]->need_to_start_in_sync &&
|
||||
interfaces->iface[i]->ready_to_start_in_sync) {
|
||||
hostapd_setup_interface_complete_sync(
|
||||
interfaces->iface[i], 0);
|
||||
/* Only once the interfaces are sync started */
|
||||
interfaces->iface[i]->need_to_start_in_sync = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hostapd_setup_interface - Setup of an interface
|
||||
* @iface: Pointer to interface data.
|
||||
@ -1778,6 +1999,8 @@ hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
|
||||
hapd->iface = hapd_iface;
|
||||
hapd->driver = hapd->iconf->driver;
|
||||
hapd->ctrl_sock = -1;
|
||||
dl_list_init(&hapd->ctrl_dst);
|
||||
dl_list_init(&hapd->nr_db);
|
||||
|
||||
return hapd;
|
||||
}
|
||||
@ -1785,6 +2008,8 @@ hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
|
||||
|
||||
static void hostapd_bss_deinit(struct hostapd_data *hapd)
|
||||
{
|
||||
if (!hapd)
|
||||
return;
|
||||
wpa_printf(MSG_DEBUG, "%s: deinit bss %s", __func__,
|
||||
hapd->conf->iface);
|
||||
hostapd_bss_deinit_no_free(hapd);
|
||||
@ -1819,8 +2044,11 @@ void hostapd_interface_deinit(struct hostapd_iface *iface)
|
||||
}
|
||||
#endif /* CONFIG_FST */
|
||||
|
||||
for (j = iface->num_bss - 1; j >= 0; j--)
|
||||
for (j = iface->num_bss - 1; j >= 0; j--) {
|
||||
if (!iface->bss)
|
||||
break;
|
||||
hostapd_bss_deinit(iface->bss[j]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1829,6 +2057,8 @@ void hostapd_interface_free(struct hostapd_iface *iface)
|
||||
size_t j;
|
||||
wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
|
||||
for (j = 0; j < iface->num_bss; j++) {
|
||||
if (!iface->bss)
|
||||
break;
|
||||
wpa_printf(MSG_DEBUG, "%s: free hapd %p",
|
||||
__func__, iface->bss[j]);
|
||||
os_free(iface->bss[j]);
|
||||
@ -1837,6 +2067,20 @@ void hostapd_interface_free(struct hostapd_iface *iface)
|
||||
}
|
||||
|
||||
|
||||
struct hostapd_iface * hostapd_alloc_iface(void)
|
||||
{
|
||||
struct hostapd_iface *hapd_iface;
|
||||
|
||||
hapd_iface = os_zalloc(sizeof(*hapd_iface));
|
||||
if (!hapd_iface)
|
||||
return NULL;
|
||||
|
||||
dl_list_init(&hapd_iface->sta_seen);
|
||||
|
||||
return hapd_iface;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hostapd_init - Allocate and initialize per-interface data
|
||||
* @config_file: Path to the configuration file
|
||||
@ -1854,7 +2098,7 @@ struct hostapd_iface * hostapd_init(struct hapd_interfaces *interfaces,
|
||||
struct hostapd_data *hapd;
|
||||
size_t i;
|
||||
|
||||
hapd_iface = os_zalloc(sizeof(*hapd_iface));
|
||||
hapd_iface = hostapd_alloc_iface();
|
||||
if (hapd_iface == NULL)
|
||||
goto fail;
|
||||
|
||||
@ -2190,7 +2434,7 @@ hostapd_iface_alloc(struct hapd_interfaces *interfaces)
|
||||
return NULL;
|
||||
interfaces->iface = iface;
|
||||
hapd_iface = interfaces->iface[interfaces->count] =
|
||||
os_zalloc(sizeof(*hapd_iface));
|
||||
hostapd_alloc_iface();
|
||||
if (hapd_iface == NULL) {
|
||||
wpa_printf(MSG_ERROR, "%s: Failed to allocate memory for "
|
||||
"the interface", __func__);
|
||||
@ -2557,6 +2801,7 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
}
|
||||
|
||||
hostapd_prune_associations(hapd, sta->addr);
|
||||
ap_sta_clear_disconnect_timeouts(hapd, sta);
|
||||
|
||||
/* IEEE 802.11F (IAPP) */
|
||||
if (hapd->conf->ieee802_11f)
|
||||
@ -2590,9 +2835,10 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm);
|
||||
|
||||
if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
|
||||
wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
|
||||
"for " MACSTR " (%d seconds - ap_max_inactivity)",
|
||||
__func__, MAC2STR(sta->addr),
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"%s: %s: reschedule ap_handle_timer timeout for "
|
||||
MACSTR " (%d seconds - ap_max_inactivity)",
|
||||
hapd->conf->iface, __func__, MAC2STR(sta->addr),
|
||||
hapd->conf->ap_max_inactivity);
|
||||
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
|
||||
eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
|
||||
@ -2627,12 +2873,23 @@ const char * hostapd_state_text(enum hostapd_iface_state s)
|
||||
void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s)
|
||||
{
|
||||
wpa_printf(MSG_INFO, "%s: interface state %s->%s",
|
||||
iface->conf->bss[0]->iface, hostapd_state_text(iface->state),
|
||||
hostapd_state_text(s));
|
||||
iface->conf ? iface->conf->bss[0]->iface : "N/A",
|
||||
hostapd_state_text(iface->state), hostapd_state_text(s));
|
||||
iface->state = s;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_csa_in_progress(struct hostapd_iface *iface)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < iface->num_bss; i++)
|
||||
if (iface->bss[i]->csa_in_progress)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef NEED_AP_MLME
|
||||
|
||||
static void free_beacon_data(struct beacon_data *beacon)
|
||||
@ -2744,9 +3001,9 @@ static int hostapd_build_beacon_data(struct hostapd_data *hapd,
|
||||
|
||||
|
||||
/*
|
||||
* TODO: This flow currently supports only changing frequency within the
|
||||
* same hw_mode. Any other changes to MAC parameters or provided settings (even
|
||||
* width) are not supported.
|
||||
* TODO: This flow currently supports only changing channel and width within
|
||||
* the same hw_mode. Any other changes to MAC parameters or provided settings
|
||||
* are not supported.
|
||||
*/
|
||||
static int hostapd_change_config_freq(struct hostapd_data *hapd,
|
||||
struct hostapd_config *conf,
|
||||
@ -2765,15 +3022,44 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd,
|
||||
return -1;
|
||||
|
||||
/* if a pointer to old_params is provided we save previous state */
|
||||
if (old_params) {
|
||||
old_params->channel = conf->channel;
|
||||
old_params->ht_enabled = conf->ieee80211n;
|
||||
old_params->sec_channel_offset = conf->secondary_channel;
|
||||
if (old_params &&
|
||||
hostapd_set_freq_params(old_params, conf->hw_mode,
|
||||
hostapd_hw_get_freq(hapd, conf->channel),
|
||||
conf->channel, conf->ieee80211n,
|
||||
conf->ieee80211ac,
|
||||
conf->secondary_channel,
|
||||
conf->vht_oper_chwidth,
|
||||
conf->vht_oper_centr_freq_seg0_idx,
|
||||
conf->vht_oper_centr_freq_seg1_idx,
|
||||
conf->vht_capab))
|
||||
return -1;
|
||||
|
||||
switch (params->bandwidth) {
|
||||
case 0:
|
||||
case 20:
|
||||
case 40:
|
||||
conf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT;
|
||||
break;
|
||||
case 80:
|
||||
if (params->center_freq2)
|
||||
conf->vht_oper_chwidth = VHT_CHANWIDTH_80P80MHZ;
|
||||
else
|
||||
conf->vht_oper_chwidth = VHT_CHANWIDTH_80MHZ;
|
||||
break;
|
||||
case 160:
|
||||
conf->vht_oper_chwidth = VHT_CHANWIDTH_160MHZ;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
conf->channel = channel;
|
||||
conf->ieee80211n = params->ht_enabled;
|
||||
conf->secondary_channel = params->sec_channel_offset;
|
||||
ieee80211_freq_to_chan(params->center_freq1,
|
||||
&conf->vht_oper_centr_freq_seg0_idx);
|
||||
ieee80211_freq_to_chan(params->center_freq2,
|
||||
&conf->vht_oper_centr_freq_seg1_idx);
|
||||
|
||||
/* TODO: maybe call here hostapd_config_check here? */
|
||||
|
||||
@ -2787,11 +3073,43 @@ static int hostapd_fill_csa_settings(struct hostapd_data *hapd,
|
||||
struct hostapd_iface *iface = hapd->iface;
|
||||
struct hostapd_freq_params old_freq;
|
||||
int ret;
|
||||
u8 chan, vht_bandwidth;
|
||||
|
||||
os_memset(&old_freq, 0, sizeof(old_freq));
|
||||
if (!iface || !iface->freq || hapd->csa_in_progress)
|
||||
return -1;
|
||||
|
||||
switch (settings->freq_params.bandwidth) {
|
||||
case 80:
|
||||
if (settings->freq_params.center_freq2)
|
||||
vht_bandwidth = VHT_CHANWIDTH_80P80MHZ;
|
||||
else
|
||||
vht_bandwidth = VHT_CHANWIDTH_80MHZ;
|
||||
break;
|
||||
case 160:
|
||||
vht_bandwidth = VHT_CHANWIDTH_160MHZ;
|
||||
break;
|
||||
default:
|
||||
vht_bandwidth = VHT_CHANWIDTH_USE_HT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ieee80211_freq_to_channel_ext(
|
||||
settings->freq_params.freq,
|
||||
settings->freq_params.sec_channel_offset,
|
||||
vht_bandwidth,
|
||||
&hapd->iface->cs_oper_class,
|
||||
&chan) == NUM_HOSTAPD_MODES) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"invalid frequency for channel switch (freq=%d, sec_channel_offset=%d, vht_enabled=%d)",
|
||||
settings->freq_params.freq,
|
||||
settings->freq_params.sec_channel_offset,
|
||||
settings->freq_params.vht_enabled);
|
||||
return -1;
|
||||
}
|
||||
|
||||
settings->freq_params.channel = chan;
|
||||
|
||||
ret = hostapd_change_config_freq(iface->bss[0], iface->conf,
|
||||
&settings->freq_params,
|
||||
&old_freq);
|
||||
@ -2818,8 +3136,10 @@ static int hostapd_fill_csa_settings(struct hostapd_data *hapd,
|
||||
return ret;
|
||||
}
|
||||
|
||||
settings->counter_offset_beacon = hapd->cs_c_off_beacon;
|
||||
settings->counter_offset_presp = hapd->cs_c_off_proberesp;
|
||||
settings->counter_offset_beacon[0] = hapd->cs_c_off_beacon;
|
||||
settings->counter_offset_presp[0] = hapd->cs_c_off_proberesp;
|
||||
settings->counter_offset_beacon[1] = hapd->cs_c_off_ecsa_beacon;
|
||||
settings->counter_offset_presp[1] = hapd->cs_c_off_ecsa_proberesp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -2833,6 +3153,8 @@ void hostapd_cleanup_cs_params(struct hostapd_data *hapd)
|
||||
hapd->cs_c_off_beacon = 0;
|
||||
hapd->cs_c_off_proberesp = 0;
|
||||
hapd->csa_in_progress = 0;
|
||||
hapd->cs_c_off_ecsa_beacon = 0;
|
||||
hapd->cs_c_off_ecsa_proberesp = 0;
|
||||
}
|
||||
|
||||
|
||||
@ -2920,6 +3242,8 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface,
|
||||
hostapd_enable_iface(iface);
|
||||
}
|
||||
|
||||
#endif /* NEED_AP_MLME */
|
||||
|
||||
|
||||
struct hostapd_data * hostapd_get_iface(struct hapd_interfaces *interfaces,
|
||||
const char *ifname)
|
||||
@ -2940,8 +3264,6 @@ struct hostapd_data * hostapd_get_iface(struct hapd_interfaces *interfaces,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* NEED_AP_MLME */
|
||||
|
||||
|
||||
void hostapd_periodic_iface(struct hostapd_iface *iface)
|
||||
{
|
||||
|
@ -41,7 +41,7 @@ struct hapd_interfaces {
|
||||
|
||||
size_t count;
|
||||
int global_ctrl_sock;
|
||||
struct wpa_ctrl_dst *global_ctrl_dst;
|
||||
struct dl_list global_ctrl_dst;
|
||||
char *global_iface_path;
|
||||
char *global_iface_name;
|
||||
#ifndef CONFIG_NATIVE_WINDOWS
|
||||
@ -53,6 +53,7 @@ struct hapd_interfaces {
|
||||
#ifndef CONFIG_NO_VLAN
|
||||
struct dynamic_iface *vlan_priv;
|
||||
#endif /* CONFIG_NO_VLAN */
|
||||
int eloop_initialized;
|
||||
};
|
||||
|
||||
enum hostapd_chan_status {
|
||||
@ -99,6 +100,16 @@ struct wps_stat {
|
||||
u8 peer_addr[ETH_ALEN];
|
||||
};
|
||||
|
||||
struct hostapd_neighbor_entry {
|
||||
struct dl_list list;
|
||||
u8 bssid[ETH_ALEN];
|
||||
struct wpa_ssid_value ssid;
|
||||
struct wpabuf *nr;
|
||||
struct wpabuf *lci;
|
||||
struct wpabuf *civic;
|
||||
/* LCI update time */
|
||||
struct os_time lci_date;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct hostapd_data - hostapd per-BSS data structure
|
||||
@ -138,7 +149,7 @@ struct hostapd_data {
|
||||
void *msg_ctx_parent; /* parent interface ctx for wpa_msg() calls */
|
||||
|
||||
struct radius_client_data *radius;
|
||||
u32 acct_session_id_hi, acct_session_id_lo;
|
||||
u64 acct_session_id;
|
||||
struct radius_das_data *radius_das;
|
||||
|
||||
struct iapp_data *iapp;
|
||||
@ -155,7 +166,7 @@ struct hostapd_data {
|
||||
int tkip_countermeasures;
|
||||
|
||||
int ctrl_sock;
|
||||
struct wpa_ctrl_dst *ctrl_dst;
|
||||
struct dl_list ctrl_dst;
|
||||
|
||||
void *ssl_ctx;
|
||||
void *eap_sim_db_priv;
|
||||
@ -228,6 +239,8 @@ struct hostapd_data {
|
||||
unsigned int cs_c_off_beacon;
|
||||
unsigned int cs_c_off_proberesp;
|
||||
int csa_in_progress;
|
||||
unsigned int cs_c_off_ecsa_beacon;
|
||||
unsigned int cs_c_off_ecsa_proberesp;
|
||||
|
||||
/* BSS Load */
|
||||
unsigned int bss_load_update_timeout;
|
||||
@ -256,9 +269,11 @@ struct hostapd_data {
|
||||
#ifdef CONFIG_MESH
|
||||
int num_plinks;
|
||||
int max_plinks;
|
||||
void (*mesh_sta_free_cb)(struct sta_info *sta);
|
||||
void (*mesh_sta_free_cb)(struct hostapd_data *hapd,
|
||||
struct sta_info *sta);
|
||||
struct wpabuf *mesh_pending_auth;
|
||||
struct os_reltime mesh_pending_auth_time;
|
||||
u8 mesh_required_peer[ETH_ALEN];
|
||||
#endif /* CONFIG_MESH */
|
||||
|
||||
#ifdef CONFIG_SQLITE
|
||||
@ -278,6 +293,17 @@ struct hostapd_data {
|
||||
|
||||
struct l2_packet_data *l2_test;
|
||||
#endif /* CONFIG_TESTING_OPTIONS */
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
unsigned int mbo_assoc_disallow;
|
||||
#endif /* CONFIG_MBO */
|
||||
|
||||
struct dl_list nr_db;
|
||||
|
||||
u8 lci_req_token;
|
||||
u8 range_req_token;
|
||||
unsigned int lci_req_active:1;
|
||||
unsigned int range_req_active:1;
|
||||
};
|
||||
|
||||
|
||||
@ -285,6 +311,9 @@ struct hostapd_sta_info {
|
||||
struct dl_list list;
|
||||
u8 addr[ETH_ALEN];
|
||||
struct os_reltime last_seen;
|
||||
#ifdef CONFIG_TAXONOMY
|
||||
struct wpabuf *probe_ie_taxonomy;
|
||||
#endif /* CONFIG_TAXONOMY */
|
||||
};
|
||||
|
||||
/**
|
||||
@ -327,6 +356,15 @@ struct hostapd_iface {
|
||||
*/
|
||||
unsigned int driver_ap_teardown:1;
|
||||
|
||||
/*
|
||||
* When set, indicates that this interface is part of list of
|
||||
* interfaces that need to be started together (synchronously).
|
||||
*/
|
||||
unsigned int need_to_start_in_sync:1;
|
||||
|
||||
/* Ready to start but waiting for other interfaces to become ready. */
|
||||
unsigned int ready_to_start_in_sync:1;
|
||||
|
||||
int num_ap; /* number of entries in ap_list */
|
||||
struct ap_info *ap_list; /* AP info list head */
|
||||
struct ap_info *ap_hash[STA_HASH_SIZE];
|
||||
@ -402,6 +440,9 @@ struct hostapd_iface {
|
||||
u64 last_channel_time_busy;
|
||||
u8 channel_utilization;
|
||||
|
||||
/* eCSA IE will be added only if operating class is specified */
|
||||
u8 cs_oper_class;
|
||||
|
||||
unsigned int dfs_cac_ms;
|
||||
struct os_reltime dfs_cac_start;
|
||||
|
||||
@ -433,6 +474,7 @@ int hostapd_setup_interface(struct hostapd_iface *iface);
|
||||
int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err);
|
||||
void hostapd_interface_deinit(struct hostapd_iface *iface);
|
||||
void hostapd_interface_free(struct hostapd_iface *iface);
|
||||
struct hostapd_iface * hostapd_alloc_iface(void);
|
||||
struct hostapd_iface * hostapd_init(struct hapd_interfaces *interfaces,
|
||||
const char *config_file);
|
||||
struct hostapd_iface *
|
||||
@ -449,6 +491,7 @@ int hostapd_remove_iface(struct hapd_interfaces *ifaces, char *buf);
|
||||
void hostapd_channel_list_updated(struct hostapd_iface *iface, int initiator);
|
||||
void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s);
|
||||
const char * hostapd_state_text(enum hostapd_iface_state s);
|
||||
int hostapd_csa_in_progress(struct hostapd_iface *iface);
|
||||
int hostapd_switch_channel(struct hostapd_data *hapd,
|
||||
struct csa_settings *settings);
|
||||
void
|
||||
@ -478,6 +521,11 @@ int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
|
||||
int ssi_signal);
|
||||
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
|
||||
int offset, int width, int cf1, int cf2);
|
||||
struct survey_results;
|
||||
void hostapd_event_get_survey(struct hostapd_iface *iface,
|
||||
struct survey_results *survey_results);
|
||||
void hostapd_acs_channel_selected(struct hostapd_data *hapd,
|
||||
struct acs_selected_channels *acs_res);
|
||||
|
||||
const struct hostapd_eap_user *
|
||||
hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
|
||||
|
@ -329,6 +329,7 @@ static void ieee80211n_check_scan(struct hostapd_iface *iface)
|
||||
res = ieee80211n_allowed_ht40_channel_pair(iface);
|
||||
if (!res) {
|
||||
iface->conf->secondary_channel = 0;
|
||||
res = 1;
|
||||
wpa_printf(MSG_INFO, "Fallback to 20 MHz");
|
||||
}
|
||||
|
||||
@ -472,8 +473,9 @@ static int ieee80211n_check_40mhz(struct hostapd_iface *iface)
|
||||
struct wpa_driver_scan_params params;
|
||||
int ret;
|
||||
|
||||
if (!iface->conf->secondary_channel)
|
||||
return 0; /* HT40 not used */
|
||||
/* Check that HT40 is used and PRI / SEC switch is allowed */
|
||||
if (!iface->conf->secondary_channel || iface->conf->no_pri_sec_switch)
|
||||
return 0;
|
||||
|
||||
hostapd_set_state(iface, HAPD_IFACE_HT_SCAN);
|
||||
wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling "
|
||||
|
@ -34,11 +34,7 @@
|
||||
#include "utils/includes.h"
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
#ifdef USE_KERNEL_HEADERS
|
||||
#include <linux/if_packet.h>
|
||||
#else /* USE_KERNEL_HEADERS */
|
||||
#include <netpacket/packet.h>
|
||||
#endif /* USE_KERNEL_HEADERS */
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "utils/eloop.h"
|
||||
@ -385,6 +381,7 @@ struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface)
|
||||
struct sockaddr_in *paddr, uaddr;
|
||||
struct iapp_data *iapp;
|
||||
struct ip_mreqn mreq;
|
||||
int reuseaddr = 1;
|
||||
|
||||
iapp = os_zalloc(sizeof(*iapp));
|
||||
if (iapp == NULL)
|
||||
@ -447,6 +444,18 @@ struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface)
|
||||
os_memset(&uaddr, 0, sizeof(uaddr));
|
||||
uaddr.sin_family = AF_INET;
|
||||
uaddr.sin_port = htons(IAPP_UDP_PORT);
|
||||
|
||||
if (setsockopt(iapp->udp_sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
|
||||
sizeof(reuseaddr)) < 0) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"iapp_init - setsockopt[UDP,SO_REUSEADDR]: %s",
|
||||
strerror(errno));
|
||||
/*
|
||||
* Ignore this and try to continue. This is fine for single
|
||||
* BSS cases, but may fail if multiple BSSes enable IAPP.
|
||||
*/
|
||||
}
|
||||
|
||||
if (bind(iapp->udp_sock, (struct sockaddr *) &uaddr,
|
||||
sizeof(uaddr)) < 0) {
|
||||
wpa_printf(MSG_INFO, "iapp_init - bind[UDP]: %s",
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -49,9 +49,13 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid, u32 nsts);
|
||||
u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid);
|
||||
u8 * hostapd_eid_txpower_envelope(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,
|
||||
const u8 *addr, const u8 *trans_id);
|
||||
@ -61,6 +65,7 @@ void hostapd_get_ht_capab(struct hostapd_data *hapd,
|
||||
void hostapd_get_vht_capab(struct hostapd_data *hapd,
|
||||
struct ieee80211_vht_capabilities *vht_cap,
|
||||
struct ieee80211_vht_capabilities *neg_vht_cap);
|
||||
int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *ht_capab);
|
||||
u16 copy_sta_vendor_vht(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
@ -97,6 +102,7 @@ int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
#ifdef CONFIG_SAE
|
||||
void sae_clear_retransmit_timer(struct hostapd_data *hapd,
|
||||
struct sta_info *sta);
|
||||
void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
#else /* CONFIG_SAE */
|
||||
static inline void sae_clear_retransmit_timer(struct hostapd_data *hapd,
|
||||
struct sta_info *sta)
|
||||
@ -104,4 +110,29 @@ static inline void sae_clear_retransmit_timer(struct hostapd_data *hapd,
|
||||
}
|
||||
#endif /* CONFIG_SAE */
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
|
||||
u8 * hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid, size_t len);
|
||||
|
||||
u8 hostapd_mbo_ie_len(struct hostapd_data *hapd);
|
||||
|
||||
#else /* CONFIG_MBO */
|
||||
|
||||
static inline u8 * hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid,
|
||||
size_t len)
|
||||
{
|
||||
return eid;
|
||||
}
|
||||
|
||||
static inline u8 hostapd_mbo_ie_len(struct hostapd_data *hapd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MBO */
|
||||
|
||||
void ap_copy_sta_supp_op_classes(struct sta_info *sta,
|
||||
const u8 *supp_op_classes,
|
||||
size_t supp_op_classes_len);
|
||||
|
||||
#endif /* IEEE802_11_H */
|
||||
|
@ -15,7 +15,6 @@
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "utils/eloop.h"
|
||||
#include "crypto/sha1.h"
|
||||
#include "radius/radius.h"
|
||||
#include "radius/radius_client.h"
|
||||
#include "hostapd.h"
|
||||
@ -35,7 +34,7 @@ struct hostapd_cached_radius_acl {
|
||||
struct hostapd_cached_radius_acl *next;
|
||||
u32 session_timeout;
|
||||
u32 acct_interim_interval;
|
||||
int vlan_id;
|
||||
struct vlan_description vlan_id;
|
||||
struct hostapd_sta_wpa_psk_short *psk;
|
||||
char *identity;
|
||||
char *radius_cui;
|
||||
@ -77,29 +76,20 @@ static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
|
||||
static void copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
|
||||
struct hostapd_sta_wpa_psk_short *src)
|
||||
{
|
||||
struct hostapd_sta_wpa_psk_short **copy_to;
|
||||
struct hostapd_sta_wpa_psk_short *copy_from;
|
||||
if (!psk)
|
||||
return;
|
||||
|
||||
/* Copy PSK linked list */
|
||||
copy_to = psk;
|
||||
copy_from = src;
|
||||
while (copy_from && copy_to) {
|
||||
*copy_to = os_zalloc(sizeof(struct hostapd_sta_wpa_psk_short));
|
||||
if (*copy_to == NULL)
|
||||
break;
|
||||
os_memcpy(*copy_to, copy_from,
|
||||
sizeof(struct hostapd_sta_wpa_psk_short));
|
||||
copy_from = copy_from->next;
|
||||
copy_to = &((*copy_to)->next);
|
||||
}
|
||||
if (copy_to)
|
||||
*copy_to = NULL;
|
||||
if (src)
|
||||
src->ref++;
|
||||
|
||||
*psk = src;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
|
||||
u32 *session_timeout,
|
||||
u32 *acct_interim_interval, int *vlan_id,
|
||||
u32 *acct_interim_interval,
|
||||
struct vlan_description *vlan_id,
|
||||
struct hostapd_sta_wpa_psk_short **psk,
|
||||
char **identity, char **radius_cui)
|
||||
{
|
||||
@ -165,7 +155,10 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
|
||||
if (msg == NULL)
|
||||
return -1;
|
||||
|
||||
radius_msg_make_authenticator(msg, addr, ETH_ALEN);
|
||||
if (radius_msg_make_authenticator(msg) < 0) {
|
||||
wpa_printf(MSG_INFO, "Could not make Request Authenticator");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, MAC2STR(addr));
|
||||
if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, (u8 *) buf,
|
||||
@ -212,6 +205,33 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
|
||||
|
||||
/**
|
||||
* hostapd_check_acl - Check a specified STA against accept/deny ACLs
|
||||
* @hapd: hostapd BSS data
|
||||
* @addr: MAC address of the STA
|
||||
* @vlan_id: Buffer for returning VLAN ID
|
||||
* Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
|
||||
*/
|
||||
int hostapd_check_acl(struct hostapd_data *hapd, const u8 *addr,
|
||||
struct vlan_description *vlan_id)
|
||||
{
|
||||
if (hostapd_maclist_found(hapd->conf->accept_mac,
|
||||
hapd->conf->num_accept_mac, addr, vlan_id))
|
||||
return HOSTAPD_ACL_ACCEPT;
|
||||
|
||||
if (hostapd_maclist_found(hapd->conf->deny_mac,
|
||||
hapd->conf->num_deny_mac, addr, vlan_id))
|
||||
return HOSTAPD_ACL_REJECT;
|
||||
|
||||
if (hapd->conf->macaddr_acl == ACCEPT_UNLESS_DENIED)
|
||||
return HOSTAPD_ACL_ACCEPT;
|
||||
if (hapd->conf->macaddr_acl == DENY_UNLESS_ACCEPTED)
|
||||
return HOSTAPD_ACL_REJECT;
|
||||
|
||||
return HOSTAPD_ACL_PENDING;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hostapd_allowed_address - Check whether a specified STA can be authenticated
|
||||
* @hapd: hostapd BSS data
|
||||
@ -231,16 +251,19 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
|
||||
*/
|
||||
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
|
||||
const u8 *msg, size_t len, u32 *session_timeout,
|
||||
u32 *acct_interim_interval, int *vlan_id,
|
||||
u32 *acct_interim_interval,
|
||||
struct vlan_description *vlan_id,
|
||||
struct hostapd_sta_wpa_psk_short **psk,
|
||||
char **identity, char **radius_cui)
|
||||
{
|
||||
int res;
|
||||
|
||||
if (session_timeout)
|
||||
*session_timeout = 0;
|
||||
if (acct_interim_interval)
|
||||
*acct_interim_interval = 0;
|
||||
if (vlan_id)
|
||||
*vlan_id = 0;
|
||||
os_memset(vlan_id, 0, sizeof(*vlan_id));
|
||||
if (psk)
|
||||
*psk = NULL;
|
||||
if (identity)
|
||||
@ -248,18 +271,9 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
|
||||
if (radius_cui)
|
||||
*radius_cui = NULL;
|
||||
|
||||
if (hostapd_maclist_found(hapd->conf->accept_mac,
|
||||
hapd->conf->num_accept_mac, addr, vlan_id))
|
||||
return HOSTAPD_ACL_ACCEPT;
|
||||
|
||||
if (hostapd_maclist_found(hapd->conf->deny_mac,
|
||||
hapd->conf->num_deny_mac, addr, vlan_id))
|
||||
return HOSTAPD_ACL_REJECT;
|
||||
|
||||
if (hapd->conf->macaddr_acl == ACCEPT_UNLESS_DENIED)
|
||||
return HOSTAPD_ACL_ACCEPT;
|
||||
if (hapd->conf->macaddr_acl == DENY_UNLESS_ACCEPTED)
|
||||
return HOSTAPD_ACL_REJECT;
|
||||
res = hostapd_check_acl(hapd, addr, vlan_id);
|
||||
if (res != HOSTAPD_ACL_PENDING)
|
||||
return res;
|
||||
|
||||
if (hapd->conf->macaddr_acl == USE_EXTERNAL_RADIUS_AUTH) {
|
||||
#ifdef CONFIG_NO_RADIUS
|
||||
@ -268,10 +282,9 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
|
||||
struct hostapd_acl_query_data *query;
|
||||
|
||||
/* Check whether ACL cache has an entry for this station */
|
||||
int res = hostapd_acl_cache_get(hapd, addr, session_timeout,
|
||||
acct_interim_interval,
|
||||
vlan_id, psk,
|
||||
identity, radius_cui);
|
||||
res = hostapd_acl_cache_get(hapd, addr, session_timeout,
|
||||
acct_interim_interval, vlan_id, psk,
|
||||
identity, radius_cui);
|
||||
if (res == HOSTAPD_ACL_ACCEPT ||
|
||||
res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
|
||||
return res;
|
||||
@ -419,7 +432,7 @@ static void decode_tunnel_passwords(struct hostapd_data *hapd,
|
||||
struct hostapd_cached_radius_acl *cache)
|
||||
{
|
||||
int passphraselen;
|
||||
char *passphrase, *strpassphrase;
|
||||
char *passphrase;
|
||||
size_t i;
|
||||
struct hostapd_sta_wpa_psk_short *psk;
|
||||
|
||||
@ -436,24 +449,42 @@ static void decode_tunnel_passwords(struct hostapd_data *hapd,
|
||||
*/
|
||||
if (passphrase == NULL)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Passphase should be 8..63 chars (to be hashed with SSID)
|
||||
* or 64 chars hex string (no separate hashing with SSID).
|
||||
*/
|
||||
|
||||
if (passphraselen < MIN_PASSPHRASE_LEN ||
|
||||
passphraselen > MAX_PASSPHRASE_LEN + 1)
|
||||
goto free_pass;
|
||||
|
||||
/*
|
||||
* passphrase does not contain the NULL termination.
|
||||
* Add it here as pbkdf2_sha1() requires it.
|
||||
*/
|
||||
strpassphrase = os_zalloc(passphraselen + 1);
|
||||
psk = os_zalloc(sizeof(struct hostapd_sta_wpa_psk_short));
|
||||
if (strpassphrase && psk) {
|
||||
os_memcpy(strpassphrase, passphrase, passphraselen);
|
||||
pbkdf2_sha1(strpassphrase,
|
||||
hapd->conf->ssid.ssid,
|
||||
hapd->conf->ssid.ssid_len, 4096,
|
||||
psk->psk, PMK_LEN);
|
||||
if (psk) {
|
||||
if ((passphraselen == MAX_PASSPHRASE_LEN + 1) &&
|
||||
(hexstr2bin(passphrase, psk->psk, PMK_LEN) < 0)) {
|
||||
hostapd_logger(hapd, cache->addr,
|
||||
HOSTAPD_MODULE_RADIUS,
|
||||
HOSTAPD_LEVEL_WARNING,
|
||||
"invalid hex string (%d chars) in Tunnel-Password",
|
||||
passphraselen);
|
||||
goto skip;
|
||||
} else if (passphraselen <= MAX_PASSPHRASE_LEN) {
|
||||
os_memcpy(psk->passphrase, passphrase,
|
||||
passphraselen);
|
||||
psk->is_passphrase = 1;
|
||||
}
|
||||
psk->next = cache->psk;
|
||||
cache->psk = psk;
|
||||
psk = NULL;
|
||||
}
|
||||
os_free(strpassphrase);
|
||||
skip:
|
||||
os_free(psk);
|
||||
free_pass:
|
||||
os_free(passphrase);
|
||||
}
|
||||
}
|
||||
@ -478,6 +509,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
|
||||
struct hostapd_acl_query_data *query, *prev;
|
||||
struct hostapd_cached_radius_acl *cache;
|
||||
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
|
||||
int *untagged, *tagged, *notempty;
|
||||
|
||||
query = hapd->acl_queries;
|
||||
prev = NULL;
|
||||
@ -535,7 +567,12 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
|
||||
cache->acct_interim_interval = 0;
|
||||
}
|
||||
|
||||
cache->vlan_id = radius_msg_get_vlanid(msg);
|
||||
notempty = &cache->vlan_id.notempty;
|
||||
untagged = &cache->vlan_id.untagged;
|
||||
tagged = cache->vlan_id.tagged;
|
||||
*notempty = !!radius_msg_get_vlanid(msg, untagged,
|
||||
MAX_NUM_TAGGED_VLAN,
|
||||
tagged);
|
||||
|
||||
decode_tunnel_passwords(hapd, shared_secret, shared_secret_len,
|
||||
msg, req, cache);
|
||||
@ -558,17 +595,18 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
|
||||
!cache->psk)
|
||||
cache->accepted = HOSTAPD_ACL_REJECT;
|
||||
|
||||
if (cache->vlan_id &&
|
||||
!hostapd_vlan_id_valid(hapd->conf->vlan, cache->vlan_id)) {
|
||||
if (cache->vlan_id.notempty &&
|
||||
!hostapd_vlan_valid(hapd->conf->vlan, &cache->vlan_id)) {
|
||||
hostapd_logger(hapd, query->addr,
|
||||
HOSTAPD_MODULE_RADIUS,
|
||||
HOSTAPD_LEVEL_INFO,
|
||||
"Invalid VLAN ID %d received from RADIUS server",
|
||||
cache->vlan_id);
|
||||
cache->vlan_id = 0;
|
||||
"Invalid VLAN %d%s received from RADIUS server",
|
||||
cache->vlan_id.untagged,
|
||||
cache->vlan_id.tagged[0] ? "+" : "");
|
||||
os_memset(&cache->vlan_id, 0, sizeof(cache->vlan_id));
|
||||
}
|
||||
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
|
||||
!cache->vlan_id)
|
||||
!cache->vlan_id.notempty)
|
||||
cache->accepted = HOSTAPD_ACL_REJECT;
|
||||
} else
|
||||
cache->accepted = HOSTAPD_ACL_REJECT;
|
||||
@ -640,6 +678,12 @@ void hostapd_acl_deinit(struct hostapd_data *hapd)
|
||||
|
||||
void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk)
|
||||
{
|
||||
if (psk && psk->ref) {
|
||||
/* This will be freed when the last reference is dropped. */
|
||||
psk->ref--;
|
||||
return;
|
||||
}
|
||||
|
||||
while (psk) {
|
||||
struct hostapd_sta_wpa_psk_short *prev = psk;
|
||||
psk = psk->next;
|
||||
|
@ -16,9 +16,12 @@ enum {
|
||||
HOSTAPD_ACL_ACCEPT_TIMEOUT = 3
|
||||
};
|
||||
|
||||
int hostapd_check_acl(struct hostapd_data *hapd, const u8 *addr,
|
||||
struct vlan_description *vlan_id);
|
||||
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
|
||||
const u8 *msg, size_t len, u32 *session_timeout,
|
||||
u32 *acct_interim_interval, int *vlan_id,
|
||||
u32 *acct_interim_interval,
|
||||
struct vlan_description *vlan_id,
|
||||
struct hostapd_sta_wpa_psk_short **psk,
|
||||
char **identity, char **radius_cui);
|
||||
int hostapd_acl_init(struct hostapd_data *hapd);
|
||||
|
@ -108,6 +108,29 @@ u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid)
|
||||
}
|
||||
|
||||
|
||||
u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid)
|
||||
{
|
||||
u8 sec_ch;
|
||||
|
||||
if (!hapd->cs_freq_params.channel ||
|
||||
!hapd->cs_freq_params.sec_channel_offset)
|
||||
return eid;
|
||||
|
||||
if (hapd->cs_freq_params.sec_channel_offset == -1)
|
||||
sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW;
|
||||
else if (hapd->cs_freq_params.sec_channel_offset == 1)
|
||||
sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE;
|
||||
else
|
||||
return eid;
|
||||
|
||||
*eid++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET;
|
||||
*eid++ = 1;
|
||||
*eid++ = sec_ch;
|
||||
|
||||
return eid;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
op_mode
|
||||
Set to 0 (HT pure) under the followign conditions
|
||||
|
@ -172,6 +172,8 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
|
||||
case 0: /* Bits 0-7 */
|
||||
if (hapd->iconf->obss_interval)
|
||||
*pos |= 0x01; /* Bit 0 - Coexistence management */
|
||||
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA)
|
||||
*pos |= 0x04; /* Bit 2 - Extended Channel Switching */
|
||||
break;
|
||||
case 1: /* Bits 8-15 */
|
||||
if (hapd->conf->proxy_arp)
|
||||
@ -207,11 +209,21 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
|
||||
if (hapd->conf->hs20)
|
||||
*pos |= 0x40; /* Bit 46 - WNM-Notification */
|
||||
#endif /* CONFIG_HS20 */
|
||||
#ifdef CONFIG_MBO
|
||||
if (hapd->conf->mbo_enabled)
|
||||
*pos |= 0x40; /* Bit 46 - WNM-Notification */
|
||||
#endif /* CONFIG_MBO */
|
||||
break;
|
||||
case 6: /* Bits 48-55 */
|
||||
if (hapd->conf->ssid.utf8_ssid)
|
||||
*pos |= 0x01; /* Bit 48 - UTF-8 SSID */
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -231,6 +243,9 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
|
||||
len = 1;
|
||||
if (len < 7 && hapd->conf->ssid.utf8_ssid)
|
||||
len = 7;
|
||||
if (len < 9 &&
|
||||
(hapd->conf->ftm_initiator || hapd->conf->ftm_responder))
|
||||
len = 9;
|
||||
#ifdef CONFIG_WNM
|
||||
if (len < 4)
|
||||
len = 4;
|
||||
@ -239,6 +254,10 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
|
||||
if (hapd->conf->hs20 && len < 6)
|
||||
len = 6;
|
||||
#endif /* CONFIG_HS20 */
|
||||
#ifdef CONFIG_MBO
|
||||
if (hapd->conf->mbo_enabled && len < 6)
|
||||
len = 6;
|
||||
#endif /* CONFIG_MBO */
|
||||
if (len < hapd->iface->extended_capa_len)
|
||||
len = hapd->iface->extended_capa_len;
|
||||
if (len == 0)
|
||||
@ -506,3 +525,62 @@ u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid)
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
|
||||
u8 * hostapd_eid_mbo(struct hostapd_data *hapd, u8 *eid, size_t len)
|
||||
{
|
||||
u8 mbo[6], *mbo_pos = mbo;
|
||||
u8 *pos = eid;
|
||||
|
||||
if (!hapd->conf->mbo_enabled)
|
||||
return eid;
|
||||
|
||||
*mbo_pos++ = MBO_ATTR_ID_AP_CAPA_IND;
|
||||
*mbo_pos++ = 1;
|
||||
/* Not Cellular aware */
|
||||
*mbo_pos++ = 0;
|
||||
|
||||
if (hapd->mbo_assoc_disallow) {
|
||||
*mbo_pos++ = MBO_ATTR_ID_ASSOC_DISALLOW;
|
||||
*mbo_pos++ = 1;
|
||||
*mbo_pos++ = hapd->mbo_assoc_disallow;
|
||||
}
|
||||
|
||||
pos += mbo_add_ie(pos, len, mbo, mbo_pos - mbo);
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
u8 hostapd_mbo_ie_len(struct hostapd_data *hapd)
|
||||
{
|
||||
if (!hapd->conf->mbo_enabled)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* MBO IE header (6) + Capability Indication attribute (3) +
|
||||
* Association Disallowed attribute (3) = 12
|
||||
*/
|
||||
return 6 + 3 + (hapd->mbo_assoc_disallow ? 3 : 0);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MBO */
|
||||
|
||||
|
||||
void ap_copy_sta_supp_op_classes(struct sta_info *sta,
|
||||
const u8 *supp_op_classes,
|
||||
size_t supp_op_classes_len)
|
||||
{
|
||||
if (!supp_op_classes)
|
||||
return;
|
||||
os_free(sta->supp_op_classes);
|
||||
sta->supp_op_classes = os_malloc(1 + supp_op_classes_len);
|
||||
if (!sta->supp_op_classes)
|
||||
return;
|
||||
|
||||
sta->supp_op_classes[0] = supp_op_classes_len;
|
||||
os_memcpy(sta->supp_op_classes + 1, supp_op_classes,
|
||||
supp_op_classes_len);
|
||||
}
|
||||
|
@ -17,9 +17,10 @@
|
||||
#include "sta_info.h"
|
||||
#include "beacon.h"
|
||||
#include "ieee802_11.h"
|
||||
#include "dfs.h"
|
||||
|
||||
|
||||
u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid)
|
||||
u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid, u32 nsts)
|
||||
{
|
||||
struct ieee80211_vht_capabilities *cap;
|
||||
struct hostapd_hw_modes *mode = hapd->iface->current_mode;
|
||||
@ -49,6 +50,18 @@ u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid)
|
||||
cap->vht_capabilities_info = host_to_le32(
|
||||
hapd->iface->conf->vht_capab);
|
||||
|
||||
if (nsts != 0) {
|
||||
u32 hapd_nsts;
|
||||
|
||||
hapd_nsts = le_to_host32(cap->vht_capabilities_info);
|
||||
hapd_nsts = (hapd_nsts >> VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
|
||||
cap->vht_capabilities_info &=
|
||||
~(host_to_le32(hapd_nsts <<
|
||||
VHT_CAP_BEAMFORMEE_STS_OFFSET));
|
||||
cap->vht_capabilities_info |=
|
||||
host_to_le32(nsts << VHT_CAP_BEAMFORMEE_STS_OFFSET);
|
||||
}
|
||||
|
||||
/* Supported MCS set comes from hw */
|
||||
os_memcpy(&cap->vht_supported_mcs_set, mode->vht_mcs_set, 8);
|
||||
|
||||
@ -80,6 +93,26 @@ u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
|
||||
hapd->iconf->vht_oper_centr_freq_seg1_idx;
|
||||
|
||||
oper->vht_op_info_chwidth = hapd->iconf->vht_oper_chwidth;
|
||||
if (hapd->iconf->vht_oper_chwidth == 2) {
|
||||
/*
|
||||
* Convert 160 MHz channel width to new style as interop
|
||||
* workaround.
|
||||
*/
|
||||
oper->vht_op_info_chwidth = 1;
|
||||
oper->vht_op_info_chan_center_freq_seg1_idx =
|
||||
oper->vht_op_info_chan_center_freq_seg0_idx;
|
||||
if (hapd->iconf->channel <
|
||||
hapd->iconf->vht_oper_centr_freq_seg0_idx)
|
||||
oper->vht_op_info_chan_center_freq_seg0_idx -= 8;
|
||||
else
|
||||
oper->vht_op_info_chan_center_freq_seg0_idx += 8;
|
||||
} else if (hapd->iconf->vht_oper_chwidth == 3) {
|
||||
/*
|
||||
* Convert 80+80 MHz channel width to new style as interop
|
||||
* workaround.
|
||||
*/
|
||||
oper->vht_op_info_chwidth = 1;
|
||||
}
|
||||
|
||||
/* VHT Basic MCS set comes from hw */
|
||||
/* Hard code 1 stream, MCS0-7 is a min Basic VHT MCS rates */
|
||||
@ -131,6 +164,171 @@ static int check_valid_vht_mcs(struct hostapd_hw_modes *mode,
|
||||
}
|
||||
|
||||
|
||||
u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid)
|
||||
{
|
||||
u8 bw, chan1, chan2 = 0;
|
||||
int freq1;
|
||||
|
||||
if (!hapd->cs_freq_params.channel ||
|
||||
!hapd->cs_freq_params.vht_enabled)
|
||||
return eid;
|
||||
|
||||
/* bandwidth: 0: 40, 1: 80, 2: 160, 3: 80+80 */
|
||||
switch (hapd->cs_freq_params.bandwidth) {
|
||||
case 40:
|
||||
bw = 0;
|
||||
break;
|
||||
case 80:
|
||||
/* check if it's 80+80 */
|
||||
if (!hapd->cs_freq_params.center_freq2)
|
||||
bw = 1;
|
||||
else
|
||||
bw = 3;
|
||||
break;
|
||||
case 160:
|
||||
bw = 2;
|
||||
break;
|
||||
default:
|
||||
/* not valid VHT bandwidth or not in CSA */
|
||||
return eid;
|
||||
}
|
||||
|
||||
freq1 = hapd->cs_freq_params.center_freq1 ?
|
||||
hapd->cs_freq_params.center_freq1 :
|
||||
hapd->cs_freq_params.freq;
|
||||
if (ieee80211_freq_to_chan(freq1, &chan1) !=
|
||||
HOSTAPD_MODE_IEEE80211A)
|
||||
return eid;
|
||||
|
||||
if (hapd->cs_freq_params.center_freq2 &&
|
||||
ieee80211_freq_to_chan(hapd->cs_freq_params.center_freq2,
|
||||
&chan2) != HOSTAPD_MODE_IEEE80211A)
|
||||
return eid;
|
||||
|
||||
*eid++ = WLAN_EID_VHT_CHANNEL_SWITCH_WRAPPER;
|
||||
*eid++ = 5; /* Length of Channel Switch Wrapper */
|
||||
*eid++ = WLAN_EID_VHT_WIDE_BW_CHSWITCH;
|
||||
*eid++ = 3; /* Length of Wide Bandwidth Channel Switch element */
|
||||
*eid++ = bw; /* New Channel Width */
|
||||
*eid++ = chan1; /* New Channel Center Frequency Segment 0 */
|
||||
*eid++ = chan2; /* New Channel Center Frequency Segment 1 */
|
||||
|
||||
return eid;
|
||||
}
|
||||
|
||||
|
||||
u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid)
|
||||
{
|
||||
struct hostapd_iface *iface = hapd->iface;
|
||||
struct hostapd_config *iconf = iface->conf;
|
||||
struct hostapd_hw_modes *mode = iface->current_mode;
|
||||
struct hostapd_channel_data *chan;
|
||||
int dfs, i;
|
||||
u8 channel, tx_pwr_count, local_pwr_constraint;
|
||||
int max_tx_power;
|
||||
u8 tx_pwr;
|
||||
|
||||
if (!mode)
|
||||
return eid;
|
||||
|
||||
if (ieee80211_freq_to_chan(iface->freq, &channel) == NUM_HOSTAPD_MODES)
|
||||
return eid;
|
||||
|
||||
for (i = 0; i < mode->num_channels; i++) {
|
||||
if (mode->channels[i].freq == iface->freq)
|
||||
break;
|
||||
}
|
||||
if (i == mode->num_channels)
|
||||
return eid;
|
||||
|
||||
switch (iface->conf->vht_oper_chwidth) {
|
||||
case VHT_CHANWIDTH_USE_HT:
|
||||
if (iconf->secondary_channel == 0) {
|
||||
/* Max Transmit Power count = 0 (20 MHz) */
|
||||
tx_pwr_count = 0;
|
||||
} else {
|
||||
/* Max Transmit Power count = 1 (20, 40 MHz) */
|
||||
tx_pwr_count = 1;
|
||||
}
|
||||
break;
|
||||
case VHT_CHANWIDTH_80MHZ:
|
||||
/* Max Transmit Power count = 2 (20, 40, and 80 MHz) */
|
||||
tx_pwr_count = 2;
|
||||
break;
|
||||
case VHT_CHANWIDTH_80P80MHZ:
|
||||
case VHT_CHANWIDTH_160MHZ:
|
||||
/* Max Transmit Power count = 3 (20, 40, 80, 160/80+80 MHz) */
|
||||
tx_pwr_count = 3;
|
||||
break;
|
||||
default:
|
||||
return eid;
|
||||
}
|
||||
|
||||
/*
|
||||
* Below local_pwr_constraint logic is referred from
|
||||
* hostapd_eid_pwr_constraint.
|
||||
*
|
||||
* Check if DFS is required by regulatory.
|
||||
*/
|
||||
dfs = hostapd_is_dfs_required(hapd->iface);
|
||||
if (dfs < 0)
|
||||
dfs = 0;
|
||||
|
||||
/*
|
||||
* In order to meet regulations when TPC is not implemented using
|
||||
* a transmit power that is below the legal maximum (including any
|
||||
* mitigation factor) should help. In this case, indicate 3 dB below
|
||||
* maximum allowed transmit power.
|
||||
*/
|
||||
if (hapd->iconf->local_pwr_constraint == -1)
|
||||
local_pwr_constraint = (dfs == 0) ? 0 : 3;
|
||||
else
|
||||
local_pwr_constraint = hapd->iconf->local_pwr_constraint;
|
||||
|
||||
/*
|
||||
* A STA that is not an AP shall use a transmit power less than or
|
||||
* equal to the local maximum transmit power level for the channel.
|
||||
* The local maximum transmit power can be calculated from the formula:
|
||||
* local max TX pwr = max TX pwr - local pwr constraint
|
||||
* Where max TX pwr is maximum transmit power level specified for
|
||||
* channel in Country element and local pwr constraint is specified
|
||||
* for channel in this Power Constraint element.
|
||||
*/
|
||||
chan = &mode->channels[i];
|
||||
max_tx_power = chan->max_tx_power - local_pwr_constraint;
|
||||
|
||||
/*
|
||||
* Local Maximum Transmit power is encoded as two's complement
|
||||
* with a 0.5 dB step.
|
||||
*/
|
||||
max_tx_power *= 2; /* in 0.5 dB steps */
|
||||
if (max_tx_power > 127) {
|
||||
/* 63.5 has special meaning of 63.5 dBm or higher */
|
||||
max_tx_power = 127;
|
||||
}
|
||||
if (max_tx_power < -128)
|
||||
max_tx_power = -128;
|
||||
if (max_tx_power < 0)
|
||||
tx_pwr = 0x80 + max_tx_power + 128;
|
||||
else
|
||||
tx_pwr = max_tx_power;
|
||||
|
||||
*eid++ = WLAN_EID_VHT_TRANSMIT_POWER_ENVELOPE;
|
||||
*eid++ = 2 + tx_pwr_count;
|
||||
|
||||
/*
|
||||
* Max Transmit Power count and
|
||||
* Max Transmit Power units = 0 (EIRP)
|
||||
*/
|
||||
*eid++ = tx_pwr_count;
|
||||
|
||||
for (i = 0; i <= tx_pwr_count; i++)
|
||||
*eid++ = tx_pwr;
|
||||
|
||||
return eid;
|
||||
}
|
||||
|
||||
|
||||
u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *vht_capab)
|
||||
{
|
||||
@ -212,7 +410,7 @@ u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid)
|
||||
WPA_PUT_BE32(pos, (OUI_BROADCOM << 8) | VENDOR_VHT_TYPE);
|
||||
pos += 4;
|
||||
*pos++ = VENDOR_VHT_SUBTYPE;
|
||||
pos = hostapd_eid_vht_capabilities(hapd, pos);
|
||||
pos = hostapd_eid_vht_capabilities(hapd, pos, 0);
|
||||
pos = hostapd_eid_vht_operation(hapd, pos);
|
||||
|
||||
return pos;
|
||||
|
@ -34,6 +34,9 @@
|
||||
#include "ieee802_1x.h"
|
||||
|
||||
|
||||
#ifdef CONFIG_HS20
|
||||
static void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx);
|
||||
#endif /* CONFIG_HS20 */
|
||||
static void ieee802_1x_finished(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, int success,
|
||||
int remediation);
|
||||
@ -219,7 +222,7 @@ static void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
MAC2STR(sta->addr));
|
||||
|
||||
#ifndef CONFIG_NO_VLAN
|
||||
if (sta->vlan_id > 0 && sta->vlan_id <= MAX_VLAN_ID) {
|
||||
if (sta->vlan_id > 0) {
|
||||
wpa_printf(MSG_ERROR, "Using WEP with vlans is not supported.");
|
||||
return;
|
||||
}
|
||||
@ -401,8 +404,17 @@ static int add_common_radius_sta_attr(struct hostapd_data *hapd,
|
||||
{
|
||||
char buf[128];
|
||||
|
||||
if (!hostapd_config_get_radius_attr(req_attr,
|
||||
RADIUS_ATTR_SERVICE_TYPE) &&
|
||||
!radius_msg_add_attr_int32(msg, RADIUS_ATTR_SERVICE_TYPE,
|
||||
RADIUS_SERVICE_TYPE_FRAMED)) {
|
||||
wpa_printf(MSG_ERROR, "Could not add Service-Type");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!hostapd_config_get_radius_attr(req_attr,
|
||||
RADIUS_ATTR_NAS_PORT) &&
|
||||
sta->aid > 0 &&
|
||||
!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
|
||||
wpa_printf(MSG_ERROR, "Could not add NAS-Port");
|
||||
return -1;
|
||||
@ -435,9 +447,9 @@ static int add_common_radius_sta_attr(struct hostapd_data *hapd,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sta->acct_session_id_hi || sta->acct_session_id_lo) {
|
||||
os_snprintf(buf, sizeof(buf), "%08X-%08X",
|
||||
sta->acct_session_id_hi, sta->acct_session_id_lo);
|
||||
if (sta->acct_session_id) {
|
||||
os_snprintf(buf, sizeof(buf), "%016llX",
|
||||
(unsigned long long) sta->acct_session_id);
|
||||
if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
|
||||
(u8 *) buf, os_strlen(buf))) {
|
||||
wpa_printf(MSG_ERROR, "Could not add Acct-Session-Id");
|
||||
@ -445,6 +457,21 @@ static int add_common_radius_sta_attr(struct hostapd_data *hapd,
|
||||
}
|
||||
}
|
||||
|
||||
if ((hapd->conf->wpa & 2) &&
|
||||
!hapd->conf->disable_pmksa_caching &&
|
||||
sta->eapol_sm && sta->eapol_sm->acct_multi_session_id) {
|
||||
os_snprintf(buf, sizeof(buf), "%016llX",
|
||||
(unsigned long long)
|
||||
sta->eapol_sm->acct_multi_session_id);
|
||||
if (!radius_msg_add_attr(
|
||||
msg, RADIUS_ATTR_ACCT_MULTI_SESSION_ID,
|
||||
(u8 *) buf, os_strlen(buf))) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"Could not add Acct-Multi-Session-Id");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
if (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) &&
|
||||
sta->wpa_sm &&
|
||||
@ -475,6 +502,7 @@ int add_common_radius_attr(struct hostapd_data *hapd,
|
||||
{
|
||||
char buf[128];
|
||||
struct hostapd_radius_attr *attr;
|
||||
int len;
|
||||
|
||||
if (!hostapd_config_get_radius_attr(req_attr,
|
||||
RADIUS_ATTR_NAS_IP_ADDRESS) &&
|
||||
@ -506,15 +534,15 @@ int add_common_radius_attr(struct hostapd_data *hapd,
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
|
||||
MAC2STR(hapd->own_addr),
|
||||
wpa_ssid_txt(hapd->conf->ssid.ssid,
|
||||
hapd->conf->ssid.ssid_len));
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
len = os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":",
|
||||
MAC2STR(hapd->own_addr));
|
||||
os_memcpy(&buf[len], hapd->conf->ssid.ssid,
|
||||
hapd->conf->ssid.ssid_len);
|
||||
len += hapd->conf->ssid.ssid_len;
|
||||
if (!hostapd_config_get_radius_attr(req_attr,
|
||||
RADIUS_ATTR_CALLED_STATION_ID) &&
|
||||
!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
|
||||
(u8 *) buf, os_strlen(buf))) {
|
||||
(u8 *) buf, len)) {
|
||||
wpa_printf(MSG_ERROR, "Could not add Called-Station-Id");
|
||||
return -1;
|
||||
}
|
||||
@ -583,7 +611,10 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
|
||||
return;
|
||||
}
|
||||
|
||||
radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta));
|
||||
if (radius_msg_make_authenticator(msg) < 0) {
|
||||
wpa_printf(MSG_INFO, "Could not make Request Authenticator");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (sm->identity &&
|
||||
!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME,
|
||||
@ -831,6 +862,29 @@ ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
}
|
||||
|
||||
|
||||
static void ieee802_1x_save_eapol(struct sta_info *sta, const u8 *buf,
|
||||
size_t len)
|
||||
{
|
||||
if (sta->pending_eapol_rx) {
|
||||
wpabuf_free(sta->pending_eapol_rx->buf);
|
||||
} else {
|
||||
sta->pending_eapol_rx =
|
||||
os_malloc(sizeof(*sta->pending_eapol_rx));
|
||||
if (!sta->pending_eapol_rx)
|
||||
return;
|
||||
}
|
||||
|
||||
sta->pending_eapol_rx->buf = wpabuf_alloc_copy(buf, len);
|
||||
if (!sta->pending_eapol_rx->buf) {
|
||||
os_free(sta->pending_eapol_rx);
|
||||
sta->pending_eapol_rx = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
os_get_reltime(&sta->pending_eapol_rx->rx_time);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ieee802_1x_receive - Process the EAPOL frames from the Supplicant
|
||||
* @hapd: hostapd BSS data
|
||||
@ -861,6 +915,13 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
|
||||
!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) {
|
||||
wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not "
|
||||
"associated/Pre-authenticating STA");
|
||||
|
||||
if (sta && (sta->flags & WLAN_STA_AUTH)) {
|
||||
wpa_printf(MSG_DEBUG, "Saving EAPOL frame from " MACSTR
|
||||
" for later use", MAC2STR(sta->addr));
|
||||
ieee802_1x_save_eapol(sta, buf, len);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1047,7 +1108,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
* Clear any possible EAPOL authenticator state to support
|
||||
* reassociation change from WPS to PSK.
|
||||
*/
|
||||
ieee802_1x_free_station(sta);
|
||||
ieee802_1x_free_station(hapd, sta);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1058,7 +1119,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
* Clear any possible EAPOL authenticator state to support
|
||||
* reassociation change from WPA-EAP to PSK.
|
||||
*/
|
||||
ieee802_1x_free_station(sta);
|
||||
ieee802_1x_free_station(hapd, sta);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1106,6 +1167,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
|
||||
sta->eapol_sm->authSuccess = TRUE;
|
||||
sta->eapol_sm->authFail = FALSE;
|
||||
sta->eapol_sm->portValid = TRUE;
|
||||
if (sta->eapol_sm->eap)
|
||||
eap_sm_notify_cached(sta->eapol_sm->eap);
|
||||
/* TODO: get vlan_id from R0KH using RRB message */
|
||||
@ -1128,7 +1190,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
sta->eapol_sm->authFail = FALSE;
|
||||
if (sta->eapol_sm->eap)
|
||||
eap_sm_notify_cached(sta->eapol_sm->eap);
|
||||
pmksa_cache_to_eapol_data(pmksa, sta->eapol_sm);
|
||||
pmksa_cache_to_eapol_data(hapd, pmksa, sta->eapol_sm);
|
||||
ap_sta_bind_vlan(hapd, sta);
|
||||
} else {
|
||||
if (reassoc) {
|
||||
@ -1144,10 +1206,20 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
}
|
||||
|
||||
|
||||
void ieee802_1x_free_station(struct sta_info *sta)
|
||||
void ieee802_1x_free_station(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
{
|
||||
struct eapol_state_machine *sm = sta->eapol_sm;
|
||||
|
||||
#ifdef CONFIG_HS20
|
||||
eloop_cancel_timeout(ieee802_1x_wnm_notif_send, hapd, sta);
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
if (sta->pending_eapol_rx) {
|
||||
wpabuf_free(sta->pending_eapol_rx->buf);
|
||||
os_free(sta->pending_eapol_rx);
|
||||
sta->pending_eapol_rx = NULL;
|
||||
}
|
||||
|
||||
if (sm == NULL)
|
||||
return;
|
||||
|
||||
@ -1156,10 +1228,8 @@ void ieee802_1x_free_station(struct sta_info *sta)
|
||||
#ifndef CONFIG_NO_RADIUS
|
||||
radius_msg_free(sm->last_recv_radius);
|
||||
radius_free_class(&sm->radius_class);
|
||||
wpabuf_free(sm->radius_cui);
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
|
||||
os_free(sm->identity);
|
||||
eapol_auth_free(sm);
|
||||
}
|
||||
|
||||
@ -1592,10 +1662,16 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
|
||||
struct hostapd_data *hapd = data;
|
||||
struct sta_info *sta;
|
||||
u32 session_timeout = 0, termination_action, acct_interim_interval;
|
||||
int session_timeout_set, vlan_id = 0;
|
||||
int session_timeout_set;
|
||||
struct eapol_state_machine *sm;
|
||||
int override_eapReq = 0;
|
||||
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
|
||||
struct vlan_description vlan_desc;
|
||||
#ifndef CONFIG_NO_VLAN
|
||||
int *untagged, *tagged, *notempty;
|
||||
#endif /* CONFIG_NO_VLAN */
|
||||
|
||||
os_memset(&vlan_desc, 0, sizeof(vlan_desc));
|
||||
|
||||
sm = ieee802_1x_search_radius_identifier(hapd, hdr->identifier);
|
||||
if (sm == NULL) {
|
||||
@ -1659,27 +1735,32 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
|
||||
|
||||
switch (hdr->code) {
|
||||
case RADIUS_CODE_ACCESS_ACCEPT:
|
||||
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
|
||||
vlan_id = 0;
|
||||
#ifndef CONFIG_NO_VLAN
|
||||
else
|
||||
vlan_id = radius_msg_get_vlanid(msg);
|
||||
if (vlan_id > 0 &&
|
||||
hostapd_vlan_id_valid(hapd->conf->vlan, vlan_id)) {
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_RADIUS,
|
||||
HOSTAPD_LEVEL_INFO,
|
||||
"VLAN ID %d", vlan_id);
|
||||
} else if (vlan_id > 0) {
|
||||
if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED) {
|
||||
notempty = &vlan_desc.notempty;
|
||||
untagged = &vlan_desc.untagged;
|
||||
tagged = vlan_desc.tagged;
|
||||
*notempty = !!radius_msg_get_vlanid(msg, untagged,
|
||||
MAX_NUM_TAGGED_VLAN,
|
||||
tagged);
|
||||
}
|
||||
|
||||
if (vlan_desc.notempty &&
|
||||
!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) {
|
||||
sta->eapol_sm->authFail = TRUE;
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_RADIUS,
|
||||
HOSTAPD_LEVEL_INFO,
|
||||
"Invalid VLAN ID %d received from RADIUS server",
|
||||
vlan_id);
|
||||
"Invalid VLAN %d%s received from RADIUS server",
|
||||
vlan_desc.untagged,
|
||||
vlan_desc.tagged[0] ? "+" : "");
|
||||
os_memset(&vlan_desc, 0, sizeof(vlan_desc));
|
||||
ap_sta_set_vlan(hapd, sta, &vlan_desc);
|
||||
break;
|
||||
} else if (hapd->conf->ssid.dynamic_vlan ==
|
||||
DYNAMIC_VLAN_REQUIRED) {
|
||||
}
|
||||
|
||||
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
|
||||
!vlan_desc.notempty) {
|
||||
sta->eapol_sm->authFail = TRUE;
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_IEEE8021X,
|
||||
@ -1690,7 +1771,18 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
|
||||
}
|
||||
#endif /* CONFIG_NO_VLAN */
|
||||
|
||||
sta->vlan_id = vlan_id;
|
||||
if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0)
|
||||
break;
|
||||
|
||||
#ifndef CONFIG_NO_VLAN
|
||||
if (sta->vlan_id > 0) {
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_RADIUS,
|
||||
HOSTAPD_LEVEL_INFO,
|
||||
"VLAN ID %d", sta->vlan_id);
|
||||
}
|
||||
#endif /* CONFIG_NO_VLAN */
|
||||
|
||||
if ((sta->flags & WLAN_STA_ASSOC) &&
|
||||
ap_sta_bind_vlan(hapd, sta) < 0)
|
||||
break;
|
||||
@ -1715,15 +1807,6 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
|
||||
ieee802_1x_check_hs20(hapd, sta, msg,
|
||||
session_timeout_set ?
|
||||
(int) session_timeout : -1);
|
||||
if (sm->eap_if->eapKeyAvailable && !sta->remediation &&
|
||||
!sta->hs20_deauth_requested &&
|
||||
wpa_auth_pmksa_add(sta->wpa_sm, sm->eapol_key_crypt,
|
||||
session_timeout_set ?
|
||||
(int) session_timeout : -1, sm) == 0) {
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"Added PMKSA cache entry");
|
||||
}
|
||||
break;
|
||||
case RADIUS_CODE_ACCESS_REJECT:
|
||||
sm->eap_if->aaaFail = TRUE;
|
||||
@ -2190,7 +2273,7 @@ void ieee802_1x_deinit(struct hostapd_data *hapd)
|
||||
{
|
||||
eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL);
|
||||
|
||||
if (hapd->driver != NULL &&
|
||||
if (hapd->driver && hapd->drv_priv &&
|
||||
(hapd->conf->ieee802_1x || hapd->conf->wpa))
|
||||
hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0);
|
||||
|
||||
@ -2495,12 +2578,12 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
/* TODO: dot1xAuthSessionOctetsTx */
|
||||
/* TODO: dot1xAuthSessionFramesRx */
|
||||
/* TODO: dot1xAuthSessionFramesTx */
|
||||
"dot1xAuthSessionId=%08X-%08X\n"
|
||||
"dot1xAuthSessionId=%016llX\n"
|
||||
"dot1xAuthSessionAuthenticMethod=%d\n"
|
||||
"dot1xAuthSessionTime=%u\n"
|
||||
"dot1xAuthSessionTerminateCause=999\n"
|
||||
"dot1xAuthSessionUserName=%s\n",
|
||||
sta->acct_session_id_hi, sta->acct_session_id_lo,
|
||||
(unsigned long long) sta->acct_session_id,
|
||||
(wpa_key_mgmt_wpa_ieee8021x(
|
||||
wpa_auth_sta_key_mgmt(sta->wpa_sm))) ?
|
||||
1 : 2,
|
||||
@ -2510,11 +2593,11 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
return len;
|
||||
len += ret;
|
||||
|
||||
if (sm->acct_multi_session_id_hi) {
|
||||
if (sm->acct_multi_session_id) {
|
||||
ret = os_snprintf(buf + len, buflen - len,
|
||||
"authMultiSessionId=%08X+%08X\n",
|
||||
sm->acct_multi_session_id_hi,
|
||||
sm->acct_multi_session_id_lo);
|
||||
"authMultiSessionId=%016llX\n",
|
||||
(unsigned long long)
|
||||
sm->acct_multi_session_id);
|
||||
if (os_snprintf_error(buflen - len, ret))
|
||||
return len;
|
||||
len += ret;
|
||||
@ -2535,6 +2618,34 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_HS20
|
||||
static void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
struct hostapd_data *hapd = eloop_ctx;
|
||||
struct sta_info *sta = timeout_ctx;
|
||||
|
||||
if (sta->remediation) {
|
||||
wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to "
|
||||
MACSTR " to indicate Subscription Remediation",
|
||||
MAC2STR(sta->addr));
|
||||
hs20_send_wnm_notification(hapd, sta->addr,
|
||||
sta->remediation_method,
|
||||
sta->remediation_url);
|
||||
os_free(sta->remediation_url);
|
||||
sta->remediation_url = NULL;
|
||||
}
|
||||
|
||||
if (sta->hs20_deauth_req) {
|
||||
wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to "
|
||||
MACSTR " to indicate imminent deauthentication",
|
||||
MAC2STR(sta->addr));
|
||||
hs20_send_wnm_notification_deauth_req(hapd, sta->addr,
|
||||
sta->hs20_deauth_req);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
|
||||
static void ieee802_1x_finished(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, int success,
|
||||
int remediation)
|
||||
@ -2554,26 +2665,12 @@ static void ieee802_1x_finished(struct hostapd_data *hapd,
|
||||
sta->remediation_method = 1; /* SOAP-XML SPP */
|
||||
}
|
||||
|
||||
if (success) {
|
||||
if (sta->remediation) {
|
||||
wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification "
|
||||
"to " MACSTR " to indicate Subscription "
|
||||
"Remediation",
|
||||
MAC2STR(sta->addr));
|
||||
hs20_send_wnm_notification(hapd, sta->addr,
|
||||
sta->remediation_method,
|
||||
sta->remediation_url);
|
||||
os_free(sta->remediation_url);
|
||||
sta->remediation_url = NULL;
|
||||
}
|
||||
|
||||
if (sta->hs20_deauth_req) {
|
||||
wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification "
|
||||
"to " MACSTR " to indicate imminent "
|
||||
"deauthentication", MAC2STR(sta->addr));
|
||||
hs20_send_wnm_notification_deauth_req(
|
||||
hapd, sta->addr, sta->hs20_deauth_req);
|
||||
}
|
||||
if (success && (sta->remediation || sta->hs20_deauth_req)) {
|
||||
wpa_printf(MSG_DEBUG, "HS 2.0: Schedule WNM-Notification to "
|
||||
MACSTR " in 100 ms", MAC2STR(sta->addr));
|
||||
eloop_cancel_timeout(ieee802_1x_wnm_notif_send, hapd, sta);
|
||||
eloop_register_timeout(0, 100000, ieee802_1x_wnm_notif_send,
|
||||
hapd, sta);
|
||||
}
|
||||
#endif /* CONFIG_HS20 */
|
||||
|
||||
@ -2584,7 +2681,7 @@ static void ieee802_1x_finished(struct hostapd_data *hapd,
|
||||
session_timeout = dot11RSNAConfigPMKLifetime;
|
||||
if (success && key && len >= PMK_LEN && !sta->remediation &&
|
||||
!sta->hs20_deauth_requested &&
|
||||
wpa_auth_pmksa_add(sta->wpa_sm, key, session_timeout,
|
||||
wpa_auth_pmksa_add(sta->wpa_sm, key, len, session_timeout,
|
||||
sta->eapol_sm) == 0) {
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
|
@ -21,7 +21,7 @@ struct radius_msg;
|
||||
void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
|
||||
size_t len);
|
||||
void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
void ieee802_1x_free_station(struct sta_info *sta);
|
||||
void ieee802_1x_free_station(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
|
||||
void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
|
||||
|
244
src/ap/mbo_ap.c
Normal file
244
src/ap/mbo_ap.c
Normal file
@ -0,0 +1,244 @@
|
||||
/*
|
||||
* hostapd - MBO
|
||||
* Copyright (c) 2016, 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 "common/ieee802_11_common.h"
|
||||
#include "hostapd.h"
|
||||
#include "sta_info.h"
|
||||
#include "mbo_ap.h"
|
||||
|
||||
|
||||
void mbo_ap_sta_free(struct sta_info *sta)
|
||||
{
|
||||
struct mbo_non_pref_chan_info *info, *prev;
|
||||
|
||||
info = sta->non_pref_chan;
|
||||
sta->non_pref_chan = NULL;
|
||||
while (info) {
|
||||
prev = info;
|
||||
info = info->next;
|
||||
os_free(prev);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void mbo_ap_parse_non_pref_chan(struct sta_info *sta,
|
||||
const u8 *buf, size_t len)
|
||||
{
|
||||
struct mbo_non_pref_chan_info *info, *tmp;
|
||||
char channels[200], *pos, *end;
|
||||
size_t num_chan, i;
|
||||
int ret;
|
||||
|
||||
if (len <= 3)
|
||||
return; /* Not enough room for any channels */
|
||||
|
||||
num_chan = len - 3;
|
||||
info = os_zalloc(sizeof(*info) + num_chan);
|
||||
if (!info)
|
||||
return;
|
||||
info->op_class = buf[0];
|
||||
info->pref = buf[len - 2];
|
||||
info->reason_code = buf[len - 1];
|
||||
info->num_channels = num_chan;
|
||||
buf++;
|
||||
os_memcpy(info->channels, buf, num_chan);
|
||||
if (!sta->non_pref_chan) {
|
||||
sta->non_pref_chan = info;
|
||||
} else {
|
||||
tmp = sta->non_pref_chan;
|
||||
while (tmp->next)
|
||||
tmp = tmp->next;
|
||||
tmp->next = info;
|
||||
}
|
||||
|
||||
pos = channels;
|
||||
end = pos + sizeof(channels);
|
||||
*pos = '\0';
|
||||
for (i = 0; i < num_chan; i++) {
|
||||
ret = os_snprintf(pos, end - pos, "%s%u",
|
||||
i == 0 ? "" : " ", buf[i]);
|
||||
if (os_snprintf_error(end - pos, ret)) {
|
||||
*pos = '\0';
|
||||
break;
|
||||
}
|
||||
pos += ret;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "MBO: STA " MACSTR
|
||||
" non-preferred channel list (op class %u, pref %u, reason code %u, channels %s)",
|
||||
MAC2STR(sta->addr), info->op_class, info->pref,
|
||||
info->reason_code, channels);
|
||||
}
|
||||
|
||||
|
||||
void mbo_ap_check_sta_assoc(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
struct ieee802_11_elems *elems)
|
||||
{
|
||||
const u8 *pos, *attr, *end;
|
||||
size_t len;
|
||||
|
||||
if (!hapd->conf->mbo_enabled || !elems->mbo)
|
||||
return;
|
||||
|
||||
pos = elems->mbo + 4;
|
||||
len = elems->mbo_len - 4;
|
||||
wpa_hexdump(MSG_DEBUG, "MBO: Association Request attributes", pos, len);
|
||||
|
||||
attr = get_ie(pos, len, MBO_ATTR_ID_CELL_DATA_CAPA);
|
||||
if (attr && attr[1] >= 1)
|
||||
sta->cell_capa = attr[2];
|
||||
|
||||
mbo_ap_sta_free(sta);
|
||||
end = pos + len;
|
||||
while (end - pos > 1) {
|
||||
u8 ie_len = pos[1];
|
||||
|
||||
if (2 + ie_len > end - pos)
|
||||
break;
|
||||
|
||||
if (pos[0] == MBO_ATTR_ID_NON_PREF_CHAN_REPORT)
|
||||
mbo_ap_parse_non_pref_chan(sta, pos + 2, ie_len);
|
||||
pos += 2 + pos[1];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int mbo_ap_get_info(struct sta_info *sta, char *buf, size_t buflen)
|
||||
{
|
||||
char *pos = buf, *end = buf + buflen;
|
||||
int ret;
|
||||
struct mbo_non_pref_chan_info *info;
|
||||
u8 i;
|
||||
unsigned int count = 0;
|
||||
|
||||
if (!sta->cell_capa)
|
||||
return 0;
|
||||
|
||||
ret = os_snprintf(pos, end - pos, "mbo_cell_capa=%u\n", sta->cell_capa);
|
||||
if (os_snprintf_error(end - pos, ret))
|
||||
return pos - buf;
|
||||
pos += ret;
|
||||
|
||||
for (info = sta->non_pref_chan; info; info = info->next) {
|
||||
char *pos2 = pos;
|
||||
|
||||
ret = os_snprintf(pos2, end - pos2,
|
||||
"non_pref_chan[%u]=%u:%u:%u:",
|
||||
count, info->op_class, info->pref,
|
||||
info->reason_code);
|
||||
count++;
|
||||
if (os_snprintf_error(end - pos2, ret))
|
||||
break;
|
||||
pos2 += ret;
|
||||
|
||||
for (i = 0; i < info->num_channels; i++) {
|
||||
ret = os_snprintf(pos2, end - pos2, "%u%s",
|
||||
info->channels[i],
|
||||
i + 1 < info->num_channels ?
|
||||
"," : "");
|
||||
if (os_snprintf_error(end - pos2, ret)) {
|
||||
pos2 = NULL;
|
||||
break;
|
||||
}
|
||||
pos2 += ret;
|
||||
}
|
||||
|
||||
if (!pos2)
|
||||
break;
|
||||
ret = os_snprintf(pos2, end - pos2, "\n");
|
||||
if (os_snprintf_error(end - pos2, ret))
|
||||
break;
|
||||
pos2 += ret;
|
||||
pos = pos2;
|
||||
}
|
||||
|
||||
return pos - buf;
|
||||
}
|
||||
|
||||
|
||||
static void mbo_ap_wnm_notif_req_cell_capa(struct sta_info *sta,
|
||||
const u8 *buf, size_t len)
|
||||
{
|
||||
if (len < 1)
|
||||
return;
|
||||
wpa_printf(MSG_DEBUG, "MBO: STA " MACSTR
|
||||
" updated cellular data capability: %u",
|
||||
MAC2STR(sta->addr), buf[0]);
|
||||
sta->cell_capa = buf[0];
|
||||
}
|
||||
|
||||
|
||||
static void mbo_ap_wnm_notif_req_elem(struct sta_info *sta, u8 type,
|
||||
const u8 *buf, size_t len,
|
||||
int *first_non_pref_chan)
|
||||
{
|
||||
switch (type) {
|
||||
case WFA_WNM_NOTIF_SUBELEM_NON_PREF_CHAN_REPORT:
|
||||
if (*first_non_pref_chan) {
|
||||
/*
|
||||
* Need to free the previously stored entries now to
|
||||
* allow the update to replace all entries.
|
||||
*/
|
||||
*first_non_pref_chan = 0;
|
||||
mbo_ap_sta_free(sta);
|
||||
}
|
||||
mbo_ap_parse_non_pref_chan(sta, buf, len);
|
||||
break;
|
||||
case WFA_WNM_NOTIF_SUBELEM_CELL_DATA_CAPA:
|
||||
mbo_ap_wnm_notif_req_cell_capa(sta, buf, len);
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"MBO: Ignore unknown WNM Notification WFA subelement %u",
|
||||
type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void mbo_ap_wnm_notification_req(struct hostapd_data *hapd, const u8 *addr,
|
||||
const u8 *buf, size_t len)
|
||||
{
|
||||
const u8 *pos, *end;
|
||||
u8 ie_len;
|
||||
struct sta_info *sta;
|
||||
int first_non_pref_chan = 1;
|
||||
|
||||
if (!hapd->conf->mbo_enabled)
|
||||
return;
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (!sta)
|
||||
return;
|
||||
|
||||
pos = buf;
|
||||
end = buf + len;
|
||||
|
||||
while (end - pos > 1) {
|
||||
ie_len = pos[1];
|
||||
|
||||
if (2 + ie_len > end - pos)
|
||||
break;
|
||||
|
||||
if (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
|
||||
ie_len >= 4 && WPA_GET_BE24(pos + 2) == OUI_WFA)
|
||||
mbo_ap_wnm_notif_req_elem(sta, pos[5],
|
||||
pos + 6, ie_len - 4,
|
||||
&first_non_pref_chan);
|
||||
else
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"MBO: Ignore unknown WNM Notification element %u (len=%u)",
|
||||
pos[0], pos[1]);
|
||||
|
||||
pos += 2 + pos[1];
|
||||
}
|
||||
}
|
51
src/ap/mbo_ap.h
Normal file
51
src/ap/mbo_ap.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* MBO related functions and structures
|
||||
* Copyright (c) 2016, Qualcomm Atheros, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef MBO_AP_H
|
||||
#define MBO_AP_H
|
||||
|
||||
struct hostapd_data;
|
||||
struct sta_info;
|
||||
struct ieee802_11_elems;
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
|
||||
void mbo_ap_check_sta_assoc(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
struct ieee802_11_elems *elems);
|
||||
int mbo_ap_get_info(struct sta_info *sta, char *buf, size_t buflen);
|
||||
void mbo_ap_wnm_notification_req(struct hostapd_data *hapd, const u8 *addr,
|
||||
const u8 *buf, size_t len);
|
||||
void mbo_ap_sta_free(struct sta_info *sta);
|
||||
|
||||
#else /* CONFIG_MBO */
|
||||
|
||||
static inline void mbo_ap_check_sta_assoc(struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
struct ieee802_11_elems *elems)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int mbo_ap_get_info(struct sta_info *sta, char *buf,
|
||||
size_t buflen)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void mbo_ap_wnm_notification_req(struct hostapd_data *hapd,
|
||||
const u8 *addr,
|
||||
const u8 *buf, size_t len)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void mbo_ap_sta_free(struct sta_info *sta)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MBO */
|
||||
|
||||
#endif /* MBO_AP_H */
|
@ -17,6 +17,7 @@
|
||||
#include "ap_drv_ops.h"
|
||||
#include "list.h"
|
||||
#include "x_snoop.h"
|
||||
#include "ndisc_snoop.h"
|
||||
|
||||
struct ip6addr {
|
||||
struct in6_addr addr;
|
||||
|
133
src/ap/neighbor_db.c
Normal file
133
src/ap/neighbor_db.c
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* hostapd / Neighboring APs DB
|
||||
* Copyright(c) 2013 - 2016 Intel Mobile Communications GmbH.
|
||||
* Copyright(c) 2011 - 2016 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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 "hostapd.h"
|
||||
#include "neighbor_db.h"
|
||||
|
||||
|
||||
struct hostapd_neighbor_entry *
|
||||
hostapd_neighbor_get(struct hostapd_data *hapd, const u8 *bssid,
|
||||
const struct wpa_ssid_value *ssid)
|
||||
{
|
||||
struct hostapd_neighbor_entry *nr;
|
||||
|
||||
dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
|
||||
list) {
|
||||
if (os_memcmp(bssid, nr->bssid, ETH_ALEN) == 0 &&
|
||||
(!ssid ||
|
||||
(ssid->ssid_len == nr->ssid.ssid_len &&
|
||||
os_memcmp(ssid->ssid, nr->ssid.ssid,
|
||||
ssid->ssid_len) == 0)))
|
||||
return nr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_neighbor_clear_entry(struct hostapd_neighbor_entry *nr)
|
||||
{
|
||||
wpabuf_free(nr->nr);
|
||||
nr->nr = NULL;
|
||||
wpabuf_free(nr->lci);
|
||||
nr->lci = NULL;
|
||||
wpabuf_free(nr->civic);
|
||||
nr->civic = NULL;
|
||||
os_memset(nr->bssid, 0, sizeof(nr->bssid));
|
||||
os_memset(&nr->ssid, 0, sizeof(nr->ssid));
|
||||
}
|
||||
|
||||
|
||||
static struct hostapd_neighbor_entry *
|
||||
hostapd_neighbor_add(struct hostapd_data *hapd)
|
||||
{
|
||||
struct hostapd_neighbor_entry *nr;
|
||||
|
||||
nr = os_zalloc(sizeof(struct hostapd_neighbor_entry));
|
||||
if (!nr)
|
||||
return NULL;
|
||||
|
||||
dl_list_add(&hapd->nr_db, &nr->list);
|
||||
|
||||
return nr;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_neighbor_set(struct hostapd_data *hapd, const u8 *bssid,
|
||||
const struct wpa_ssid_value *ssid,
|
||||
const struct wpabuf *nr, const struct wpabuf *lci,
|
||||
const struct wpabuf *civic)
|
||||
{
|
||||
struct hostapd_neighbor_entry *entry;
|
||||
|
||||
entry = hostapd_neighbor_get(hapd, bssid, ssid);
|
||||
if (!entry)
|
||||
entry = hostapd_neighbor_add(hapd);
|
||||
if (!entry)
|
||||
return -1;
|
||||
|
||||
hostapd_neighbor_clear_entry(entry);
|
||||
|
||||
os_memcpy(entry->bssid, bssid, ETH_ALEN);
|
||||
os_memcpy(&entry->ssid, ssid, sizeof(entry->ssid));
|
||||
|
||||
entry->nr = wpabuf_dup(nr);
|
||||
if (!entry->nr)
|
||||
goto fail;
|
||||
|
||||
if (lci) {
|
||||
entry->lci = wpabuf_dup(lci);
|
||||
if (!entry->lci || os_get_time(&entry->lci_date))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (civic) {
|
||||
entry->civic = wpabuf_dup(civic);
|
||||
if (!entry->civic)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
hostapd_neighbor_remove(hapd, bssid, ssid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid,
|
||||
const struct wpa_ssid_value *ssid)
|
||||
{
|
||||
struct hostapd_neighbor_entry *nr;
|
||||
|
||||
nr = hostapd_neighbor_get(hapd, bssid, ssid);
|
||||
if (!nr)
|
||||
return -1;
|
||||
|
||||
hostapd_neighbor_clear_entry(nr);
|
||||
dl_list_del(&nr->list);
|
||||
os_free(nr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void hostpad_free_neighbor_db(struct hostapd_data *hapd)
|
||||
{
|
||||
struct hostapd_neighbor_entry *nr, *prev;
|
||||
|
||||
dl_list_for_each_safe(nr, prev, &hapd->nr_db,
|
||||
struct hostapd_neighbor_entry, list) {
|
||||
hostapd_neighbor_clear_entry(nr);
|
||||
dl_list_del(&nr->list);
|
||||
os_free(nr);
|
||||
}
|
||||
}
|
24
src/ap/neighbor_db.h
Normal file
24
src/ap/neighbor_db.h
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* hostapd / Neighboring APs DB
|
||||
* Copyright(c) 2013 - 2016 Intel Mobile Communications GmbH.
|
||||
* Copyright(c) 2011 - 2016 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef NEIGHBOR_DB_H
|
||||
#define NEIGHBOR_DB_H
|
||||
|
||||
struct hostapd_neighbor_entry *
|
||||
hostapd_neighbor_get(struct hostapd_data *hapd, const u8 *bssid,
|
||||
const struct wpa_ssid_value *ssid);
|
||||
int hostapd_neighbor_set(struct hostapd_data *hapd, const u8 *bssid,
|
||||
const struct wpa_ssid_value *ssid,
|
||||
const struct wpabuf *nr, const struct wpabuf *lci,
|
||||
const struct wpabuf *civic);
|
||||
int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid,
|
||||
const struct wpa_ssid_value *ssid);
|
||||
void hostpad_free_neighbor_db(struct hostapd_data *hapd);
|
||||
|
||||
#endif /* NEIGHBOR_DB_H */
|
@ -38,6 +38,7 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa);
|
||||
|
||||
static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
|
||||
{
|
||||
os_free(entry->vlan_desc);
|
||||
os_free(entry->identity);
|
||||
wpabuf_free(entry->cui);
|
||||
#ifndef CONFIG_NO_RADIUS
|
||||
@ -91,6 +92,20 @@ void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* pmksa_cache_auth_flush - Flush all PMKSA cache entries
|
||||
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
|
||||
*/
|
||||
void pmksa_cache_auth_flush(struct rsn_pmksa_cache *pmksa)
|
||||
{
|
||||
while (pmksa->pmksa) {
|
||||
wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry for "
|
||||
MACSTR, MAC2STR(pmksa->pmksa->spa));
|
||||
pmksa_cache_free_entry(pmksa, pmksa->pmksa);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
struct rsn_pmksa_cache *pmksa = eloop_ctx;
|
||||
@ -126,6 +141,8 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
|
||||
static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry,
|
||||
struct eapol_state_machine *eapol)
|
||||
{
|
||||
struct vlan_description *vlan_desc;
|
||||
|
||||
if (eapol == NULL)
|
||||
return;
|
||||
|
||||
@ -146,14 +163,22 @@ static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry,
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
|
||||
entry->eap_type_authsrv = eapol->eap_type_authsrv;
|
||||
entry->vlan_id = ((struct sta_info *) eapol->sta)->vlan_id;
|
||||
|
||||
entry->acct_multi_session_id_hi = eapol->acct_multi_session_id_hi;
|
||||
entry->acct_multi_session_id_lo = eapol->acct_multi_session_id_lo;
|
||||
vlan_desc = ((struct sta_info *) eapol->sta)->vlan_desc;
|
||||
if (vlan_desc && vlan_desc->notempty) {
|
||||
entry->vlan_desc = os_zalloc(sizeof(struct vlan_description));
|
||||
if (entry->vlan_desc)
|
||||
*entry->vlan_desc = *vlan_desc;
|
||||
} else {
|
||||
entry->vlan_desc = NULL;
|
||||
}
|
||||
|
||||
entry->acct_multi_session_id = eapol->acct_multi_session_id;
|
||||
}
|
||||
|
||||
|
||||
void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
|
||||
void pmksa_cache_to_eapol_data(struct hostapd_data *hapd,
|
||||
struct rsn_pmksa_cache_entry *entry,
|
||||
struct eapol_state_machine *eapol)
|
||||
{
|
||||
if (entry == NULL || eapol == NULL)
|
||||
@ -186,10 +211,11 @@ void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
|
||||
}
|
||||
|
||||
eapol->eap_type_authsrv = entry->eap_type_authsrv;
|
||||
((struct sta_info *) eapol->sta)->vlan_id = entry->vlan_id;
|
||||
#ifndef CONFIG_NO_VLAN
|
||||
ap_sta_set_vlan(hapd, eapol->sta, entry->vlan_desc);
|
||||
#endif /* CONFIG_NO_VLAN */
|
||||
|
||||
eapol->acct_multi_session_id_hi = entry->acct_multi_session_id_hi;
|
||||
eapol->acct_multi_session_id_lo = entry->acct_multi_session_id_lo;
|
||||
eapol->acct_multi_session_id = entry->acct_multi_session_id;
|
||||
}
|
||||
|
||||
|
||||
@ -234,6 +260,7 @@ static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
|
||||
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
|
||||
* @pmk: The new pairwise master key
|
||||
* @pmk_len: PMK length in bytes, usually PMK_LEN (32)
|
||||
* @pmkid: Calculated PMKID
|
||||
* @kck: Key confirmation key or %NULL if not yet derived
|
||||
* @kck_len: KCK length in bytes
|
||||
* @aa: Authenticator address
|
||||
@ -250,7 +277,7 @@ static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
|
||||
*/
|
||||
struct rsn_pmksa_cache_entry *
|
||||
pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
|
||||
const u8 *pmk, size_t pmk_len,
|
||||
const u8 *pmk, size_t pmk_len, const u8 *pmkid,
|
||||
const u8 *kck, size_t kck_len,
|
||||
const u8 *aa, const u8 *spa, int session_timeout,
|
||||
struct eapol_state_machine *eapol, int akmp)
|
||||
@ -258,7 +285,7 @@ pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
|
||||
struct rsn_pmksa_cache_entry *entry, *pos;
|
||||
struct os_reltime now;
|
||||
|
||||
if (pmk_len > PMK_LEN)
|
||||
if (pmk_len > PMK_LEN_MAX)
|
||||
return NULL;
|
||||
|
||||
if (wpa_key_mgmt_suite_b(akmp) && !kck)
|
||||
@ -269,7 +296,9 @@ pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
|
||||
return NULL;
|
||||
os_memcpy(entry->pmk, pmk, pmk_len);
|
||||
entry->pmk_len = pmk_len;
|
||||
if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
|
||||
if (pmkid)
|
||||
os_memcpy(entry->pmkid, pmkid, PMKID_LEN);
|
||||
else if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
|
||||
rsn_pmkid_suite_b_192(kck, kck_len, aa, spa, entry->pmkid);
|
||||
else if (wpa_key_mgmt_suite_b(akmp))
|
||||
rsn_pmkid_suite_b(kck, kck_len, aa, spa, entry->pmkid);
|
||||
@ -337,7 +366,13 @@ pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa,
|
||||
radius_copy_class(&entry->radius_class, &old_entry->radius_class);
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
entry->eap_type_authsrv = old_entry->eap_type_authsrv;
|
||||
entry->vlan_id = old_entry->vlan_id;
|
||||
if (old_entry->vlan_desc) {
|
||||
entry->vlan_desc = os_zalloc(sizeof(struct vlan_description));
|
||||
if (entry->vlan_desc)
|
||||
*entry->vlan_desc = *old_entry->vlan_desc;
|
||||
} else {
|
||||
entry->vlan_desc = NULL;
|
||||
}
|
||||
entry->opportunistic = 1;
|
||||
|
||||
pmksa_cache_link_entry(pmksa, entry);
|
||||
@ -471,12 +506,11 @@ static int das_attr_match(struct rsn_pmksa_cache_entry *entry,
|
||||
if (attr->acct_multi_session_id) {
|
||||
char buf[20];
|
||||
|
||||
if (attr->acct_multi_session_id_len != 17)
|
||||
if (attr->acct_multi_session_id_len != 16)
|
||||
return 0;
|
||||
os_snprintf(buf, sizeof(buf), "%08X+%08X",
|
||||
entry->acct_multi_session_id_hi,
|
||||
entry->acct_multi_session_id_lo);
|
||||
if (os_memcmp(attr->acct_multi_session_id, buf, 17) != 0)
|
||||
os_snprintf(buf, sizeof(buf), "%016llX",
|
||||
(unsigned long long) entry->acct_multi_session_id);
|
||||
if (os_memcmp(attr->acct_multi_session_id, buf, 16) != 0)
|
||||
return 0;
|
||||
match++;
|
||||
}
|
||||
@ -526,3 +560,48 @@ int pmksa_cache_auth_radius_das_disconnect(struct rsn_pmksa_cache *pmksa,
|
||||
|
||||
return found ? 0 : -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* pmksa_cache_auth_list - Dump text list of entries in PMKSA cache
|
||||
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
|
||||
* @buf: Buffer for the list
|
||||
* @len: Length of the buffer
|
||||
* Returns: Number of bytes written to buffer
|
||||
*
|
||||
* This function is used to generate a text format representation of the
|
||||
* current PMKSA cache contents for the ctrl_iface PMKSA command.
|
||||
*/
|
||||
int pmksa_cache_auth_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len)
|
||||
{
|
||||
int i, ret;
|
||||
char *pos = buf;
|
||||
struct rsn_pmksa_cache_entry *entry;
|
||||
struct os_reltime now;
|
||||
|
||||
os_get_reltime(&now);
|
||||
ret = os_snprintf(pos, buf + len - pos,
|
||||
"Index / SPA / PMKID / expiration (in seconds) / opportunistic\n");
|
||||
if (os_snprintf_error(buf + len - pos, ret))
|
||||
return pos - buf;
|
||||
pos += ret;
|
||||
i = 0;
|
||||
entry = pmksa->pmksa;
|
||||
while (entry) {
|
||||
ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ",
|
||||
i, MAC2STR(entry->spa));
|
||||
if (os_snprintf_error(buf + len - pos, ret))
|
||||
return pos - buf;
|
||||
pos += ret;
|
||||
pos += wpa_snprintf_hex(pos, buf + len - pos, entry->pmkid,
|
||||
PMKID_LEN);
|
||||
ret = os_snprintf(pos, buf + len - pos, " %d %d\n",
|
||||
(int) (entry->expiration - now.sec),
|
||||
entry->opportunistic);
|
||||
if (os_snprintf_error(buf + len - pos, ret))
|
||||
return pos - buf;
|
||||
pos += ret;
|
||||
entry = entry->next;
|
||||
}
|
||||
return pos - buf;
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
struct rsn_pmksa_cache_entry {
|
||||
struct rsn_pmksa_cache_entry *next, *hnext;
|
||||
u8 pmkid[PMKID_LEN];
|
||||
u8 pmk[PMK_LEN];
|
||||
u8 pmk[PMK_LEN_MAX];
|
||||
size_t pmk_len;
|
||||
os_time_t expiration;
|
||||
int akmp; /* WPA_KEY_MGMT_* */
|
||||
@ -28,11 +28,10 @@ struct rsn_pmksa_cache_entry {
|
||||
struct wpabuf *cui;
|
||||
struct radius_class_data radius_class;
|
||||
u8 eap_type_authsrv;
|
||||
int vlan_id;
|
||||
struct vlan_description *vlan_desc;
|
||||
int opportunistic;
|
||||
|
||||
u32 acct_multi_session_id_hi;
|
||||
u32 acct_multi_session_id_lo;
|
||||
u64 acct_multi_session_id;
|
||||
};
|
||||
|
||||
struct rsn_pmksa_cache;
|
||||
@ -49,7 +48,7 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
|
||||
const u8 *pmkid);
|
||||
struct rsn_pmksa_cache_entry *
|
||||
pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
|
||||
const u8 *pmk, size_t pmk_len,
|
||||
const u8 *pmk, size_t pmk_len, const u8 *pmkid,
|
||||
const u8 *kck, size_t kck_len,
|
||||
const u8 *aa, const u8 *spa, int session_timeout,
|
||||
struct eapol_state_machine *eapol, int akmp);
|
||||
@ -57,11 +56,14 @@ struct rsn_pmksa_cache_entry *
|
||||
pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa,
|
||||
const struct rsn_pmksa_cache_entry *old_entry,
|
||||
const u8 *aa, const u8 *pmkid);
|
||||
void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
|
||||
void pmksa_cache_to_eapol_data(struct hostapd_data *hapd,
|
||||
struct rsn_pmksa_cache_entry *entry,
|
||||
struct eapol_state_machine *eapol);
|
||||
void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
|
||||
struct rsn_pmksa_cache_entry *entry);
|
||||
int pmksa_cache_auth_radius_das_disconnect(struct rsn_pmksa_cache *pmksa,
|
||||
struct radius_das_attrs *attr);
|
||||
int pmksa_cache_auth_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len);
|
||||
void pmksa_cache_auth_flush(struct rsn_pmksa_cache *pmksa);
|
||||
|
||||
#endif /* PMKSA_CACHE_H */
|
||||
|
544
src/ap/rrm.c
Normal file
544
src/ap/rrm.c
Normal file
@ -0,0 +1,544 @@
|
||||
/*
|
||||
* hostapd / Radio Measurement (RRM)
|
||||
* Copyright(c) 2013 - 2016 Intel Mobile Communications GmbH.
|
||||
* Copyright(c) 2011 - 2016 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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 "hostapd.h"
|
||||
#include "ap_drv_ops.h"
|
||||
#include "sta_info.h"
|
||||
#include "eloop.h"
|
||||
#include "neighbor_db.h"
|
||||
#include "rrm.h"
|
||||
|
||||
#define HOSTAPD_RRM_REQUEST_TIMEOUT 5
|
||||
|
||||
|
||||
static void hostapd_lci_rep_timeout_handler(void *eloop_data, void *user_ctx)
|
||||
{
|
||||
struct hostapd_data *hapd = eloop_data;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "RRM: LCI request (token %u) timed out",
|
||||
hapd->lci_req_token);
|
||||
hapd->lci_req_active = 0;
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_handle_lci_report(struct hostapd_data *hapd, u8 token,
|
||||
const u8 *pos, size_t len)
|
||||
{
|
||||
if (!hapd->lci_req_active || hapd->lci_req_token != token) {
|
||||
wpa_printf(MSG_DEBUG, "Unexpected LCI report, token %u", token);
|
||||
return;
|
||||
}
|
||||
|
||||
hapd->lci_req_active = 0;
|
||||
eloop_cancel_timeout(hostapd_lci_rep_timeout_handler, hapd, NULL);
|
||||
wpa_printf(MSG_DEBUG, "LCI report token %u len %zu", token, len);
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_range_rep_timeout_handler(void *eloop_data, void *user_ctx)
|
||||
{
|
||||
struct hostapd_data *hapd = eloop_data;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "RRM: Range request (token %u) timed out",
|
||||
hapd->range_req_token);
|
||||
hapd->range_req_active = 0;
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_handle_range_report(struct hostapd_data *hapd, u8 token,
|
||||
const u8 *pos, size_t len)
|
||||
{
|
||||
if (!hapd->range_req_active || hapd->range_req_token != token) {
|
||||
wpa_printf(MSG_DEBUG, "Unexpected range report, token %u",
|
||||
token);
|
||||
return;
|
||||
}
|
||||
|
||||
hapd->range_req_active = 0;
|
||||
eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd, NULL);
|
||||
wpa_printf(MSG_DEBUG, "Range report token %u len %zu", token, len);
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_handle_radio_msmt_report(struct hostapd_data *hapd,
|
||||
const u8 *buf, size_t len)
|
||||
{
|
||||
const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf;
|
||||
const u8 *pos, *ie, *end;
|
||||
u8 token;
|
||||
|
||||
end = buf + len;
|
||||
token = mgmt->u.action.u.rrm.dialog_token;
|
||||
pos = mgmt->u.action.u.rrm.variable;
|
||||
|
||||
while ((ie = get_ie(pos, end - pos, WLAN_EID_MEASURE_REPORT))) {
|
||||
if (ie[1] < 5) {
|
||||
wpa_printf(MSG_DEBUG, "Bad Measurement Report element");
|
||||
break;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Measurement report type %u", ie[4]);
|
||||
|
||||
switch (ie[4]) {
|
||||
case MEASURE_TYPE_LCI:
|
||||
hostapd_handle_lci_report(hapd, token, ie + 2, ie[1]);
|
||||
break;
|
||||
case MEASURE_TYPE_FTM_RANGE:
|
||||
hostapd_handle_range_report(hapd, token, ie + 2, ie[1]);
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Measurement report type %u is not supported",
|
||||
ie[4]);
|
||||
break;
|
||||
}
|
||||
|
||||
pos = ie + ie[1] + 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static u16 hostapd_parse_location_lci_req_age(const u8 *buf, size_t len)
|
||||
{
|
||||
const u8 *subelem;
|
||||
|
||||
/* Range Request element + Location Subject + Maximum Age subelement */
|
||||
if (len < 3 + 1 + 4)
|
||||
return 0;
|
||||
|
||||
/* Subelements are arranged as IEs */
|
||||
subelem = get_ie(buf + 4, len - 4, LCI_REQ_SUBELEM_MAX_AGE);
|
||||
if (subelem && subelem[1] == 2)
|
||||
return *(u16 *) (subelem + 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int hostapd_check_lci_age(struct hostapd_neighbor_entry *nr, u16 max_age)
|
||||
{
|
||||
struct os_time curr, diff;
|
||||
unsigned long diff_l;
|
||||
|
||||
if (!max_age)
|
||||
return 0;
|
||||
|
||||
if (max_age == 0xffff)
|
||||
return 1;
|
||||
|
||||
if (os_get_time(&curr))
|
||||
return 0;
|
||||
|
||||
os_time_sub(&curr, &nr->lci_date, &diff);
|
||||
|
||||
/* avoid overflow */
|
||||
if (diff.sec > 0xffff)
|
||||
return 0;
|
||||
|
||||
/* LCI age is calculated in 10th of a second units. */
|
||||
diff_l = diff.sec * 10 + diff.usec / 100000;
|
||||
|
||||
return max_age > diff_l;
|
||||
}
|
||||
|
||||
|
||||
static size_t hostapd_neighbor_report_len(struct wpabuf *buf,
|
||||
struct hostapd_neighbor_entry *nr,
|
||||
int send_lci, int send_civic)
|
||||
{
|
||||
size_t len = 2 + wpabuf_len(nr->nr);
|
||||
|
||||
if (send_lci && nr->lci)
|
||||
len += 2 + wpabuf_len(nr->lci);
|
||||
|
||||
if (send_civic && nr->civic)
|
||||
len += 2 + wpabuf_len(nr->civic);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_send_nei_report_resp(struct hostapd_data *hapd,
|
||||
const u8 *addr, u8 dialog_token,
|
||||
struct wpa_ssid_value *ssid, u8 lci,
|
||||
u8 civic, u16 lci_max_age)
|
||||
{
|
||||
struct hostapd_neighbor_entry *nr;
|
||||
struct wpabuf *buf;
|
||||
u8 *msmt_token;
|
||||
|
||||
/*
|
||||
* The number and length of the Neighbor Report elements in a Neighbor
|
||||
* Report frame is limited by the maximum allowed MMPDU size; + 3 bytes
|
||||
* of RRM header.
|
||||
*/
|
||||
buf = wpabuf_alloc(3 + IEEE80211_MAX_MMPDU_SIZE);
|
||||
if (!buf)
|
||||
return;
|
||||
|
||||
wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
|
||||
wpabuf_put_u8(buf, WLAN_RRM_NEIGHBOR_REPORT_RESPONSE);
|
||||
wpabuf_put_u8(buf, dialog_token);
|
||||
|
||||
dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
|
||||
list) {
|
||||
int send_lci;
|
||||
size_t len;
|
||||
|
||||
if (ssid->ssid_len != nr->ssid.ssid_len ||
|
||||
os_memcmp(ssid->ssid, nr->ssid.ssid, ssid->ssid_len) != 0)
|
||||
continue;
|
||||
|
||||
send_lci = (lci != 0) && hostapd_check_lci_age(nr, lci_max_age);
|
||||
len = hostapd_neighbor_report_len(buf, nr, send_lci, civic);
|
||||
|
||||
if (len - 2 > 0xff) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"NR entry for " MACSTR " exceeds 0xFF bytes",
|
||||
MAC2STR(nr->bssid));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (len > wpabuf_tailroom(buf))
|
||||
break;
|
||||
|
||||
wpabuf_put_u8(buf, WLAN_EID_NEIGHBOR_REPORT);
|
||||
wpabuf_put_u8(buf, len - 2);
|
||||
wpabuf_put_buf(buf, nr->nr);
|
||||
|
||||
if (send_lci && nr->lci) {
|
||||
wpabuf_put_u8(buf, WLAN_EID_MEASURE_REPORT);
|
||||
wpabuf_put_u8(buf, wpabuf_len(nr->lci));
|
||||
/*
|
||||
* Override measurement token - the first byte of the
|
||||
* Measurement Report element.
|
||||
*/
|
||||
msmt_token = wpabuf_put(buf, 0);
|
||||
wpabuf_put_buf(buf, nr->lci);
|
||||
*msmt_token = lci;
|
||||
}
|
||||
|
||||
if (civic && nr->civic) {
|
||||
wpabuf_put_u8(buf, WLAN_EID_MEASURE_REPORT);
|
||||
wpabuf_put_u8(buf, wpabuf_len(nr->civic));
|
||||
/*
|
||||
* Override measurement token - the first byte of the
|
||||
* Measurement Report element.
|
||||
*/
|
||||
msmt_token = wpabuf_put(buf, 0);
|
||||
wpabuf_put_buf(buf, nr->civic);
|
||||
*msmt_token = civic;
|
||||
}
|
||||
}
|
||||
|
||||
hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
|
||||
wpabuf_head(buf), wpabuf_len(buf));
|
||||
wpabuf_free(buf);
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_handle_nei_report_req(struct hostapd_data *hapd,
|
||||
const u8 *buf, size_t len)
|
||||
{
|
||||
const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf;
|
||||
const u8 *pos, *ie, *end;
|
||||
struct wpa_ssid_value ssid = {
|
||||
.ssid_len = 0
|
||||
};
|
||||
u8 token;
|
||||
u8 lci = 0, civic = 0; /* Measurement tokens */
|
||||
u16 lci_max_age = 0;
|
||||
|
||||
if (!(hapd->conf->radio_measurements[0] &
|
||||
WLAN_RRM_CAPS_NEIGHBOR_REPORT))
|
||||
return;
|
||||
|
||||
end = buf + len;
|
||||
|
||||
token = mgmt->u.action.u.rrm.dialog_token;
|
||||
pos = mgmt->u.action.u.rrm.variable;
|
||||
len = end - pos;
|
||||
|
||||
ie = get_ie(pos, len, WLAN_EID_SSID);
|
||||
if (ie && ie[1] && ie[1] <= SSID_MAX_LEN) {
|
||||
ssid.ssid_len = ie[1];
|
||||
os_memcpy(ssid.ssid, ie + 2, ssid.ssid_len);
|
||||
} else {
|
||||
ssid.ssid_len = hapd->conf->ssid.ssid_len;
|
||||
os_memcpy(ssid.ssid, hapd->conf->ssid.ssid, ssid.ssid_len);
|
||||
}
|
||||
|
||||
while ((ie = get_ie(pos, len, WLAN_EID_MEASURE_REQUEST))) {
|
||||
if (ie[1] < 3)
|
||||
break;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Neighbor report request, measure type %u",
|
||||
ie[4]);
|
||||
|
||||
switch (ie[4]) { /* Measurement Type */
|
||||
case MEASURE_TYPE_LCI:
|
||||
lci = ie[2]; /* Measurement Token */
|
||||
lci_max_age = hostapd_parse_location_lci_req_age(ie + 2,
|
||||
ie[1]);
|
||||
break;
|
||||
case MEASURE_TYPE_LOCATION_CIVIC:
|
||||
civic = ie[2]; /* Measurement token */
|
||||
break;
|
||||
}
|
||||
|
||||
pos = ie + ie[1] + 2;
|
||||
len = end - pos;
|
||||
}
|
||||
|
||||
hostapd_send_nei_report_resp(hapd, mgmt->sa, token, &ssid, lci, civic,
|
||||
lci_max_age);
|
||||
}
|
||||
|
||||
|
||||
void hostapd_handle_radio_measurement(struct hostapd_data *hapd,
|
||||
const u8 *buf, size_t len)
|
||||
{
|
||||
const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf;
|
||||
|
||||
/*
|
||||
* Check for enough bytes: header + (1B)Category + (1B)Action +
|
||||
* (1B)Dialog Token.
|
||||
*/
|
||||
if (len < IEEE80211_HDRLEN + 3)
|
||||
return;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Radio measurement frame, action %u from " MACSTR,
|
||||
mgmt->u.action.u.rrm.action, MAC2STR(mgmt->sa));
|
||||
|
||||
switch (mgmt->u.action.u.rrm.action) {
|
||||
case WLAN_RRM_RADIO_MEASUREMENT_REPORT:
|
||||
hostapd_handle_radio_msmt_report(hapd, buf, len);
|
||||
break;
|
||||
case WLAN_RRM_NEIGHBOR_REPORT_REQUEST:
|
||||
hostapd_handle_nei_report_req(hapd, buf, len);
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "RRM action %u is not supported",
|
||||
mgmt->u.action.u.rrm.action);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int hostapd_send_lci_req(struct hostapd_data *hapd, const u8 *addr)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
struct sta_info *sta = ap_get_sta(hapd, addr);
|
||||
int ret;
|
||||
|
||||
if (!sta) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"Request LCI: Destination address is not in station list");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(sta->flags & WLAN_STA_AUTHORIZED)) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"Request LCI: Destination address is not connected");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(sta->rrm_enabled_capa[1] & WLAN_RRM_CAPS_LCI_MEASUREMENT)) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"Request LCI: Station does not support LCI in RRM");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hapd->lci_req_active) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Request LCI: LCI request is already in process, overriding");
|
||||
hapd->lci_req_active = 0;
|
||||
eloop_cancel_timeout(hostapd_lci_rep_timeout_handler, hapd,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/* Measurement request (5) + Measurement element with LCI (10) */
|
||||
buf = wpabuf_alloc(5 + 10);
|
||||
if (!buf)
|
||||
return -1;
|
||||
|
||||
hapd->lci_req_token++;
|
||||
/* For wraparounds - the token must be nonzero */
|
||||
if (!hapd->lci_req_token)
|
||||
hapd->lci_req_token++;
|
||||
|
||||
wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
|
||||
wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REQUEST);
|
||||
wpabuf_put_u8(buf, hapd->lci_req_token);
|
||||
wpabuf_put_le16(buf, 0); /* Number of repetitions */
|
||||
|
||||
wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
|
||||
wpabuf_put_u8(buf, 3 + 1 + 4);
|
||||
|
||||
wpabuf_put_u8(buf, 1); /* Measurement Token */
|
||||
/*
|
||||
* Parallel and Enable bits are 0, Duration, Request, and Report are
|
||||
* reserved.
|
||||
*/
|
||||
wpabuf_put_u8(buf, 0);
|
||||
wpabuf_put_u8(buf, MEASURE_TYPE_LCI);
|
||||
|
||||
wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE);
|
||||
|
||||
wpabuf_put_u8(buf, LCI_REQ_SUBELEM_MAX_AGE);
|
||||
wpabuf_put_u8(buf, 2);
|
||||
wpabuf_put_le16(buf, 0xffff);
|
||||
|
||||
ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
|
||||
wpabuf_head(buf), wpabuf_len(buf));
|
||||
wpabuf_free(buf);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
hapd->lci_req_active = 1;
|
||||
|
||||
eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0,
|
||||
hostapd_lci_rep_timeout_handler, hapd, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int hostapd_send_range_req(struct hostapd_data *hapd, const u8 *addr,
|
||||
u16 random_interval, u8 min_ap,
|
||||
const u8 *responders, unsigned int n_responders)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
struct sta_info *sta;
|
||||
u8 *len;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Request range: dest addr " MACSTR
|
||||
" rand interval %u min AP %u n_responders %u", MAC2STR(addr),
|
||||
random_interval, min_ap, n_responders);
|
||||
|
||||
if (min_ap == 0 || min_ap > n_responders) {
|
||||
wpa_printf(MSG_INFO, "Request range: Wrong min AP count");
|
||||
return -1;
|
||||
}
|
||||
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) {
|
||||
wpa_printf(MSG_INFO,
|
||||
"Request range: Destination address is not connected");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(sta->rrm_enabled_capa[4] & WLAN_RRM_CAPS_FTM_RANGE_REPORT)) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"Request range: Destination station does not support FTM range report in RRM");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hapd->range_req_active) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Request range: Range request is already in process; overriding");
|
||||
hapd->range_req_active = 0;
|
||||
eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0,
|
||||
hostapd_range_rep_timeout_handler, hapd,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/* Action + measurement type + token + reps + EID + len = 7 */
|
||||
buf = wpabuf_alloc(7 + 255);
|
||||
if (!buf)
|
||||
return -1;
|
||||
|
||||
hapd->range_req_token++;
|
||||
if (!hapd->range_req_token) /* For wraparounds */
|
||||
hapd->range_req_token++;
|
||||
|
||||
/* IEEE P802.11-REVmc/D5.0, 9.6.7.2 */
|
||||
wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
|
||||
wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REQUEST);
|
||||
wpabuf_put_u8(buf, hapd->range_req_token); /* Dialog Token */
|
||||
wpabuf_put_le16(buf, 0); /* Number of Repetitions */
|
||||
|
||||
/* IEEE P802.11-REVmc/D5.0, 9.4.2.21 */
|
||||
wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST);
|
||||
len = wpabuf_put(buf, 1); /* Length will be set later */
|
||||
|
||||
wpabuf_put_u8(buf, 1); /* Measurement Token */
|
||||
/*
|
||||
* Parallel and Enable bits are 0; Duration, Request, and Report are
|
||||
* reserved.
|
||||
*/
|
||||
wpabuf_put_u8(buf, 0); /* Measurement Request Mode */
|
||||
wpabuf_put_u8(buf, MEASURE_TYPE_FTM_RANGE); /* Measurement Type */
|
||||
|
||||
/* IEEE P802.11-REVmc/D5.0, 9.4.2.21.19 */
|
||||
wpabuf_put_le16(buf, random_interval); /* Randomization Interval */
|
||||
wpabuf_put_u8(buf, min_ap); /* Minimum AP Count */
|
||||
|
||||
/* FTM Range Subelements */
|
||||
|
||||
/*
|
||||
* Taking the neighbor report part of the range request from neighbor
|
||||
* database instead of requesting the separate bits of data from the
|
||||
* user.
|
||||
*/
|
||||
for (i = 0; i < n_responders; i++) {
|
||||
struct hostapd_neighbor_entry *nr;
|
||||
|
||||
nr = hostapd_neighbor_get(hapd, responders + ETH_ALEN * i,
|
||||
NULL);
|
||||
if (!nr) {
|
||||
wpa_printf(MSG_INFO, "Missing neighbor report for "
|
||||
MACSTR, MAC2STR(responders + ETH_ALEN * i));
|
||||
wpabuf_free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wpabuf_tailroom(buf) < 2 + wpabuf_len(nr->nr)) {
|
||||
wpa_printf(MSG_ERROR, "Too long range request");
|
||||
wpabuf_free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpabuf_put_u8(buf, WLAN_EID_NEIGHBOR_REPORT);
|
||||
wpabuf_put_u8(buf, wpabuf_len(nr->nr));
|
||||
wpabuf_put_buf(buf, nr->nr);
|
||||
}
|
||||
|
||||
/* Action + measurement type + token + reps + EID + len = 7 */
|
||||
*len = wpabuf_len(buf) - 7;
|
||||
|
||||
ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
|
||||
wpabuf_head(buf), wpabuf_len(buf));
|
||||
wpabuf_free(buf);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
hapd->range_req_active = 1;
|
||||
|
||||
eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0,
|
||||
hostapd_range_rep_timeout_handler, hapd, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void hostapd_clean_rrm(struct hostapd_data *hapd)
|
||||
{
|
||||
hostpad_free_neighbor_db(hapd);
|
||||
eloop_cancel_timeout(hostapd_lci_rep_timeout_handler, hapd, NULL);
|
||||
hapd->lci_req_active = 0;
|
||||
eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd, NULL);
|
||||
hapd->range_req_active = 0;
|
||||
}
|
28
src/ap/rrm.h
Normal file
28
src/ap/rrm.h
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* hostapd / Radio Measurement (RRM)
|
||||
* Copyright(c) 2013 - 2016 Intel Mobile Communications GmbH.
|
||||
* Copyright(c) 2011 - 2016 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef RRM_H
|
||||
#define RRM_H
|
||||
|
||||
/*
|
||||
* Max measure request length is 255, -6 of the body we have 249 for the
|
||||
* neighbor report elements. Each neighbor report element is at least 2 + 13
|
||||
* bytes, so we can't have more than 16 responders in the request.
|
||||
*/
|
||||
#define RRM_RANGE_REQ_MAX_RESPONDERS 16
|
||||
|
||||
void hostapd_handle_radio_measurement(struct hostapd_data *hapd,
|
||||
const u8 *buf, size_t len);
|
||||
int hostapd_send_lci_req(struct hostapd_data *hapd, const u8 *addr);
|
||||
int hostapd_send_range_req(struct hostapd_data *hapd, const u8 *addr,
|
||||
u16 random_interval, u8 min_ap,
|
||||
const u8 *responders, unsigned int n_responders);
|
||||
void hostapd_clean_rrm(struct hostapd_data *hapd);
|
||||
|
||||
#endif /* RRM_H */
|
@ -32,8 +32,10 @@
|
||||
#include "ap_drv_ops.h"
|
||||
#include "gas_serv.h"
|
||||
#include "wnm_ap.h"
|
||||
#include "mbo_ap.h"
|
||||
#include "ndisc_snoop.h"
|
||||
#include "sta_info.h"
|
||||
#include "vlan.h"
|
||||
|
||||
static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
|
||||
struct sta_info *sta);
|
||||
@ -169,21 +171,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
ap_sta_ip6addr_del(hapd, sta);
|
||||
|
||||
if (!hapd->iface->driver_ap_teardown &&
|
||||
!(sta->flags & WLAN_STA_PREAUTH))
|
||||
!(sta->flags & WLAN_STA_PREAUTH)) {
|
||||
hostapd_drv_sta_remove(hapd, sta->addr);
|
||||
|
||||
#ifndef CONFIG_NO_VLAN
|
||||
if (sta->vlan_id_bound) {
|
||||
/*
|
||||
* Need to remove the STA entry before potentially removing the
|
||||
* VLAN.
|
||||
*/
|
||||
if (hapd->iface->driver_ap_teardown &&
|
||||
!(sta->flags & WLAN_STA_PREAUTH))
|
||||
hostapd_drv_sta_remove(hapd, sta->addr);
|
||||
vlan_remove_dynamic(hapd, sta->vlan_id_bound);
|
||||
sta->added_unassoc = 0;
|
||||
}
|
||||
#endif /* CONFIG_NO_VLAN */
|
||||
|
||||
ap_sta_hash_del(hapd, sta);
|
||||
ap_sta_list_del(hapd, sta);
|
||||
@ -231,6 +222,13 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
hapd->iface->num_sta_ht_20mhz--;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TAXONOMY
|
||||
wpabuf_free(sta->probe_ie_taxonomy);
|
||||
sta->probe_ie_taxonomy = NULL;
|
||||
wpabuf_free(sta->assoc_ie_taxonomy);
|
||||
sta->assoc_ie_taxonomy = NULL;
|
||||
#endif /* CONFIG_TAXONOMY */
|
||||
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
ht40_intolerant_remove(hapd->iface, sta);
|
||||
#endif /* CONFIG_IEEE80211N */
|
||||
@ -251,7 +249,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
|
||||
#ifdef CONFIG_MESH
|
||||
if (hapd->mesh_sta_free_cb)
|
||||
hapd->mesh_sta_free_cb(sta);
|
||||
hapd->mesh_sta_free_cb(hapd, sta);
|
||||
#endif /* CONFIG_MESH */
|
||||
|
||||
if (set_beacon)
|
||||
@ -262,11 +260,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
|
||||
eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
|
||||
eloop_cancel_timeout(ap_handle_session_warning_timer, hapd, sta);
|
||||
eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
|
||||
eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
|
||||
ap_sta_clear_disconnect_timeouts(hapd, sta);
|
||||
sae_clear_retransmit_timer(hapd, sta);
|
||||
|
||||
ieee802_1x_free_station(sta);
|
||||
ieee802_1x_free_station(hapd, sta);
|
||||
wpa_auth_sta_deinit(sta->wpa_sm);
|
||||
rsn_preauth_free_station(hapd, sta);
|
||||
#ifndef CONFIG_NO_RADIUS
|
||||
@ -274,6 +271,28 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
radius_client_flush_auth(hapd->radius, sta->addr);
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
|
||||
#ifndef CONFIG_NO_VLAN
|
||||
/*
|
||||
* sta->wpa_sm->group needs to be released before so that
|
||||
* vlan_remove_dynamic() can check that no stations are left on the
|
||||
* AP_VLAN netdev.
|
||||
*/
|
||||
if (sta->vlan_id)
|
||||
vlan_remove_dynamic(hapd, sta->vlan_id);
|
||||
if (sta->vlan_id_bound) {
|
||||
/*
|
||||
* Need to remove the STA entry before potentially removing the
|
||||
* VLAN.
|
||||
*/
|
||||
if (hapd->iface->driver_ap_teardown &&
|
||||
!(sta->flags & WLAN_STA_PREAUTH)) {
|
||||
hostapd_drv_sta_remove(hapd, sta->addr);
|
||||
sta->added_unassoc = 0;
|
||||
}
|
||||
vlan_remove_dynamic(hapd, sta->vlan_id_bound);
|
||||
}
|
||||
#endif /* CONFIG_NO_VLAN */
|
||||
|
||||
os_free(sta->challenge);
|
||||
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
@ -315,6 +334,9 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
os_free(sta->sae);
|
||||
#endif /* CONFIG_SAE */
|
||||
|
||||
mbo_ap_sta_free(sta);
|
||||
os_free(sta->supp_op_classes);
|
||||
|
||||
os_free(sta);
|
||||
}
|
||||
|
||||
@ -354,8 +376,8 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
|
||||
unsigned long next_time = 0;
|
||||
int reason;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: " MACSTR " flags=0x%x timeout_next=%d",
|
||||
__func__, MAC2STR(sta->addr), sta->flags,
|
||||
wpa_printf(MSG_DEBUG, "%s: %s: " MACSTR " flags=0x%x timeout_next=%d",
|
||||
hapd->conf->iface, __func__, MAC2STR(sta->addr), sta->flags,
|
||||
sta->timeout_next);
|
||||
if (sta->timeout_next == STA_REMOVE) {
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||
@ -482,7 +504,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
|
||||
sta->acct_terminate_cause =
|
||||
RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT;
|
||||
accounting_sta_stop(hapd, sta);
|
||||
ieee802_1x_free_station(sta);
|
||||
ieee802_1x_free_station(hapd, sta);
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_INFO, "disassociated due to "
|
||||
"inactivity");
|
||||
@ -519,6 +541,8 @@ static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx)
|
||||
struct hostapd_data *hapd = eloop_ctx;
|
||||
struct sta_info *sta = timeout_ctx;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: Session timer for STA " MACSTR,
|
||||
hapd->conf->iface, MAC2STR(sta->addr));
|
||||
if (!(sta->flags & WLAN_STA_AUTH)) {
|
||||
if (sta->flags & WLAN_STA_GAS) {
|
||||
wpa_printf(MSG_DEBUG, "GAS: Remove temporary STA "
|
||||
@ -577,8 +601,8 @@ static void ap_handle_session_warning_timer(void *eloop_ctx, void *timeout_ctx)
|
||||
struct hostapd_data *hapd = eloop_ctx;
|
||||
struct sta_info *sta = timeout_ctx;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "WNM: Session warning time reached for " MACSTR,
|
||||
MAC2STR(sta->addr));
|
||||
wpa_printf(MSG_DEBUG, "%s: WNM: Session warning time reached for "
|
||||
MACSTR, hapd->conf->iface, MAC2STR(sta->addr));
|
||||
if (sta->hs20_session_info_url == NULL)
|
||||
return;
|
||||
|
||||
@ -619,7 +643,10 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
|
||||
return NULL;
|
||||
}
|
||||
sta->acct_interim_interval = hapd->conf->acct_interim_interval;
|
||||
accounting_sta_get_id(hapd, sta);
|
||||
if (accounting_sta_get_id(hapd, sta) < 0) {
|
||||
os_free(sta);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
|
||||
wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
|
||||
@ -640,6 +667,11 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
|
||||
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
|
||||
dl_list_init(&sta->ip6addr);
|
||||
|
||||
#ifdef CONFIG_TAXONOMY
|
||||
sta_track_claim_taxonomy_info(hapd->iface, addr,
|
||||
&sta->probe_ie_taxonomy);
|
||||
#endif /* CONFIG_TAXONOMY */
|
||||
|
||||
return sta;
|
||||
}
|
||||
|
||||
@ -652,14 +684,16 @@ static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
|
||||
ap_sta_ip6addr_del(hapd, sta);
|
||||
|
||||
wpa_printf(MSG_DEBUG, "Removing STA " MACSTR " from kernel driver",
|
||||
MAC2STR(sta->addr));
|
||||
wpa_printf(MSG_DEBUG, "%s: Removing STA " MACSTR " from kernel driver",
|
||||
hapd->conf->iface, MAC2STR(sta->addr));
|
||||
if (hostapd_drv_sta_remove(hapd, sta->addr) &&
|
||||
sta->flags & WLAN_STA_ASSOC) {
|
||||
wpa_printf(MSG_DEBUG, "Could not remove station " MACSTR
|
||||
" from kernel driver.", MAC2STR(sta->addr));
|
||||
wpa_printf(MSG_DEBUG, "%s: Could not remove station " MACSTR
|
||||
" from kernel driver",
|
||||
hapd->conf->iface, MAC2STR(sta->addr));
|
||||
return -1;
|
||||
}
|
||||
sta->added_unassoc = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -683,6 +717,10 @@ static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
|
||||
if (!sta2)
|
||||
continue;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: disconnect old STA " MACSTR
|
||||
" association from another BSS %s",
|
||||
hapd->conf->iface, MAC2STR(sta2->addr),
|
||||
bss->conf->iface);
|
||||
ap_sta_disconnect(bss, sta2, sta2->addr,
|
||||
WLAN_REASON_PREV_AUTH_NOT_VALID);
|
||||
}
|
||||
@ -694,6 +732,8 @@ static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx)
|
||||
struct hostapd_data *hapd = eloop_ctx;
|
||||
struct sta_info *sta = timeout_ctx;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: Disassociation callback for STA " MACSTR,
|
||||
hapd->conf->iface, MAC2STR(sta->addr));
|
||||
ap_sta_remove(hapd, sta);
|
||||
mlme_disassociate_indication(hapd, sta, sta->disassoc_reason);
|
||||
}
|
||||
@ -717,7 +757,7 @@ void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0,
|
||||
ap_handle_timer, hapd, sta);
|
||||
accounting_sta_stop(hapd, sta);
|
||||
ieee802_1x_free_station(sta);
|
||||
ieee802_1x_free_station(hapd, sta);
|
||||
|
||||
sta->disassoc_reason = reason;
|
||||
sta->flags |= WLAN_STA_PENDING_DISASSOC_CB;
|
||||
@ -733,6 +773,8 @@ static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx)
|
||||
struct hostapd_data *hapd = eloop_ctx;
|
||||
struct sta_info *sta = timeout_ctx;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: Deauthentication callback for STA " MACSTR,
|
||||
hapd->conf->iface, MAC2STR(sta->addr));
|
||||
ap_sta_remove(hapd, sta);
|
||||
mlme_deauthenticate_indication(hapd, sta, sta->deauth_reason);
|
||||
}
|
||||
@ -756,7 +798,7 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
|
||||
ap_handle_timer, hapd, sta);
|
||||
accounting_sta_stop(hapd, sta);
|
||||
ieee802_1x_free_station(sta);
|
||||
ieee802_1x_free_station(hapd, sta);
|
||||
|
||||
sta->deauth_reason = reason;
|
||||
sta->flags |= WLAN_STA_PENDING_DEAUTH_CB;
|
||||
@ -784,6 +826,128 @@ int ap_sta_wps_cancel(struct hostapd_data *hapd,
|
||||
#endif /* CONFIG_WPS */
|
||||
|
||||
|
||||
static int ap_sta_get_free_vlan_id(struct hostapd_data *hapd)
|
||||
{
|
||||
struct hostapd_vlan *vlan;
|
||||
int vlan_id = MAX_VLAN_ID + 2;
|
||||
|
||||
retry:
|
||||
for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
|
||||
if (vlan->vlan_id == vlan_id) {
|
||||
vlan_id++;
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
return vlan_id;
|
||||
}
|
||||
|
||||
|
||||
int ap_sta_set_vlan(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
struct vlan_description *vlan_desc)
|
||||
{
|
||||
struct hostapd_vlan *vlan = NULL, *wildcard_vlan = NULL;
|
||||
int old_vlan_id, vlan_id = 0, ret = 0;
|
||||
|
||||
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
|
||||
vlan_desc = NULL;
|
||||
|
||||
/* Check if there is something to do */
|
||||
if (hapd->conf->ssid.per_sta_vif && !sta->vlan_id) {
|
||||
/* This sta is lacking its own vif */
|
||||
} else if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED &&
|
||||
!hapd->conf->ssid.per_sta_vif && sta->vlan_id) {
|
||||
/* sta->vlan_id needs to be reset */
|
||||
} else if (!vlan_compare(vlan_desc, sta->vlan_desc)) {
|
||||
return 0; /* nothing to change */
|
||||
}
|
||||
|
||||
/* Now the real VLAN changed or the STA just needs its own vif */
|
||||
if (hapd->conf->ssid.per_sta_vif) {
|
||||
/* Assign a new vif, always */
|
||||
/* find a free vlan_id sufficiently big */
|
||||
vlan_id = ap_sta_get_free_vlan_id(hapd);
|
||||
/* Get wildcard VLAN */
|
||||
for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
|
||||
if (vlan->vlan_id == VLAN_ID_WILDCARD)
|
||||
break;
|
||||
}
|
||||
if (!vlan) {
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"per_sta_vif missing wildcard");
|
||||
vlan_id = 0;
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
} else if (vlan_desc && vlan_desc->notempty) {
|
||||
for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
|
||||
if (!vlan_compare(&vlan->vlan_desc, vlan_desc))
|
||||
break;
|
||||
if (vlan->vlan_id == VLAN_ID_WILDCARD)
|
||||
wildcard_vlan = vlan;
|
||||
}
|
||||
if (vlan) {
|
||||
vlan_id = vlan->vlan_id;
|
||||
} else if (wildcard_vlan) {
|
||||
vlan = wildcard_vlan;
|
||||
vlan_id = vlan_desc->untagged;
|
||||
if (vlan_desc->tagged[0]) {
|
||||
/* Tagged VLAN configuration */
|
||||
vlan_id = ap_sta_get_free_vlan_id(hapd);
|
||||
}
|
||||
} else {
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"missing vlan and wildcard for vlan=%d%s",
|
||||
vlan_desc->untagged,
|
||||
vlan_desc->tagged[0] ? "+" : "");
|
||||
vlan_id = 0;
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (vlan && vlan->vlan_id == VLAN_ID_WILDCARD) {
|
||||
vlan = vlan_add_dynamic(hapd, vlan, vlan_id, vlan_desc);
|
||||
if (vlan == NULL) {
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"could not add dynamic VLAN interface for vlan=%d%s",
|
||||
vlan_desc ? vlan_desc->untagged : -1,
|
||||
(vlan_desc && vlan_desc->tagged[0]) ?
|
||||
"+" : "");
|
||||
vlan_id = 0;
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"added new dynamic VLAN interface '%s'",
|
||||
vlan->ifname);
|
||||
} else if (vlan && vlan->dynamic_vlan > 0) {
|
||||
vlan->dynamic_vlan++;
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"updated existing dynamic VLAN interface '%s'",
|
||||
vlan->ifname);
|
||||
}
|
||||
done:
|
||||
old_vlan_id = sta->vlan_id;
|
||||
sta->vlan_id = vlan_id;
|
||||
sta->vlan_desc = vlan ? &vlan->vlan_desc : NULL;
|
||||
|
||||
if (vlan_id != old_vlan_id && old_vlan_id)
|
||||
vlan_remove_dynamic(hapd, old_vlan_id);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
{
|
||||
#ifndef CONFIG_NO_VLAN
|
||||
@ -796,20 +960,11 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
if (hapd->conf->ssid.vlan[0])
|
||||
iface = hapd->conf->ssid.vlan;
|
||||
|
||||
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
|
||||
sta->vlan_id = 0;
|
||||
else if (sta->vlan_id > 0) {
|
||||
struct hostapd_vlan *wildcard_vlan = NULL;
|
||||
vlan = hapd->conf->vlan;
|
||||
while (vlan) {
|
||||
if (sta->vlan_id > 0) {
|
||||
for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
|
||||
if (vlan->vlan_id == sta->vlan_id)
|
||||
break;
|
||||
if (vlan->vlan_id == VLAN_ID_WILDCARD)
|
||||
wildcard_vlan = vlan;
|
||||
vlan = vlan->next;
|
||||
}
|
||||
if (!vlan)
|
||||
vlan = wildcard_vlan;
|
||||
if (vlan)
|
||||
iface = vlan->ifname;
|
||||
}
|
||||
@ -829,54 +984,13 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
sta->vlan_id);
|
||||
ret = -1;
|
||||
goto done;
|
||||
} else if (sta->vlan_id > 0 && vlan->vlan_id == VLAN_ID_WILDCARD) {
|
||||
vlan = vlan_add_dynamic(hapd, vlan, sta->vlan_id);
|
||||
if (vlan == NULL) {
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG, "could not add "
|
||||
"dynamic VLAN interface for vlan_id=%d",
|
||||
sta->vlan_id);
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
iface = vlan->ifname;
|
||||
if (vlan_setup_encryption_dyn(hapd, iface) != 0) {
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG, "could not "
|
||||
"configure encryption for dynamic VLAN "
|
||||
"interface for vlan_id=%d",
|
||||
sta->vlan_id);
|
||||
}
|
||||
|
||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG, "added new dynamic VLAN "
|
||||
"interface '%s'", iface);
|
||||
} else if (vlan && vlan->vlan_id == sta->vlan_id) {
|
||||
if (vlan->dynamic_vlan > 0) {
|
||||
vlan->dynamic_vlan++;
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG, "updated existing "
|
||||
"dynamic VLAN interface '%s'", iface);
|
||||
}
|
||||
|
||||
/*
|
||||
* Update encryption configuration for statically generated
|
||||
* VLAN interface. This is only used for static WEP
|
||||
* configuration for the case where hostapd did not yet know
|
||||
* which keys are to be used when the interface was added.
|
||||
*/
|
||||
if (vlan_setup_encryption_dyn(hapd, iface) != 0) {
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG, "could not "
|
||||
"configure encryption for VLAN "
|
||||
"interface for vlan_id=%d",
|
||||
sta->vlan_id);
|
||||
}
|
||||
} else if (vlan && vlan->dynamic_vlan > 0) {
|
||||
vlan->dynamic_vlan++;
|
||||
hostapd_logger(hapd, sta->addr,
|
||||
HOSTAPD_MODULE_IEEE80211,
|
||||
HOSTAPD_LEVEL_DEBUG,
|
||||
"updated existing dynamic VLAN interface '%s'",
|
||||
iface);
|
||||
}
|
||||
|
||||
/* ref counters have been increased, so mark the station */
|
||||
@ -942,6 +1056,10 @@ static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
|
||||
unsigned int timeout, sec, usec;
|
||||
u8 *trans_id, *nbuf;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "%s: SA Query timer for STA " MACSTR
|
||||
" (count=%d)",
|
||||
hapd->conf->iface, MAC2STR(sta->addr), sta->sa_query_count);
|
||||
|
||||
if (sta->sa_query_count > 0 &&
|
||||
ap_check_sa_query_timeout(hapd, sta))
|
||||
return;
|
||||
@ -1080,6 +1198,14 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
const u8 *addr, u16 reason)
|
||||
{
|
||||
if (sta)
|
||||
wpa_printf(MSG_DEBUG, "%s: %s STA " MACSTR " reason=%u",
|
||||
hapd->conf->iface, __func__, MAC2STR(sta->addr),
|
||||
reason);
|
||||
else if (addr)
|
||||
wpa_printf(MSG_DEBUG, "%s: %s addr " MACSTR " reason=%u",
|
||||
hapd->conf->iface, __func__, MAC2STR(addr),
|
||||
reason);
|
||||
|
||||
if (sta == NULL && addr)
|
||||
sta = ap_get_sta(hapd, addr);
|
||||
@ -1093,10 +1219,10 @@ void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
|
||||
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
|
||||
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
|
||||
wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
|
||||
wpa_printf(MSG_DEBUG, "%s: %s: reschedule ap_handle_timer timeout "
|
||||
"for " MACSTR " (%d seconds - "
|
||||
"AP_MAX_INACTIVITY_AFTER_DEAUTH)",
|
||||
__func__, MAC2STR(sta->addr),
|
||||
hapd->conf->iface, __func__, MAC2STR(sta->addr),
|
||||
AP_MAX_INACTIVITY_AFTER_DEAUTH);
|
||||
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
|
||||
eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
|
||||
@ -1136,6 +1262,22 @@ void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta)
|
||||
}
|
||||
|
||||
|
||||
void ap_sta_clear_disconnect_timeouts(struct hostapd_data *hapd,
|
||||
struct sta_info *sta)
|
||||
{
|
||||
if (eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta) > 0)
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"%s: Removed ap_sta_deauth_cb_timeout timeout for "
|
||||
MACSTR,
|
||||
hapd->conf->iface, MAC2STR(sta->addr));
|
||||
if (eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta) > 0)
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"%s: Removed ap_sta_disassoc_cb_timeout timeout for "
|
||||
MACSTR,
|
||||
hapd->conf->iface, MAC2STR(sta->addr));
|
||||
}
|
||||
|
||||
|
||||
int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
|
||||
{
|
||||
int res;
|
||||
|
@ -12,9 +12,11 @@
|
||||
#ifdef CONFIG_MESH
|
||||
/* needed for mesh_plink_state enum */
|
||||
#include "common/defs.h"
|
||||
#include "common/wpa_common.h"
|
||||
#endif /* CONFIG_MESH */
|
||||
|
||||
#include "list.h"
|
||||
#include "vlan.h"
|
||||
|
||||
/* STA flags */
|
||||
#define WLAN_STA_AUTH BIT(0)
|
||||
@ -45,6 +47,20 @@
|
||||
#define WLAN_SUPP_RATES_MAX 32
|
||||
|
||||
|
||||
struct mbo_non_pref_chan_info {
|
||||
struct mbo_non_pref_chan_info *next;
|
||||
u8 op_class;
|
||||
u8 pref;
|
||||
u8 reason_code;
|
||||
u8 num_channels;
|
||||
u8 channels[];
|
||||
};
|
||||
|
||||
struct pending_eapol_rx {
|
||||
struct wpabuf *buf;
|
||||
struct os_reltime rx_time;
|
||||
};
|
||||
|
||||
struct sta_info {
|
||||
struct sta_info *next; /* next entry in sta list */
|
||||
struct sta_info *hnext; /* next entry in hash table list */
|
||||
@ -63,13 +79,22 @@ struct sta_info {
|
||||
enum mesh_plink_state plink_state;
|
||||
u16 peer_lid;
|
||||
u16 my_lid;
|
||||
u16 peer_aid;
|
||||
u16 mpm_close_reason;
|
||||
int mpm_retries;
|
||||
u8 my_nonce[32];
|
||||
u8 peer_nonce[32];
|
||||
u8 my_nonce[WPA_NONCE_LEN];
|
||||
u8 peer_nonce[WPA_NONCE_LEN];
|
||||
u8 aek[32]; /* SHA256 digest length */
|
||||
u8 mtk[16];
|
||||
u8 mgtk[16];
|
||||
u8 mtk[WPA_TK_MAX_LEN];
|
||||
size_t mtk_len;
|
||||
u8 mgtk_rsc[6];
|
||||
u8 mgtk_key_id;
|
||||
u8 mgtk[WPA_TK_MAX_LEN];
|
||||
size_t mgtk_len;
|
||||
u8 igtk_rsc[6];
|
||||
u8 igtk[WPA_TK_MAX_LEN];
|
||||
size_t igtk_len;
|
||||
u16 igtk_key_id;
|
||||
u8 sae_auth_retry;
|
||||
#endif /* CONFIG_MESH */
|
||||
|
||||
@ -86,6 +111,8 @@ struct sta_info {
|
||||
unsigned int hs20_deauth_requested:1;
|
||||
unsigned int session_timeout_set:1;
|
||||
unsigned int radius_das_match:1;
|
||||
unsigned int ecsa_supported:1;
|
||||
unsigned int added_unassoc:1;
|
||||
|
||||
u16 auth_alg;
|
||||
|
||||
@ -100,17 +127,20 @@ struct sta_info {
|
||||
/* IEEE 802.1X related data */
|
||||
struct eapol_state_machine *eapol_sm;
|
||||
|
||||
u32 acct_session_id_hi;
|
||||
u32 acct_session_id_lo;
|
||||
struct pending_eapol_rx *pending_eapol_rx;
|
||||
|
||||
u64 acct_session_id;
|
||||
struct os_reltime acct_session_start;
|
||||
int acct_session_started;
|
||||
int acct_terminate_cause; /* Acct-Terminate-Cause */
|
||||
int acct_interim_interval; /* Acct-Interim-Interval */
|
||||
unsigned int acct_interim_errors;
|
||||
|
||||
unsigned long last_rx_bytes;
|
||||
unsigned long last_tx_bytes;
|
||||
u32 acct_input_gigawords; /* Acct-Input-Gigawords */
|
||||
u32 acct_output_gigawords; /* Acct-Output-Gigawords */
|
||||
/* For extending 32-bit driver counters to 64-bit counters */
|
||||
u32 last_rx_bytes_hi;
|
||||
u32 last_rx_bytes_lo;
|
||||
u32 last_tx_bytes_hi;
|
||||
u32 last_tx_bytes_lo;
|
||||
|
||||
u8 *challenge; /* IEEE 802.11 Shared Key Authentication Challenge */
|
||||
|
||||
@ -118,6 +148,7 @@ struct sta_info {
|
||||
struct rsn_preauth_interface *preauth_iface;
|
||||
|
||||
int vlan_id; /* 0: none, >0: VID */
|
||||
struct vlan_description *vlan_desc;
|
||||
int vlan_id_bound; /* updated by ap_sta_bind_vlan() */
|
||||
/* PSKs from RADIUS authentication server */
|
||||
struct hostapd_sta_wpa_psk_short *psk;
|
||||
@ -161,6 +192,7 @@ struct sta_info {
|
||||
|
||||
#ifdef CONFIG_SAE
|
||||
struct sae_data *sae;
|
||||
unsigned int mesh_sae_pmksa_caching:1;
|
||||
#endif /* CONFIG_SAE */
|
||||
|
||||
u32 session_timeout; /* valid only if session_timeout_set == 1 */
|
||||
@ -170,6 +202,22 @@ struct sta_info {
|
||||
u16 last_seq_ctrl;
|
||||
/* Last Authentication/(Re)Association Request/Action frame subtype */
|
||||
u8 last_subtype;
|
||||
|
||||
#ifdef CONFIG_MBO
|
||||
u8 cell_capa; /* 0 = unknown (not an MBO STA); otherwise,
|
||||
* enum mbo_cellular_capa values */
|
||||
struct mbo_non_pref_chan_info *non_pref_chan;
|
||||
#endif /* CONFIG_MBO */
|
||||
|
||||
u8 *supp_op_classes; /* Supported Operating Classes element, if
|
||||
* received, starting from the Length field */
|
||||
|
||||
u8 rrm_enabled_capa[5];
|
||||
|
||||
#ifdef CONFIG_TAXONOMY
|
||||
struct wpabuf *probe_ie_taxonomy;
|
||||
struct wpabuf *assoc_ie_taxonomy;
|
||||
#endif /* CONFIG_TAXONOMY */
|
||||
};
|
||||
|
||||
|
||||
@ -180,7 +228,7 @@ struct sta_info {
|
||||
* AP_DISASSOC_DELAY seconds. Similarly, the station will be deauthenticated
|
||||
* after AP_DEAUTH_DELAY seconds has passed after disassociation. */
|
||||
#define AP_MAX_INACTIVITY (5 * 60)
|
||||
#define AP_DISASSOC_DELAY (1)
|
||||
#define AP_DISASSOC_DELAY (3)
|
||||
#define AP_DEAUTH_DELAY (1)
|
||||
/* Number of seconds to keep STA entry with Authenticated flag after it has
|
||||
* been disassociated. */
|
||||
@ -220,6 +268,8 @@ int ap_sta_wps_cancel(struct hostapd_data *hapd,
|
||||
struct sta_info *sta, void *ctx);
|
||||
#endif /* CONFIG_WPS */
|
||||
int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
int ap_sta_set_vlan(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
struct vlan_description *vlan_desc);
|
||||
void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
@ -235,6 +285,8 @@ static inline int ap_sta_is_authorized(struct sta_info *sta)
|
||||
|
||||
void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta);
|
||||
void ap_sta_clear_disconnect_timeouts(struct hostapd_data *hapd,
|
||||
struct sta_info *sta);
|
||||
|
||||
int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen);
|
||||
|
||||
|
291
src/ap/taxonomy.c
Normal file
291
src/ap/taxonomy.c
Normal file
@ -0,0 +1,291 @@
|
||||
/*
|
||||
* hostapd / Client taxonomy
|
||||
* Copyright (c) 2015 Google, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*
|
||||
* Parse a series of IEs, as in Probe Request or (Re)Association Request frames,
|
||||
* and render them to a descriptive string. The tag number of standard options
|
||||
* is written to the string, while the vendor ID and subtag are written for
|
||||
* vendor options.
|
||||
*
|
||||
* Example strings:
|
||||
* 0,1,50,45,221(00904c,51)
|
||||
* 0,1,33,36,48,45,221(00904c,51),221(0050f2,2)
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "common/wpa_ctrl.h"
|
||||
#include "hostapd.h"
|
||||
#include "sta_info.h"
|
||||
|
||||
|
||||
/* Copy a string with no funny schtuff allowed; only alphanumerics. */
|
||||
static void no_mischief_strncpy(char *dst, const char *src, size_t n)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
unsigned char s = src[i];
|
||||
int is_lower = s >= 'a' && s <= 'z';
|
||||
int is_upper = s >= 'A' && s <= 'Z';
|
||||
int is_digit = s >= '0' && s <= '9';
|
||||
|
||||
if (is_lower || is_upper || is_digit) {
|
||||
/* TODO: if any manufacturer uses Unicode within the
|
||||
* WPS header, it will get mangled here. */
|
||||
dst[i] = s;
|
||||
} else {
|
||||
/* Note that even spaces will be transformed to
|
||||
* underscores, so 'Nexus 7' will turn into 'Nexus_7'.
|
||||
* This is deliberate, to make the string easier to
|
||||
* parse. */
|
||||
dst[i] = '_';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int get_wps_name(char *name, size_t name_len,
|
||||
const u8 *data, size_t data_len)
|
||||
{
|
||||
/* Inside the WPS IE are a series of attributes, using two byte IDs
|
||||
* and two byte lengths. We're looking for the model name, if
|
||||
* present. */
|
||||
while (data_len >= 4) {
|
||||
u16 id, elen;
|
||||
|
||||
id = WPA_GET_BE16(data);
|
||||
elen = WPA_GET_BE16(data + 2);
|
||||
data += 4;
|
||||
data_len -= 4;
|
||||
|
||||
if (elen > data_len)
|
||||
return 0;
|
||||
|
||||
if (id == 0x1023) {
|
||||
/* Model name, like 'Nexus 7' */
|
||||
size_t n = (elen < name_len) ? elen : name_len;
|
||||
no_mischief_strncpy(name, (const char *) data, n);
|
||||
return n;
|
||||
}
|
||||
|
||||
data += elen;
|
||||
data_len -= elen;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void ie_to_string(char *fstr, size_t fstr_len, const struct wpabuf *ies)
|
||||
{
|
||||
char *fpos = fstr;
|
||||
char *fend = fstr + fstr_len;
|
||||
char htcap[7 + 4 + 1]; /* ",htcap:" + %04hx + trailing NUL */
|
||||
char htagg[7 + 2 + 1]; /* ",htagg:" + %02hx + trailing NUL */
|
||||
char htmcs[7 + 8 + 1]; /* ",htmcs:" + %08x + trailing NUL */
|
||||
char vhtcap[8 + 8 + 1]; /* ",vhtcap:" + %08x + trailing NUL */
|
||||
char vhtrxmcs[10 + 8 + 1]; /* ",vhtrxmcs:" + %08x + trailing NUL */
|
||||
char vhttxmcs[10 + 8 + 1]; /* ",vhttxmcs:" + %08x + trailing NUL */
|
||||
#define MAX_EXTCAP 254
|
||||
char extcap[8 + 2 * MAX_EXTCAP + 1]; /* ",extcap:" + hex + trailing NUL
|
||||
*/
|
||||
char txpow[7 + 4 + 1]; /* ",txpow:" + %04hx + trailing NUL */
|
||||
#define WPS_NAME_LEN 32
|
||||
char wps[WPS_NAME_LEN + 5 + 1]; /* room to prepend ",wps:" + trailing
|
||||
* NUL */
|
||||
int num = 0;
|
||||
const u8 *ie;
|
||||
size_t ie_len;
|
||||
int ret;
|
||||
|
||||
os_memset(htcap, 0, sizeof(htcap));
|
||||
os_memset(htagg, 0, sizeof(htagg));
|
||||
os_memset(htmcs, 0, sizeof(htmcs));
|
||||
os_memset(vhtcap, 0, sizeof(vhtcap));
|
||||
os_memset(vhtrxmcs, 0, sizeof(vhtrxmcs));
|
||||
os_memset(vhttxmcs, 0, sizeof(vhttxmcs));
|
||||
os_memset(extcap, 0, sizeof(extcap));
|
||||
os_memset(txpow, 0, sizeof(txpow));
|
||||
os_memset(wps, 0, sizeof(wps));
|
||||
*fpos = '\0';
|
||||
|
||||
if (!ies)
|
||||
return;
|
||||
ie = wpabuf_head(ies);
|
||||
ie_len = wpabuf_len(ies);
|
||||
|
||||
while (ie_len >= 2) {
|
||||
u8 id, elen;
|
||||
char *sep = (num++ == 0) ? "" : ",";
|
||||
|
||||
id = *ie++;
|
||||
elen = *ie++;
|
||||
ie_len -= 2;
|
||||
|
||||
if (elen > ie_len)
|
||||
break;
|
||||
|
||||
if (id == WLAN_EID_VENDOR_SPECIFIC && elen >= 4) {
|
||||
/* Vendor specific */
|
||||
if (WPA_GET_BE32(ie) == WPS_IE_VENDOR_TYPE) {
|
||||
/* WPS */
|
||||
char model_name[WPS_NAME_LEN + 1];
|
||||
const u8 *data = &ie[4];
|
||||
size_t data_len = elen - 4;
|
||||
|
||||
os_memset(model_name, 0, sizeof(model_name));
|
||||
if (get_wps_name(model_name, WPS_NAME_LEN, data,
|
||||
data_len)) {
|
||||
os_snprintf(wps, sizeof(wps),
|
||||
",wps:%s", model_name);
|
||||
}
|
||||
}
|
||||
|
||||
ret = os_snprintf(fpos, fend - fpos,
|
||||
"%s%d(%02x%02x%02x,%d)",
|
||||
sep, id, ie[0], ie[1], ie[2], ie[3]);
|
||||
} else {
|
||||
if (id == WLAN_EID_HT_CAP && elen >= 2) {
|
||||
/* HT Capabilities (802.11n) */
|
||||
os_snprintf(htcap, sizeof(htcap),
|
||||
",htcap:%04hx",
|
||||
WPA_GET_LE16(ie));
|
||||
}
|
||||
if (id == WLAN_EID_HT_CAP && elen >= 3) {
|
||||
/* HT Capabilities (802.11n), A-MPDU information
|
||||
*/
|
||||
os_snprintf(htagg, sizeof(htagg),
|
||||
",htagg:%02hx", (u16) ie[2]);
|
||||
}
|
||||
if (id == WLAN_EID_HT_CAP && elen >= 7) {
|
||||
/* HT Capabilities (802.11n), MCS information */
|
||||
os_snprintf(htmcs, sizeof(htmcs),
|
||||
",htmcs:%08hx",
|
||||
(u16) WPA_GET_LE32(ie + 3));
|
||||
}
|
||||
if (id == WLAN_EID_VHT_CAP && elen >= 4) {
|
||||
/* VHT Capabilities (802.11ac) */
|
||||
os_snprintf(vhtcap, sizeof(vhtcap),
|
||||
",vhtcap:%08x",
|
||||
WPA_GET_LE32(ie));
|
||||
}
|
||||
if (id == WLAN_EID_VHT_CAP && elen >= 8) {
|
||||
/* VHT Capabilities (802.11ac), RX MCS
|
||||
* information */
|
||||
os_snprintf(vhtrxmcs, sizeof(vhtrxmcs),
|
||||
",vhtrxmcs:%08x",
|
||||
WPA_GET_LE32(ie + 4));
|
||||
}
|
||||
if (id == WLAN_EID_VHT_CAP && elen >= 12) {
|
||||
/* VHT Capabilities (802.11ac), TX MCS
|
||||
* information */
|
||||
os_snprintf(vhttxmcs, sizeof(vhttxmcs),
|
||||
",vhttxmcs:%08x",
|
||||
WPA_GET_LE32(ie + 8));
|
||||
}
|
||||
if (id == WLAN_EID_EXT_CAPAB) {
|
||||
/* Extended Capabilities */
|
||||
int i;
|
||||
int len = (elen < MAX_EXTCAP) ? elen :
|
||||
MAX_EXTCAP;
|
||||
char *p = extcap;
|
||||
|
||||
p += os_snprintf(extcap, sizeof(extcap),
|
||||
",extcap:");
|
||||
for (i = 0; i < len; i++) {
|
||||
int lim;
|
||||
|
||||
lim = sizeof(extcap) -
|
||||
os_strlen(extcap);
|
||||
if (lim <= 0)
|
||||
break;
|
||||
p += os_snprintf(p, lim, "%02x",
|
||||
*(ie + i));
|
||||
}
|
||||
}
|
||||
if (id == WLAN_EID_PWR_CAPABILITY && elen == 2) {
|
||||
/* TX Power */
|
||||
os_snprintf(txpow, sizeof(txpow),
|
||||
",txpow:%04hx",
|
||||
WPA_GET_LE16(ie));
|
||||
}
|
||||
|
||||
ret = os_snprintf(fpos, fend - fpos, "%s%d", sep, id);
|
||||
}
|
||||
if (os_snprintf_error(fend - fpos, ret))
|
||||
goto fail;
|
||||
fpos += ret;
|
||||
|
||||
ie += elen;
|
||||
ie_len -= elen;
|
||||
}
|
||||
|
||||
ret = os_snprintf(fpos, fend - fpos, "%s%s%s%s%s%s%s%s%s",
|
||||
htcap, htagg, htmcs, vhtcap, vhtrxmcs, vhttxmcs,
|
||||
txpow, extcap, wps);
|
||||
if (os_snprintf_error(fend - fpos, ret)) {
|
||||
fail:
|
||||
fstr[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int retrieve_sta_taxonomy(const struct hostapd_data *hapd,
|
||||
struct sta_info *sta, char *buf, size_t buflen)
|
||||
{
|
||||
int ret;
|
||||
char *pos, *end;
|
||||
|
||||
if (!sta->probe_ie_taxonomy || !sta->assoc_ie_taxonomy)
|
||||
return 0;
|
||||
|
||||
ret = os_snprintf(buf, buflen, "wifi4|probe:");
|
||||
if (os_snprintf_error(buflen, ret))
|
||||
return 0;
|
||||
pos = buf + ret;
|
||||
end = buf + buflen;
|
||||
|
||||
ie_to_string(pos, end - pos, sta->probe_ie_taxonomy);
|
||||
pos = os_strchr(pos, '\0');
|
||||
if (pos >= end)
|
||||
return 0;
|
||||
ret = os_snprintf(pos, end - pos, "|assoc:");
|
||||
if (os_snprintf_error(end - pos, ret))
|
||||
return 0;
|
||||
pos += ret;
|
||||
ie_to_string(pos, end - pos, sta->assoc_ie_taxonomy);
|
||||
pos = os_strchr(pos, '\0');
|
||||
return pos - buf;
|
||||
}
|
||||
|
||||
|
||||
void taxonomy_sta_info_probe_req(const struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
const u8 *ie, size_t ie_len)
|
||||
{
|
||||
wpabuf_free(sta->probe_ie_taxonomy);
|
||||
sta->probe_ie_taxonomy = wpabuf_alloc_copy(ie, ie_len);
|
||||
}
|
||||
|
||||
|
||||
void taxonomy_hostapd_sta_info_probe_req(const struct hostapd_data *hapd,
|
||||
struct hostapd_sta_info *info,
|
||||
const u8 *ie, size_t ie_len)
|
||||
{
|
||||
wpabuf_free(info->probe_ie_taxonomy);
|
||||
info->probe_ie_taxonomy = wpabuf_alloc_copy(ie, ie_len);
|
||||
}
|
||||
|
||||
|
||||
void taxonomy_sta_info_assoc_req(const struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
const u8 *ie, size_t ie_len)
|
||||
{
|
||||
wpabuf_free(sta->assoc_ie_taxonomy);
|
||||
sta->assoc_ie_taxonomy = wpabuf_alloc_copy(ie, ie_len);
|
||||
}
|
24
src/ap/taxonomy.h
Normal file
24
src/ap/taxonomy.h
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* hostapd / Station client taxonomy
|
||||
* Copyright (c) 2015 Google, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef TAXONOMY_H
|
||||
#define TAXONOMY_H
|
||||
|
||||
void taxonomy_sta_info_probe_req(const struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
const u8 *ie, size_t ie_len);
|
||||
void taxonomy_hostapd_sta_info_probe_req(const struct hostapd_data *hapd,
|
||||
struct hostapd_sta_info *sta,
|
||||
const u8 *ie, size_t ie_len);
|
||||
void taxonomy_sta_info_assoc_req(const struct hostapd_data *hapd,
|
||||
struct sta_info *sta,
|
||||
const u8 *ie, size_t ie_len);
|
||||
int retrieve_sta_taxonomy(const struct hostapd_data *hapd,
|
||||
struct sta_info *sta, char *buf, size_t buflen);
|
||||
|
||||
#endif /* TAXONOMY_H */
|
34
src/ap/vlan.c
Normal file
34
src/ap/vlan.c
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* hostapd / VLAN definition
|
||||
* 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 "ap/vlan.h"
|
||||
|
||||
/* compare the two arguments, NULL is treated as empty
|
||||
* return zero iff they are equal
|
||||
*/
|
||||
int vlan_compare(struct vlan_description *a, struct vlan_description *b)
|
||||
{
|
||||
int i;
|
||||
const int a_empty = !a || !a->notempty;
|
||||
const int b_empty = !b || !b->notempty;
|
||||
|
||||
if (a_empty && b_empty)
|
||||
return 0;
|
||||
if (a_empty || b_empty)
|
||||
return 1;
|
||||
if (a->untagged != b->untagged)
|
||||
return 1;
|
||||
for (i = 0; i < MAX_NUM_TAGGED_VLAN; i++) {
|
||||
if (a->tagged[i] != b->tagged[i])
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
30
src/ap/vlan.h
Normal file
30
src/ap/vlan.h
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* hostapd / VLAN definition
|
||||
* Copyright (c) 2015, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef VLAN_H
|
||||
#define VLAN_H
|
||||
|
||||
#define MAX_NUM_TAGGED_VLAN 32
|
||||
|
||||
struct vlan_description {
|
||||
int notempty; /* 0 : no vlan information present, 1: else */
|
||||
int untagged; /* >0 802.1q vid */
|
||||
int tagged[MAX_NUM_TAGGED_VLAN]; /* first k items, ascending order */
|
||||
};
|
||||
|
||||
#ifndef CONFIG_NO_VLAN
|
||||
int vlan_compare(struct vlan_description *a, struct vlan_description *b);
|
||||
#else /* CONFIG_NO_VLAN */
|
||||
static inline int
|
||||
vlan_compare(struct vlan_description *a, struct vlan_description *b)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_NO_VLAN */
|
||||
|
||||
#endif /* VLAN_H */
|
752
src/ap/vlan_full.c
Normal file
752
src/ap/vlan_full.c
Normal file
@ -0,0 +1,752 @@
|
||||
/*
|
||||
* hostapd / VLAN initialization - full dynamic VLAN
|
||||
* Copyright 2003, Instant802 Networks, Inc.
|
||||
* Copyright 2005-2006, Devicescape Software, Inc.
|
||||
* Copyright (c) 2009, 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 <net/if.h>
|
||||
/* Avoid conflicts due to NetBSD net/if.h if_type define with driver.h */
|
||||
#undef if_type
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "drivers/priv_netlink.h"
|
||||
#include "common/linux_bridge.h"
|
||||
#include "common/linux_vlan.h"
|
||||
#include "utils/eloop.h"
|
||||
#include "hostapd.h"
|
||||
#include "ap_config.h"
|
||||
#include "ap_drv_ops.h"
|
||||
#include "wpa_auth.h"
|
||||
#include "vlan_init.h"
|
||||
#include "vlan_util.h"
|
||||
|
||||
|
||||
struct full_dynamic_vlan {
|
||||
int s; /* socket on which to listen for new/removed interfaces. */
|
||||
};
|
||||
|
||||
#define DVLAN_CLEAN_BR 0x1
|
||||
#define DVLAN_CLEAN_VLAN 0x2
|
||||
#define DVLAN_CLEAN_VLAN_PORT 0x4
|
||||
|
||||
struct dynamic_iface {
|
||||
char ifname[IFNAMSIZ + 1];
|
||||
int usage;
|
||||
int clean;
|
||||
struct dynamic_iface *next;
|
||||
};
|
||||
|
||||
|
||||
/* Increment ref counter for ifname and add clean flag.
|
||||
* If not in list, add it only if some flags are given.
|
||||
*/
|
||||
static void dyn_iface_get(struct hostapd_data *hapd, const char *ifname,
|
||||
int clean)
|
||||
{
|
||||
struct dynamic_iface *next, **dynamic_ifaces;
|
||||
struct hapd_interfaces *interfaces;
|
||||
|
||||
interfaces = hapd->iface->interfaces;
|
||||
dynamic_ifaces = &interfaces->vlan_priv;
|
||||
|
||||
for (next = *dynamic_ifaces; next; next = next->next) {
|
||||
if (os_strcmp(ifname, next->ifname) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (next) {
|
||||
next->usage++;
|
||||
next->clean |= clean;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!clean)
|
||||
return;
|
||||
|
||||
next = os_zalloc(sizeof(*next));
|
||||
if (!next)
|
||||
return;
|
||||
os_strlcpy(next->ifname, ifname, sizeof(next->ifname));
|
||||
next->usage = 1;
|
||||
next->clean = clean;
|
||||
next->next = *dynamic_ifaces;
|
||||
*dynamic_ifaces = next;
|
||||
}
|
||||
|
||||
|
||||
/* Decrement reference counter for given ifname.
|
||||
* Return clean flag iff reference counter was decreased to zero, else zero
|
||||
*/
|
||||
static int dyn_iface_put(struct hostapd_data *hapd, const char *ifname)
|
||||
{
|
||||
struct dynamic_iface *next, *prev = NULL, **dynamic_ifaces;
|
||||
struct hapd_interfaces *interfaces;
|
||||
int clean;
|
||||
|
||||
interfaces = hapd->iface->interfaces;
|
||||
dynamic_ifaces = &interfaces->vlan_priv;
|
||||
|
||||
for (next = *dynamic_ifaces; next; next = next->next) {
|
||||
if (os_strcmp(ifname, next->ifname) == 0)
|
||||
break;
|
||||
prev = next;
|
||||
}
|
||||
|
||||
if (!next)
|
||||
return 0;
|
||||
|
||||
next->usage--;
|
||||
if (next->usage)
|
||||
return 0;
|
||||
|
||||
if (prev)
|
||||
prev->next = next->next;
|
||||
else
|
||||
*dynamic_ifaces = next->next;
|
||||
clean = next->clean;
|
||||
os_free(next);
|
||||
|
||||
return clean;
|
||||
}
|
||||
|
||||
|
||||
static int ifconfig_down(const char *if_name)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "VLAN: Set interface %s down", if_name);
|
||||
return ifconfig_helper(if_name, 0);
|
||||
}
|
||||
|
||||
|
||||
/* This value should be 256 ONLY. If it is something else, then hostapd
|
||||
* might crash!, as this value has been hard-coded in 2.4.x kernel
|
||||
* bridging code.
|
||||
*/
|
||||
#define MAX_BR_PORTS 256
|
||||
|
||||
static int br_delif(const char *br_name, const char *if_name)
|
||||
{
|
||||
int fd;
|
||||
struct ifreq ifr;
|
||||
unsigned long args[2];
|
||||
int if_index;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "VLAN: br_delif(%s, %s)", br_name, if_name);
|
||||
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
|
||||
"failed: %s", __func__, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if_index = if_nametoindex(if_name);
|
||||
|
||||
if (if_index == 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
|
||||
"interface index for '%s'",
|
||||
__func__, if_name);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
args[0] = BRCTL_DEL_IF;
|
||||
args[1] = if_index;
|
||||
|
||||
os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
|
||||
ifr.ifr_data = (void *) args;
|
||||
|
||||
if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0 && errno != EINVAL) {
|
||||
/* No error if interface already removed. */
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
|
||||
"BRCTL_DEL_IF] failed for br_name=%s if_name=%s: "
|
||||
"%s", __func__, br_name, if_name, strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Add interface 'if_name' to the bridge 'br_name'
|
||||
|
||||
returns -1 on error
|
||||
returns 1 if the interface is already part of the bridge
|
||||
returns 0 otherwise
|
||||
*/
|
||||
static int br_addif(const char *br_name, const char *if_name)
|
||||
{
|
||||
int fd;
|
||||
struct ifreq ifr;
|
||||
unsigned long args[2];
|
||||
int if_index;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "VLAN: br_addif(%s, %s)", br_name, if_name);
|
||||
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
|
||||
"failed: %s", __func__, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if_index = if_nametoindex(if_name);
|
||||
|
||||
if (if_index == 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
|
||||
"interface index for '%s'",
|
||||
__func__, if_name);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
args[0] = BRCTL_ADD_IF;
|
||||
args[1] = if_index;
|
||||
|
||||
os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
|
||||
ifr.ifr_data = (void *) args;
|
||||
|
||||
if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
|
||||
if (errno == EBUSY) {
|
||||
/* The interface is already added. */
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
|
||||
"BRCTL_ADD_IF] failed for br_name=%s if_name=%s: "
|
||||
"%s", __func__, br_name, if_name, strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int br_delbr(const char *br_name)
|
||||
{
|
||||
int fd;
|
||||
unsigned long arg[2];
|
||||
|
||||
wpa_printf(MSG_DEBUG, "VLAN: br_delbr(%s)", br_name);
|
||||
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
|
||||
"failed: %s", __func__, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
arg[0] = BRCTL_DEL_BRIDGE;
|
||||
arg[1] = (unsigned long) br_name;
|
||||
|
||||
if (ioctl(fd, SIOCGIFBR, arg) < 0 && errno != ENXIO) {
|
||||
/* No error if bridge already removed. */
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_DEL_BRIDGE failed for "
|
||||
"%s: %s", __func__, br_name, strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Add a bridge with the name 'br_name'.
|
||||
|
||||
returns -1 on error
|
||||
returns 1 if the bridge already exists
|
||||
returns 0 otherwise
|
||||
*/
|
||||
static int br_addbr(const char *br_name)
|
||||
{
|
||||
int fd;
|
||||
unsigned long arg[4];
|
||||
struct ifreq ifr;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "VLAN: br_addbr(%s)", br_name);
|
||||
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
|
||||
"failed: %s", __func__, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
arg[0] = BRCTL_ADD_BRIDGE;
|
||||
arg[1] = (unsigned long) br_name;
|
||||
|
||||
if (ioctl(fd, SIOCGIFBR, arg) < 0) {
|
||||
if (errno == EEXIST) {
|
||||
/* The bridge is already added. */
|
||||
close(fd);
|
||||
return 1;
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_ADD_BRIDGE "
|
||||
"failed for %s: %s",
|
||||
__func__, br_name, strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Decrease forwarding delay to avoid EAPOL timeouts. */
|
||||
os_memset(&ifr, 0, sizeof(ifr));
|
||||
os_strlcpy(ifr.ifr_name, br_name, IFNAMSIZ);
|
||||
arg[0] = BRCTL_SET_BRIDGE_FORWARD_DELAY;
|
||||
arg[1] = 1;
|
||||
arg[2] = 0;
|
||||
arg[3] = 0;
|
||||
ifr.ifr_data = (char *) &arg;
|
||||
if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: "
|
||||
"BRCTL_SET_BRIDGE_FORWARD_DELAY (1 sec) failed for "
|
||||
"%s: %s", __func__, br_name, strerror(errno));
|
||||
/* Continue anyway */
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int br_getnumports(const char *br_name)
|
||||
{
|
||||
int fd;
|
||||
int i;
|
||||
int port_cnt = 0;
|
||||
unsigned long arg[4];
|
||||
int ifindices[MAX_BR_PORTS];
|
||||
struct ifreq ifr;
|
||||
|
||||
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
|
||||
"failed: %s", __func__, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
arg[0] = BRCTL_GET_PORT_LIST;
|
||||
arg[1] = (unsigned long) ifindices;
|
||||
arg[2] = MAX_BR_PORTS;
|
||||
arg[3] = 0;
|
||||
|
||||
os_memset(ifindices, 0, sizeof(ifindices));
|
||||
os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
|
||||
ifr.ifr_data = (void *) arg;
|
||||
|
||||
if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_GET_PORT_LIST "
|
||||
"failed for %s: %s",
|
||||
__func__, br_name, strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 1; i < MAX_BR_PORTS; i++) {
|
||||
if (ifindices[i] > 0) {
|
||||
port_cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return port_cnt;
|
||||
}
|
||||
|
||||
|
||||
static void vlan_newlink_tagged(int vlan_naming, const char *tagged_interface,
|
||||
const char *br_name, int vid,
|
||||
struct hostapd_data *hapd)
|
||||
{
|
||||
char vlan_ifname[IFNAMSIZ];
|
||||
int clean;
|
||||
|
||||
if (vlan_naming == DYNAMIC_VLAN_NAMING_WITH_DEVICE)
|
||||
os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s.%d",
|
||||
tagged_interface, vid);
|
||||
else
|
||||
os_snprintf(vlan_ifname, sizeof(vlan_ifname), "vlan%d", vid);
|
||||
|
||||
clean = 0;
|
||||
ifconfig_up(tagged_interface);
|
||||
if (!vlan_add(tagged_interface, vid, vlan_ifname))
|
||||
clean |= DVLAN_CLEAN_VLAN;
|
||||
|
||||
if (!br_addif(br_name, vlan_ifname))
|
||||
clean |= DVLAN_CLEAN_VLAN_PORT;
|
||||
|
||||
dyn_iface_get(hapd, vlan_ifname, clean);
|
||||
|
||||
ifconfig_up(vlan_ifname);
|
||||
}
|
||||
|
||||
|
||||
static void vlan_bridge_name(char *br_name, struct hostapd_data *hapd, int vid)
|
||||
{
|
||||
char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
|
||||
|
||||
if (hapd->conf->vlan_bridge[0]) {
|
||||
os_snprintf(br_name, IFNAMSIZ, "%s%d",
|
||||
hapd->conf->vlan_bridge, vid);
|
||||
} else if (tagged_interface) {
|
||||
os_snprintf(br_name, IFNAMSIZ, "br%s.%d",
|
||||
tagged_interface, vid);
|
||||
} else {
|
||||
os_snprintf(br_name, IFNAMSIZ, "brvlan%d", vid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void vlan_get_bridge(const char *br_name, struct hostapd_data *hapd,
|
||||
int vid)
|
||||
{
|
||||
char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
|
||||
int vlan_naming = hapd->conf->ssid.vlan_naming;
|
||||
|
||||
dyn_iface_get(hapd, br_name, br_addbr(br_name) ? 0 : DVLAN_CLEAN_BR);
|
||||
|
||||
ifconfig_up(br_name);
|
||||
|
||||
if (tagged_interface)
|
||||
vlan_newlink_tagged(vlan_naming, tagged_interface, br_name,
|
||||
vid, hapd);
|
||||
}
|
||||
|
||||
|
||||
void vlan_newlink(const char *ifname, struct hostapd_data *hapd)
|
||||
{
|
||||
char br_name[IFNAMSIZ];
|
||||
struct hostapd_vlan *vlan;
|
||||
int untagged, *tagged, i, notempty;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
|
||||
|
||||
for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
|
||||
if (vlan->configured ||
|
||||
os_strcmp(ifname, vlan->ifname) != 0)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
if (!vlan)
|
||||
return;
|
||||
|
||||
vlan->configured = 1;
|
||||
|
||||
notempty = vlan->vlan_desc.notempty;
|
||||
untagged = vlan->vlan_desc.untagged;
|
||||
tagged = vlan->vlan_desc.tagged;
|
||||
|
||||
if (!notempty) {
|
||||
/* Non-VLAN STA */
|
||||
if (hapd->conf->bridge[0] &&
|
||||
!br_addif(hapd->conf->bridge, ifname))
|
||||
vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
|
||||
} else if (untagged > 0 && untagged <= MAX_VLAN_ID) {
|
||||
vlan_bridge_name(br_name, hapd, untagged);
|
||||
|
||||
vlan_get_bridge(br_name, hapd, untagged);
|
||||
|
||||
if (!br_addif(br_name, ifname))
|
||||
vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_NUM_TAGGED_VLAN && tagged[i]; i++) {
|
||||
if (tagged[i] == untagged ||
|
||||
tagged[i] <= 0 || tagged[i] > MAX_VLAN_ID ||
|
||||
(i > 0 && tagged[i] == tagged[i - 1]))
|
||||
continue;
|
||||
vlan_bridge_name(br_name, hapd, tagged[i]);
|
||||
vlan_get_bridge(br_name, hapd, tagged[i]);
|
||||
vlan_newlink_tagged(DYNAMIC_VLAN_NAMING_WITH_DEVICE,
|
||||
ifname, br_name, tagged[i], hapd);
|
||||
}
|
||||
|
||||
ifconfig_up(ifname);
|
||||
}
|
||||
|
||||
|
||||
static void vlan_dellink_tagged(int vlan_naming, const char *tagged_interface,
|
||||
const char *br_name, int vid,
|
||||
struct hostapd_data *hapd)
|
||||
{
|
||||
char vlan_ifname[IFNAMSIZ];
|
||||
int clean;
|
||||
|
||||
if (vlan_naming == DYNAMIC_VLAN_NAMING_WITH_DEVICE)
|
||||
os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s.%d",
|
||||
tagged_interface, vid);
|
||||
else
|
||||
os_snprintf(vlan_ifname, sizeof(vlan_ifname), "vlan%d", vid);
|
||||
|
||||
clean = dyn_iface_put(hapd, vlan_ifname);
|
||||
|
||||
if (clean & DVLAN_CLEAN_VLAN_PORT)
|
||||
br_delif(br_name, vlan_ifname);
|
||||
|
||||
if (clean & DVLAN_CLEAN_VLAN) {
|
||||
ifconfig_down(vlan_ifname);
|
||||
vlan_rem(vlan_ifname);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void vlan_put_bridge(const char *br_name, struct hostapd_data *hapd,
|
||||
int vid)
|
||||
{
|
||||
int clean;
|
||||
char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
|
||||
int vlan_naming = hapd->conf->ssid.vlan_naming;
|
||||
|
||||
if (tagged_interface)
|
||||
vlan_dellink_tagged(vlan_naming, tagged_interface, br_name,
|
||||
vid, hapd);
|
||||
|
||||
clean = dyn_iface_put(hapd, br_name);
|
||||
if ((clean & DVLAN_CLEAN_BR) && br_getnumports(br_name) == 0) {
|
||||
ifconfig_down(br_name);
|
||||
br_delbr(br_name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void vlan_dellink(const char *ifname, struct hostapd_data *hapd)
|
||||
{
|
||||
struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname);
|
||||
|
||||
first = prev = vlan;
|
||||
|
||||
while (vlan) {
|
||||
if (os_strcmp(ifname, vlan->ifname) != 0) {
|
||||
prev = vlan;
|
||||
vlan = vlan->next;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!vlan)
|
||||
return;
|
||||
|
||||
if (vlan->configured) {
|
||||
int notempty = vlan->vlan_desc.notempty;
|
||||
int untagged = vlan->vlan_desc.untagged;
|
||||
int *tagged = vlan->vlan_desc.tagged;
|
||||
char br_name[IFNAMSIZ];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_NUM_TAGGED_VLAN && tagged[i]; i++) {
|
||||
if (tagged[i] == untagged ||
|
||||
tagged[i] <= 0 || tagged[i] > MAX_VLAN_ID ||
|
||||
(i > 0 && tagged[i] == tagged[i - 1]))
|
||||
continue;
|
||||
vlan_bridge_name(br_name, hapd, tagged[i]);
|
||||
vlan_dellink_tagged(DYNAMIC_VLAN_NAMING_WITH_DEVICE,
|
||||
ifname, br_name, tagged[i], hapd);
|
||||
vlan_put_bridge(br_name, hapd, tagged[i]);
|
||||
}
|
||||
|
||||
if (!notempty) {
|
||||
/* Non-VLAN STA */
|
||||
if (hapd->conf->bridge[0] &&
|
||||
(vlan->clean & DVLAN_CLEAN_WLAN_PORT))
|
||||
br_delif(hapd->conf->bridge, ifname);
|
||||
} else if (untagged > 0 && untagged <= MAX_VLAN_ID) {
|
||||
vlan_bridge_name(br_name, hapd, untagged);
|
||||
|
||||
if (vlan->clean & DVLAN_CLEAN_WLAN_PORT)
|
||||
br_delif(br_name, vlan->ifname);
|
||||
|
||||
vlan_put_bridge(br_name, hapd, untagged);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure this VLAN interface is actually removed even if
|
||||
* NEWLINK message is only received later.
|
||||
*/
|
||||
if (if_nametoindex(vlan->ifname) && vlan_if_remove(hapd, vlan))
|
||||
wpa_printf(MSG_ERROR,
|
||||
"VLAN: Could not remove VLAN iface: %s: %s",
|
||||
vlan->ifname, strerror(errno));
|
||||
|
||||
if (vlan == first)
|
||||
hapd->conf->vlan = vlan->next;
|
||||
else
|
||||
prev->next = vlan->next;
|
||||
|
||||
os_free(vlan);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del,
|
||||
struct hostapd_data *hapd)
|
||||
{
|
||||
struct ifinfomsg *ifi;
|
||||
int attrlen, nlmsg_len, rta_len;
|
||||
struct rtattr *attr;
|
||||
char ifname[IFNAMSIZ + 1];
|
||||
|
||||
if (len < sizeof(*ifi))
|
||||
return;
|
||||
|
||||
ifi = NLMSG_DATA(h);
|
||||
|
||||
nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
|
||||
|
||||
attrlen = h->nlmsg_len - nlmsg_len;
|
||||
if (attrlen < 0)
|
||||
return;
|
||||
|
||||
attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
|
||||
|
||||
os_memset(ifname, 0, sizeof(ifname));
|
||||
rta_len = RTA_ALIGN(sizeof(struct rtattr));
|
||||
while (RTA_OK(attr, attrlen)) {
|
||||
if (attr->rta_type == IFLA_IFNAME) {
|
||||
int n = attr->rta_len - rta_len;
|
||||
if (n < 0)
|
||||
break;
|
||||
|
||||
if ((size_t) n >= sizeof(ifname))
|
||||
n = sizeof(ifname) - 1;
|
||||
os_memcpy(ifname, ((char *) attr) + rta_len, n);
|
||||
|
||||
}
|
||||
|
||||
attr = RTA_NEXT(attr, attrlen);
|
||||
}
|
||||
|
||||
if (!ifname[0])
|
||||
return;
|
||||
if (del && if_nametoindex(ifname)) {
|
||||
/* interface still exists, race condition ->
|
||||
* iface has just been recreated */
|
||||
return;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"VLAN: RTM_%sLINK: ifi_index=%d ifname=%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
|
||||
del ? "DEL" : "NEW",
|
||||
ifi->ifi_index, ifname, ifi->ifi_family, ifi->ifi_flags,
|
||||
(ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
|
||||
(ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
|
||||
(ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
|
||||
(ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
|
||||
|
||||
if (del)
|
||||
vlan_dellink(ifname, hapd);
|
||||
else
|
||||
vlan_newlink(ifname, hapd);
|
||||
}
|
||||
|
||||
|
||||
static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx)
|
||||
{
|
||||
char buf[8192];
|
||||
int left;
|
||||
struct sockaddr_nl from;
|
||||
socklen_t fromlen;
|
||||
struct nlmsghdr *h;
|
||||
struct hostapd_data *hapd = eloop_ctx;
|
||||
|
||||
fromlen = sizeof(from);
|
||||
left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
|
||||
(struct sockaddr *) &from, &fromlen);
|
||||
if (left < 0) {
|
||||
if (errno != EINTR && errno != EAGAIN)
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: recvfrom failed: %s",
|
||||
__func__, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
h = (struct nlmsghdr *) buf;
|
||||
while (NLMSG_OK(h, left)) {
|
||||
int len, plen;
|
||||
|
||||
len = h->nlmsg_len;
|
||||
plen = len - sizeof(*h);
|
||||
if (len > left || plen < 0) {
|
||||
wpa_printf(MSG_DEBUG, "VLAN: Malformed netlink "
|
||||
"message: len=%d left=%d plen=%d",
|
||||
len, left, plen);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (h->nlmsg_type) {
|
||||
case RTM_NEWLINK:
|
||||
vlan_read_ifnames(h, plen, 0, hapd);
|
||||
break;
|
||||
case RTM_DELLINK:
|
||||
vlan_read_ifnames(h, plen, 1, hapd);
|
||||
break;
|
||||
}
|
||||
|
||||
h = NLMSG_NEXT(h, left);
|
||||
}
|
||||
|
||||
if (left > 0) {
|
||||
wpa_printf(MSG_DEBUG, "VLAN: %s: %d extra bytes in the end of "
|
||||
"netlink message", __func__, left);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct full_dynamic_vlan *
|
||||
full_dynamic_vlan_init(struct hostapd_data *hapd)
|
||||
{
|
||||
struct sockaddr_nl local;
|
||||
struct full_dynamic_vlan *priv;
|
||||
|
||||
priv = os_zalloc(sizeof(*priv));
|
||||
if (priv == NULL)
|
||||
return NULL;
|
||||
|
||||
vlan_set_name_type(hapd->conf->ssid.vlan_naming ==
|
||||
DYNAMIC_VLAN_NAMING_WITH_DEVICE ?
|
||||
VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD :
|
||||
VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
|
||||
|
||||
priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||
if (priv->s < 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: socket(PF_NETLINK,SOCK_RAW,"
|
||||
"NETLINK_ROUTE) failed: %s",
|
||||
__func__, strerror(errno));
|
||||
os_free(priv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
os_memset(&local, 0, sizeof(local));
|
||||
local.nl_family = AF_NETLINK;
|
||||
local.nl_groups = RTMGRP_LINK;
|
||||
if (bind(priv->s, (struct sockaddr *) &local, sizeof(local)) < 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: bind(netlink) failed: %s",
|
||||
__func__, strerror(errno));
|
||||
close(priv->s);
|
||||
os_free(priv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (eloop_register_read_sock(priv->s, vlan_event_receive, hapd, NULL))
|
||||
{
|
||||
close(priv->s);
|
||||
os_free(priv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return priv;
|
||||
}
|
||||
|
||||
|
||||
void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv)
|
||||
{
|
||||
if (priv == NULL)
|
||||
return;
|
||||
eloop_unregister_read_sock(priv->s);
|
||||
close(priv->s);
|
||||
os_free(priv);
|
||||
}
|
69
src/ap/vlan_ifconfig.c
Normal file
69
src/ap/vlan_ifconfig.c
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* hostapd / VLAN ifconfig helpers
|
||||
* Copyright 2003, Instant802 Networks, Inc.
|
||||
* Copyright 2005-2006, Devicescape Software, Inc.
|
||||
* Copyright (c) 2009, 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 <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "vlan_util.h"
|
||||
|
||||
|
||||
int ifconfig_helper(const char *if_name, int up)
|
||||
{
|
||||
int fd;
|
||||
struct ifreq ifr;
|
||||
|
||||
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
|
||||
"failed: %s", __func__, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memset(&ifr, 0, sizeof(ifr));
|
||||
os_strlcpy(ifr.ifr_name, if_name, IFNAMSIZ);
|
||||
|
||||
if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCGIFFLAGS) failed "
|
||||
"for interface %s: %s",
|
||||
__func__, if_name, strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (up)
|
||||
ifr.ifr_flags |= IFF_UP;
|
||||
else
|
||||
ifr.ifr_flags &= ~IFF_UP;
|
||||
|
||||
if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCSIFFLAGS) failed "
|
||||
"for interface %s (up=%d): %s",
|
||||
__func__, if_name, up, strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int ifconfig_up(const char *if_name)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "VLAN: Set interface %s up", if_name);
|
||||
return ifconfig_helper(if_name, 1);
|
||||
}
|
||||
|
||||
|
||||
int iface_exists(const char *ifname)
|
||||
{
|
||||
return if_nametoindex(ifname);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -15,10 +15,9 @@ int vlan_init(struct hostapd_data *hapd);
|
||||
void vlan_deinit(struct hostapd_data *hapd);
|
||||
struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
|
||||
struct hostapd_vlan *vlan,
|
||||
int vlan_id);
|
||||
int vlan_id,
|
||||
struct vlan_description *vlan_desc);
|
||||
int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id);
|
||||
int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
|
||||
const char *dyn_vlan);
|
||||
#else /* CONFIG_NO_VLAN */
|
||||
static inline int vlan_init(struct hostapd_data *hapd)
|
||||
{
|
||||
@ -29,9 +28,9 @@ static inline void vlan_deinit(struct hostapd_data *hapd)
|
||||
{
|
||||
}
|
||||
|
||||
static inline struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
|
||||
struct hostapd_vlan *vlan,
|
||||
int vlan_id)
|
||||
static inline struct hostapd_vlan *
|
||||
vlan_add_dynamic(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
|
||||
int vlan_id, struct vlan_description *vlan_desc)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
@ -40,12 +39,6 @@ static inline int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
|
||||
const char *dyn_vlan)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#endif /* CONFIG_NO_VLAN */
|
||||
|
||||
#endif /* VLAN_INIT_H */
|
||||
|
155
src/ap/vlan_ioctl.c
Normal file
155
src/ap/vlan_ioctl.c
Normal file
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* hostapd / VLAN ioctl API
|
||||
* Copyright 2003, Instant802 Networks, Inc.
|
||||
* Copyright 2005-2006, Devicescape Software, Inc.
|
||||
* Copyright (c) 2009, 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 <sys/ioctl.h>
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "common/linux_vlan.h"
|
||||
#include "vlan_util.h"
|
||||
|
||||
|
||||
int vlan_rem(const char *if_name)
|
||||
{
|
||||
int fd;
|
||||
struct vlan_ioctl_args if_request;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(%s)", if_name);
|
||||
if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
|
||||
if_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
|
||||
"failed: %s", __func__, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memset(&if_request, 0, sizeof(if_request));
|
||||
|
||||
os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
|
||||
if_request.cmd = DEL_VLAN_CMD;
|
||||
|
||||
if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: DEL_VLAN_CMD failed for %s: "
|
||||
"%s", __func__, if_name, strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Add a vlan interface with VLAN ID 'vid' and tagged interface
|
||||
'if_name'.
|
||||
|
||||
returns -1 on error
|
||||
returns 1 if the interface already exists
|
||||
returns 0 otherwise
|
||||
*/
|
||||
int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
|
||||
{
|
||||
int fd;
|
||||
struct vlan_ioctl_args if_request;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d)",
|
||||
if_name, vid);
|
||||
ifconfig_up(if_name);
|
||||
|
||||
if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
|
||||
if_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
|
||||
"failed: %s", __func__, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memset(&if_request, 0, sizeof(if_request));
|
||||
|
||||
/* Determine if a suitable vlan device already exists. */
|
||||
|
||||
os_snprintf(if_request.device1, sizeof(if_request.device1), "vlan%d",
|
||||
vid);
|
||||
|
||||
if_request.cmd = GET_VLAN_VID_CMD;
|
||||
|
||||
if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 &&
|
||||
if_request.u.VID == vid) {
|
||||
if_request.cmd = GET_VLAN_REALDEV_NAME_CMD;
|
||||
|
||||
if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 &&
|
||||
os_strncmp(if_request.u.device2, if_name,
|
||||
sizeof(if_request.u.device2)) == 0) {
|
||||
close(fd);
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"VLAN: vlan_add: if_name %s exists already",
|
||||
if_request.device1);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* A suitable vlan device does not already exist, add one. */
|
||||
|
||||
os_memset(&if_request, 0, sizeof(if_request));
|
||||
os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
|
||||
if_request.u.VID = vid;
|
||||
if_request.cmd = ADD_VLAN_CMD;
|
||||
|
||||
if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"VLAN: %s: ADD_VLAN_CMD failed for %s: %s",
|
||||
__func__, if_request.device1, strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int vlan_set_name_type(unsigned int name_type)
|
||||
{
|
||||
int fd;
|
||||
struct vlan_ioctl_args if_request;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "VLAN: vlan_set_name_type(name_type=%u)",
|
||||
name_type);
|
||||
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"VLAN: %s: socket(AF_INET,SOCK_STREAM) failed: %s",
|
||||
__func__, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memset(&if_request, 0, sizeof(if_request));
|
||||
|
||||
if_request.u.name_type = name_type;
|
||||
if_request.cmd = SET_VLAN_NAME_TYPE_CMD;
|
||||
if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"VLAN: %s: SET_VLAN_NAME_TYPE_CMD name_type=%u failed: %s",
|
||||
__func__, name_type, strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
@ -7,18 +7,10 @@
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <netlink/genl/genl.h>
|
||||
#include <netlink/genl/family.h>
|
||||
#include <netlink/genl/ctrl.h>
|
||||
#include <netlink/route/link.h>
|
||||
#include <netlink/route/link/vlan.h>
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "utils/eloop.h"
|
||||
#include "hostapd.h"
|
||||
#include "vlan_util.h"
|
||||
|
||||
/*
|
||||
@ -33,7 +25,6 @@ int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
|
||||
{
|
||||
int err, ret = -1;
|
||||
struct nl_sock *handle = NULL;
|
||||
struct nl_cache *cache = NULL;
|
||||
struct rtnl_link *rlink = NULL;
|
||||
int if_idx = 0;
|
||||
|
||||
@ -65,22 +56,19 @@ int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
|
||||
goto vlan_add_error;
|
||||
}
|
||||
|
||||
err = rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache);
|
||||
err = rtnl_link_get_kernel(handle, 0, if_name, &rlink);
|
||||
if (err < 0) {
|
||||
cache = NULL;
|
||||
wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache: %s",
|
||||
nl_geterror(err));
|
||||
goto vlan_add_error;
|
||||
}
|
||||
|
||||
if (!(if_idx = rtnl_link_name2i(cache, if_name))) {
|
||||
/* link does not exist */
|
||||
wpa_printf(MSG_ERROR, "VLAN: interface %s does not exist",
|
||||
if_name);
|
||||
goto vlan_add_error;
|
||||
}
|
||||
if_idx = rtnl_link_get_ifindex(rlink);
|
||||
rtnl_link_put(rlink);
|
||||
rlink = NULL;
|
||||
|
||||
if ((rlink = rtnl_link_get_by_name(cache, vlan_if_name))) {
|
||||
err = rtnl_link_get_kernel(handle, 0, vlan_if_name, &rlink);
|
||||
if (err >= 0) {
|
||||
/* link does exist */
|
||||
rtnl_link_put(rlink);
|
||||
rlink = NULL;
|
||||
@ -127,8 +115,6 @@ int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
|
||||
vlan_add_error:
|
||||
if (rlink)
|
||||
rtnl_link_put(rlink);
|
||||
if (cache)
|
||||
nl_cache_free(cache);
|
||||
if (handle)
|
||||
nl_socket_free(handle);
|
||||
return ret;
|
||||
@ -139,7 +125,6 @@ int vlan_rem(const char *if_name)
|
||||
{
|
||||
int err, ret = -1;
|
||||
struct nl_sock *handle = NULL;
|
||||
struct nl_cache *cache = NULL;
|
||||
struct rtnl_link *rlink = NULL;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(if_name=%s)", if_name);
|
||||
@ -157,15 +142,8 @@ int vlan_rem(const char *if_name)
|
||||
goto vlan_rem_error;
|
||||
}
|
||||
|
||||
err = rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache);
|
||||
err = rtnl_link_get_kernel(handle, 0, if_name, &rlink);
|
||||
if (err < 0) {
|
||||
cache = NULL;
|
||||
wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache: %s",
|
||||
nl_geterror(err));
|
||||
goto vlan_rem_error;
|
||||
}
|
||||
|
||||
if (!(rlink = rtnl_link_get_by_name(cache, if_name))) {
|
||||
/* link does not exist */
|
||||
wpa_printf(MSG_ERROR, "VLAN: interface %s does not exists",
|
||||
if_name);
|
||||
@ -184,9 +162,13 @@ int vlan_rem(const char *if_name)
|
||||
vlan_rem_error:
|
||||
if (rlink)
|
||||
rtnl_link_put(rlink);
|
||||
if (cache)
|
||||
nl_cache_free(cache);
|
||||
if (handle)
|
||||
nl_socket_free(handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int vlan_set_name_type(unsigned int name_type)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* hostapd / VLAN netlink api
|
||||
* hostapd / VLAN netlink/ioctl api
|
||||
* Copyright (c) 2012, Michael Braun <michael-dev@fami-braun.de>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
@ -9,7 +9,23 @@
|
||||
#ifndef VLAN_UTIL_H
|
||||
#define VLAN_UTIL_H
|
||||
|
||||
struct hostapd_data;
|
||||
struct hostapd_vlan;
|
||||
struct full_dynamic_vlan;
|
||||
|
||||
int vlan_add(const char *if_name, int vid, const char *vlan_if_name);
|
||||
int vlan_rem(const char *if_name);
|
||||
int vlan_set_name_type(unsigned int name_type);
|
||||
|
||||
int ifconfig_helper(const char *if_name, int up);
|
||||
int ifconfig_up(const char *if_name);
|
||||
int iface_exists(const char *ifname);
|
||||
int vlan_if_remove(struct hostapd_data *hapd, struct hostapd_vlan *vlan);
|
||||
|
||||
struct full_dynamic_vlan *
|
||||
full_dynamic_vlan_init(struct hostapd_data *hapd);
|
||||
void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv);
|
||||
void vlan_newlink(const char *ifname, struct hostapd_data *hapd);
|
||||
void vlan_dellink(const char *ifname, struct hostapd_data *hapd);
|
||||
|
||||
#endif /* VLAN_UTIL_H */
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "ap/ap_config.h"
|
||||
#include "ap/ap_drv_ops.h"
|
||||
#include "ap/wpa_auth.h"
|
||||
#include "mbo_ap.h"
|
||||
#include "wnm_ap.h"
|
||||
|
||||
#define MAX_TFS_IE_LEN 1024
|
||||
@ -94,6 +95,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
|
||||
if (mgmt == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
|
||||
"WNM-Sleep Response action frame");
|
||||
os_free(wnmtfs_ie);
|
||||
return -1;
|
||||
}
|
||||
os_memcpy(mgmt->da, addr, ETH_ALEN);
|
||||
@ -376,6 +378,29 @@ static void ieee802_11_rx_bss_trans_mgmt_resp(struct hostapd_data *hapd,
|
||||
}
|
||||
|
||||
|
||||
static void ieee802_11_rx_wnm_notification_req(struct hostapd_data *hapd,
|
||||
const u8 *addr, const u8 *buf,
|
||||
size_t len)
|
||||
{
|
||||
u8 dialog_token, type;
|
||||
|
||||
if (len < 2)
|
||||
return;
|
||||
dialog_token = *buf++;
|
||||
type = *buf++;
|
||||
len -= 2;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WNM: Received WNM Notification Request frame from "
|
||||
MACSTR " (dialog_token=%u type=%u)",
|
||||
MAC2STR(addr), dialog_token, type);
|
||||
wpa_hexdump(MSG_MSGDUMP, "WNM: Notification Request subelements",
|
||||
buf, len);
|
||||
if (type == WLAN_EID_VENDOR_SPECIFIC)
|
||||
mbo_ap_wnm_notification_req(hapd, addr, buf, len);
|
||||
}
|
||||
|
||||
|
||||
int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
|
||||
const struct ieee80211_mgmt *mgmt, size_t len)
|
||||
{
|
||||
@ -402,6 +427,10 @@ int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
|
||||
case WNM_SLEEP_MODE_REQ:
|
||||
ieee802_11_rx_wnmsleep_req(hapd, mgmt->sa, payload, plen);
|
||||
return 0;
|
||||
case WNM_NOTIFICATION_REQ:
|
||||
ieee802_11_rx_wnm_notification_req(hapd, mgmt->sa, payload,
|
||||
plen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "WNM: Unsupported WNM Action %u from " MACSTR,
|
||||
@ -527,7 +556,8 @@ int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
|
||||
int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
u8 req_mode, int disassoc_timer, u8 valid_int,
|
||||
const u8 *bss_term_dur, const char *url,
|
||||
const u8 *nei_rep, size_t nei_rep_len)
|
||||
const u8 *nei_rep, size_t nei_rep_len,
|
||||
const u8 *mbo_attrs, size_t mbo_len)
|
||||
{
|
||||
u8 *buf, *pos;
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
@ -536,7 +566,7 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to "
|
||||
MACSTR " req_mode=0x%x disassoc_timer=%d valid_int=0x%x",
|
||||
MAC2STR(sta->addr), req_mode, disassoc_timer, valid_int);
|
||||
buf = os_zalloc(1000 + nei_rep_len);
|
||||
buf = os_zalloc(1000 + nei_rep_len + mbo_len);
|
||||
if (buf == NULL)
|
||||
return -1;
|
||||
mgmt = (struct ieee80211_mgmt *) buf;
|
||||
@ -579,6 +609,11 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
pos += nei_rep_len;
|
||||
}
|
||||
|
||||
if (mbo_len > 0) {
|
||||
pos += mbo_add_ie(pos, buf + sizeof(buf) - pos, mbo_attrs,
|
||||
mbo_len);
|
||||
}
|
||||
|
||||
if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"Failed to send BSS Transition Management Request frame");
|
||||
|
@ -21,6 +21,7 @@ int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
|
||||
int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
|
||||
u8 req_mode, int disassoc_timer, u8 valid_int,
|
||||
const u8 *bss_term_dur, const char *url,
|
||||
const u8 *nei_rep, size_t nei_rep_len);
|
||||
const u8 *nei_rep, size_t nei_rep_len,
|
||||
const u8 *mbo_attrs, size_t mbo_len);
|
||||
|
||||
#endif /* WNM_AP_H */
|
||||
|
@ -44,7 +44,8 @@ static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
|
||||
static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_group *group);
|
||||
static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
|
||||
const u8 *pmk, struct wpa_ptk *ptk);
|
||||
const u8 *pmk, unsigned int pmk_len,
|
||||
struct wpa_ptk *ptk);
|
||||
static void wpa_group_free(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_group *group);
|
||||
static void wpa_group_get(struct wpa_authenticator *wpa_auth,
|
||||
@ -827,6 +828,7 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
|
||||
struct wpa_ptk PTK;
|
||||
int ok = 0;
|
||||
const u8 *pmk = NULL;
|
||||
unsigned int pmk_len;
|
||||
|
||||
for (;;) {
|
||||
if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
|
||||
@ -834,10 +836,13 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
|
||||
sm->p2p_dev_addr, pmk);
|
||||
if (pmk == NULL)
|
||||
break;
|
||||
} else
|
||||
pmk_len = PMK_LEN;
|
||||
} else {
|
||||
pmk = sm->PMK;
|
||||
pmk_len = sm->pmk_len;
|
||||
}
|
||||
|
||||
wpa_derive_ptk(sm, sm->alt_SNonce, pmk, &PTK);
|
||||
wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK);
|
||||
|
||||
if (wpa_verify_key_mic(sm->wpa_key_mgmt, &PTK, data, data_len)
|
||||
== 0) {
|
||||
@ -1904,11 +1909,27 @@ SM_STATE(WPA_PTK, INITPMK)
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
if (sm->pmksa) {
|
||||
wpa_printf(MSG_DEBUG, "WPA: PMK from PMKSA cache");
|
||||
os_memcpy(sm->PMK, sm->pmksa->pmk, PMK_LEN);
|
||||
os_memcpy(sm->PMK, sm->pmksa->pmk, sm->pmksa->pmk_len);
|
||||
sm->pmk_len = sm->pmksa->pmk_len;
|
||||
} else if (wpa_auth_get_msk(sm->wpa_auth, sm->addr, msk, &len) == 0) {
|
||||
unsigned int pmk_len;
|
||||
|
||||
if (sm->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
|
||||
pmk_len = PMK_LEN_SUITE_B_192;
|
||||
else
|
||||
pmk_len = PMK_LEN;
|
||||
wpa_printf(MSG_DEBUG, "WPA: PMK from EAPOL state machine "
|
||||
"(len=%lu)", (unsigned long) len);
|
||||
os_memcpy(sm->PMK, msk, PMK_LEN);
|
||||
"(MSK len=%lu PMK len=%u)", (unsigned long) len,
|
||||
pmk_len);
|
||||
if (len < pmk_len) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WPA: MSK not long enough (%u) to create PMK (%u)",
|
||||
(unsigned int) len, (unsigned int) pmk_len);
|
||||
sm->Disconnect = TRUE;
|
||||
return;
|
||||
}
|
||||
os_memcpy(sm->PMK, msk, pmk_len);
|
||||
sm->pmk_len = pmk_len;
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
if (len >= 2 * PMK_LEN) {
|
||||
os_memcpy(sm->xxkey, msk + PMK_LEN, PMK_LEN);
|
||||
@ -1943,6 +1964,7 @@ SM_STATE(WPA_PTK, INITPSK)
|
||||
psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr, NULL);
|
||||
if (psk) {
|
||||
os_memcpy(sm->PMK, psk, PMK_LEN);
|
||||
sm->pmk_len = PMK_LEN;
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
os_memcpy(sm->xxkey, psk, PMK_LEN);
|
||||
sm->xxkey_len = PMK_LEN;
|
||||
@ -1994,7 +2016,7 @@ SM_STATE(WPA_PTK, PTKSTART)
|
||||
* Calculate PMKID since no PMKSA cache entry was
|
||||
* available with pre-calculated PMKID.
|
||||
*/
|
||||
rsn_pmkid(sm->PMK, PMK_LEN, sm->wpa_auth->addr,
|
||||
rsn_pmkid(sm->PMK, sm->pmk_len, sm->wpa_auth->addr,
|
||||
sm->addr, &pmkid[2 + RSN_SELECTOR_LEN],
|
||||
wpa_key_mgmt_sha256(sm->wpa_key_mgmt));
|
||||
}
|
||||
@ -2006,14 +2028,15 @@ SM_STATE(WPA_PTK, PTKSTART)
|
||||
|
||||
|
||||
static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
|
||||
const u8 *pmk, struct wpa_ptk *ptk)
|
||||
const u8 *pmk, unsigned int pmk_len,
|
||||
struct wpa_ptk *ptk)
|
||||
{
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
|
||||
return wpa_auth_derive_ptk_ft(sm, pmk, ptk);
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
|
||||
return wpa_pmk_to_ptk(pmk, PMK_LEN, "Pairwise key expansion",
|
||||
return wpa_pmk_to_ptk(pmk, pmk_len, "Pairwise key expansion",
|
||||
sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce,
|
||||
ptk, sm->wpa_key_mgmt, sm->pairwise);
|
||||
}
|
||||
@ -2024,6 +2047,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
|
||||
struct wpa_ptk PTK;
|
||||
int ok = 0, psk_found = 0;
|
||||
const u8 *pmk = NULL;
|
||||
unsigned int pmk_len;
|
||||
|
||||
SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
|
||||
sm->EAPOLKeyReceived = FALSE;
|
||||
@ -2039,10 +2063,13 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
|
||||
if (pmk == NULL)
|
||||
break;
|
||||
psk_found = 1;
|
||||
} else
|
||||
pmk_len = PMK_LEN;
|
||||
} else {
|
||||
pmk = sm->PMK;
|
||||
pmk_len = sm->pmk_len;
|
||||
}
|
||||
|
||||
wpa_derive_ptk(sm, sm->SNonce, pmk, &PTK);
|
||||
wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK);
|
||||
|
||||
if (wpa_verify_key_mic(sm->wpa_key_mgmt, &PTK,
|
||||
sm->last_rx_eapol_key,
|
||||
@ -2092,6 +2119,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
|
||||
* state machine data based on whatever PSK was selected here.
|
||||
*/
|
||||
os_memcpy(sm->PMK, pmk, PMK_LEN);
|
||||
sm->pmk_len = PMK_LEN;
|
||||
}
|
||||
|
||||
sm->MICVerified = TRUE;
|
||||
@ -2270,14 +2298,19 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
|
||||
pos += wpa_ie_len;
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
|
||||
int res = wpa_insert_pmkid(kde, pos - kde, sm->pmk_r1_name);
|
||||
int res;
|
||||
size_t elen;
|
||||
|
||||
elen = pos - kde;
|
||||
res = wpa_insert_pmkid(kde, &elen, sm->pmk_r1_name);
|
||||
if (res < 0) {
|
||||
wpa_printf(MSG_ERROR, "FT: Failed to insert "
|
||||
"PMKR1Name into RSN IE in EAPOL-Key data");
|
||||
os_free(kde);
|
||||
return;
|
||||
}
|
||||
pos += res;
|
||||
pos -= wpa_ie_len;
|
||||
pos += elen;
|
||||
}
|
||||
#endif /* CONFIG_IEEE80211R */
|
||||
if (gtk) {
|
||||
@ -2295,10 +2328,18 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
|
||||
struct wpa_auth_config *conf;
|
||||
|
||||
conf = &sm->wpa_auth->conf;
|
||||
res = wpa_write_ftie(conf, conf->r0_key_holder,
|
||||
conf->r0_key_holder_len,
|
||||
NULL, NULL, pos, kde + kde_len - pos,
|
||||
NULL, 0);
|
||||
if (sm->assoc_resp_ftie &&
|
||||
kde + kde_len - pos >= 2 + sm->assoc_resp_ftie[1]) {
|
||||
os_memcpy(pos, sm->assoc_resp_ftie,
|
||||
2 + sm->assoc_resp_ftie[1]);
|
||||
res = 2 + sm->assoc_resp_ftie[1];
|
||||
} else {
|
||||
res = wpa_write_ftie(conf, conf->r0_key_holder,
|
||||
conf->r0_key_holder_len,
|
||||
NULL, NULL, pos,
|
||||
kde + kde_len - pos,
|
||||
NULL, 0);
|
||||
}
|
||||
if (res < 0) {
|
||||
wpa_printf(MSG_ERROR, "FT: Failed to insert FTIE "
|
||||
"into EAPOL-Key Key Data");
|
||||
@ -3243,13 +3284,21 @@ const u8 * wpa_auth_get_wpa_ie(struct wpa_authenticator *wpa_auth, size_t *len)
|
||||
|
||||
|
||||
int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
|
||||
unsigned int pmk_len,
|
||||
int session_timeout, struct eapol_state_machine *eapol)
|
||||
{
|
||||
if (sm == NULL || sm->wpa != WPA_VERSION_WPA2 ||
|
||||
sm->wpa_auth->conf.disable_pmksa_caching)
|
||||
return -1;
|
||||
|
||||
if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, PMK_LEN,
|
||||
if (sm->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
|
||||
if (pmk_len > PMK_LEN_SUITE_B_192)
|
||||
pmk_len = PMK_LEN_SUITE_B_192;
|
||||
} else if (pmk_len > PMK_LEN) {
|
||||
pmk_len = PMK_LEN;
|
||||
}
|
||||
|
||||
if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, pmk_len, NULL,
|
||||
sm->PTK.kck, sm->PTK.kck_len,
|
||||
sm->wpa_auth->addr, sm->addr, session_timeout,
|
||||
eapol, sm->wpa_key_mgmt))
|
||||
@ -3267,7 +3316,7 @@ int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
|
||||
if (wpa_auth == NULL)
|
||||
return -1;
|
||||
|
||||
if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, len,
|
||||
if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, len, NULL,
|
||||
NULL, 0,
|
||||
wpa_auth->addr,
|
||||
sta_addr, session_timeout, eapol,
|
||||
@ -3279,12 +3328,12 @@ int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
|
||||
|
||||
|
||||
int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr,
|
||||
const u8 *pmk)
|
||||
const u8 *pmk, const u8 *pmkid)
|
||||
{
|
||||
if (wpa_auth->conf.disable_pmksa_caching)
|
||||
return -1;
|
||||
|
||||
if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, PMK_LEN,
|
||||
if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, PMK_LEN, pmkid,
|
||||
NULL, 0,
|
||||
wpa_auth->addr, addr, 0, NULL,
|
||||
WPA_KEY_MGMT_SAE))
|
||||
@ -3310,6 +3359,46 @@ void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
|
||||
}
|
||||
|
||||
|
||||
int wpa_auth_pmksa_list(struct wpa_authenticator *wpa_auth, char *buf,
|
||||
size_t len)
|
||||
{
|
||||
if (!wpa_auth || !wpa_auth->pmksa)
|
||||
return 0;
|
||||
return pmksa_cache_auth_list(wpa_auth->pmksa, buf, len);
|
||||
}
|
||||
|
||||
|
||||
void wpa_auth_pmksa_flush(struct wpa_authenticator *wpa_auth)
|
||||
{
|
||||
if (wpa_auth && wpa_auth->pmksa)
|
||||
pmksa_cache_auth_flush(wpa_auth->pmksa);
|
||||
}
|
||||
|
||||
|
||||
struct rsn_pmksa_cache_entry *
|
||||
wpa_auth_pmksa_get(struct wpa_authenticator *wpa_auth, const u8 *sta_addr)
|
||||
{
|
||||
if (!wpa_auth || !wpa_auth->pmksa)
|
||||
return NULL;
|
||||
return pmksa_cache_auth_get(wpa_auth->pmksa, sta_addr, NULL);
|
||||
}
|
||||
|
||||
|
||||
void wpa_auth_pmksa_set_to_sm(struct rsn_pmksa_cache_entry *pmksa,
|
||||
struct wpa_state_machine *sm,
|
||||
struct wpa_authenticator *wpa_auth,
|
||||
u8 *pmkid, u8 *pmk)
|
||||
{
|
||||
if (!sm)
|
||||
return;
|
||||
|
||||
sm->pmksa = pmksa;
|
||||
os_memcpy(pmk, pmksa->pmk, PMK_LEN);
|
||||
os_memcpy(pmkid, pmksa->pmkid, PMKID_LEN);
|
||||
os_memcpy(wpa_auth->dot11RSNAPMKIDUsed, pmksa->pmkid, PMKID_LEN);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Remove and free the group from wpa_authenticator. This is triggered by a
|
||||
* callback to make sure nobody is currently iterating the group list while it
|
||||
@ -3388,6 +3477,98 @@ wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Enforce that the group state machine for the VLAN is running, increase
|
||||
* reference counter as interface is up. References might have been increased
|
||||
* even if a negative value is returned.
|
||||
* Returns: -1 on error (group missing, group already failed); otherwise, 0
|
||||
*/
|
||||
int wpa_auth_ensure_group(struct wpa_authenticator *wpa_auth, int vlan_id)
|
||||
{
|
||||
struct wpa_group *group;
|
||||
|
||||
if (wpa_auth == NULL)
|
||||
return 0;
|
||||
|
||||
group = wpa_auth->group;
|
||||
while (group) {
|
||||
if (group->vlan_id == vlan_id)
|
||||
break;
|
||||
group = group->next;
|
||||
}
|
||||
|
||||
if (group == NULL) {
|
||||
group = wpa_auth_add_group(wpa_auth, vlan_id);
|
||||
if (group == NULL)
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WPA: Ensure group state machine running for VLAN ID %d",
|
||||
vlan_id);
|
||||
|
||||
wpa_group_get(wpa_auth, group);
|
||||
group->num_setup_iface++;
|
||||
|
||||
if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Decrease reference counter, expected to be zero afterwards.
|
||||
* returns: -1 on error (group not found, group in fail state)
|
||||
* -2 if wpa_group is still referenced
|
||||
* 0 else
|
||||
*/
|
||||
int wpa_auth_release_group(struct wpa_authenticator *wpa_auth, int vlan_id)
|
||||
{
|
||||
struct wpa_group *group;
|
||||
int ret = 0;
|
||||
|
||||
if (wpa_auth == NULL)
|
||||
return 0;
|
||||
|
||||
group = wpa_auth->group;
|
||||
while (group) {
|
||||
if (group->vlan_id == vlan_id)
|
||||
break;
|
||||
group = group->next;
|
||||
}
|
||||
|
||||
if (group == NULL)
|
||||
return -1;
|
||||
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WPA: Try stopping group state machine for VLAN ID %d",
|
||||
vlan_id);
|
||||
|
||||
if (group->num_setup_iface <= 0) {
|
||||
wpa_printf(MSG_ERROR,
|
||||
"WPA: wpa_auth_release_group called more often than wpa_auth_ensure_group for VLAN ID %d, skipping.",
|
||||
vlan_id);
|
||||
return -1;
|
||||
}
|
||||
group->num_setup_iface--;
|
||||
|
||||
if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE)
|
||||
ret = -1;
|
||||
|
||||
if (group->references > 1) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"WPA: Cannot stop group state machine for VLAN ID %d as references are still hold",
|
||||
vlan_id);
|
||||
ret = -2;
|
||||
}
|
||||
|
||||
wpa_group_put(wpa_auth, group);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id)
|
||||
{
|
||||
struct wpa_group *group;
|
||||
|
@ -42,10 +42,11 @@ struct ft_rrb_frame {
|
||||
#define FT_PACKET_R0KH_R1KH_RESP 201
|
||||
#define FT_PACKET_R0KH_R1KH_PUSH 202
|
||||
|
||||
#define FT_R0KH_R1KH_PULL_DATA_LEN 44
|
||||
#define FT_R0KH_R1KH_RESP_DATA_LEN 76
|
||||
#define FT_R0KH_R1KH_PUSH_DATA_LEN 88
|
||||
#define FT_R0KH_R1KH_PULL_NONCE_LEN 16
|
||||
#define FT_R0KH_R1KH_PULL_DATA_LEN (FT_R0KH_R1KH_PULL_NONCE_LEN + \
|
||||
WPA_PMK_NAME_LEN + FT_R1KH_ID_LEN + \
|
||||
ETH_ALEN)
|
||||
#define FT_R0KH_R1KH_PULL_PAD_LEN ((8 - FT_R0KH_R1KH_PULL_DATA_LEN % 8) % 8)
|
||||
|
||||
struct ft_r0kh_r1kh_pull_frame {
|
||||
u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
|
||||
@ -57,14 +58,18 @@ struct ft_r0kh_r1kh_pull_frame {
|
||||
u8 pmk_r0_name[WPA_PMK_NAME_LEN];
|
||||
u8 r1kh_id[FT_R1KH_ID_LEN];
|
||||
u8 s1kh_id[ETH_ALEN];
|
||||
u8 pad[4]; /* 8-octet boundary for AES key wrap */
|
||||
u8 pad[FT_R0KH_R1KH_PULL_PAD_LEN]; /* 8-octet boundary for AES block */
|
||||
u8 key_wrap_extra[8];
|
||||
} STRUCT_PACKED;
|
||||
|
||||
#define FT_R0KH_R1KH_RESP_DATA_LEN (FT_R0KH_R1KH_PULL_NONCE_LEN + \
|
||||
FT_R1KH_ID_LEN + ETH_ALEN + PMK_LEN + \
|
||||
WPA_PMK_NAME_LEN + 2)
|
||||
#define FT_R0KH_R1KH_RESP_PAD_LEN ((8 - FT_R0KH_R1KH_RESP_DATA_LEN % 8) % 8)
|
||||
struct ft_r0kh_r1kh_resp_frame {
|
||||
u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
|
||||
u8 packet_type; /* FT_PACKET_R0KH_R1KH_RESP */
|
||||
le16 data_length; /* little endian length of data (76) */
|
||||
le16 data_length; /* little endian length of data (78) */
|
||||
u8 ap_address[ETH_ALEN];
|
||||
|
||||
u8 nonce[FT_R0KH_R1KH_PULL_NONCE_LEN]; /* copied from pull */
|
||||
@ -73,14 +78,18 @@ struct ft_r0kh_r1kh_resp_frame {
|
||||
u8 pmk_r1[PMK_LEN];
|
||||
u8 pmk_r1_name[WPA_PMK_NAME_LEN];
|
||||
le16 pairwise;
|
||||
u8 pad[2]; /* 8-octet boundary for AES key wrap */
|
||||
u8 pad[FT_R0KH_R1KH_RESP_PAD_LEN]; /* 8-octet boundary for AES block */
|
||||
u8 key_wrap_extra[8];
|
||||
} STRUCT_PACKED;
|
||||
|
||||
#define FT_R0KH_R1KH_PUSH_DATA_LEN (4 + FT_R1KH_ID_LEN + ETH_ALEN + \
|
||||
WPA_PMK_NAME_LEN + PMK_LEN + \
|
||||
WPA_PMK_NAME_LEN + 2)
|
||||
#define FT_R0KH_R1KH_PUSH_PAD_LEN ((8 - FT_R0KH_R1KH_PUSH_DATA_LEN % 8) % 8)
|
||||
struct ft_r0kh_r1kh_push_frame {
|
||||
u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
|
||||
u8 packet_type; /* FT_PACKET_R0KH_R1KH_PUSH */
|
||||
le16 data_length; /* little endian length of data (88) */
|
||||
le16 data_length; /* little endian length of data (82) */
|
||||
u8 ap_address[ETH_ALEN];
|
||||
|
||||
/* Encrypted with AES key-wrap */
|
||||
@ -92,7 +101,7 @@ struct ft_r0kh_r1kh_push_frame {
|
||||
u8 pmk_r1[PMK_LEN];
|
||||
u8 pmk_r1_name[WPA_PMK_NAME_LEN];
|
||||
le16 pairwise;
|
||||
u8 pad[6]; /* 8-octet boundary for AES key wrap */
|
||||
u8 pad[FT_R0KH_R1KH_PUSH_PAD_LEN]; /* 8-octet boundary for AES block */
|
||||
u8 key_wrap_extra[8];
|
||||
} STRUCT_PACKED;
|
||||
|
||||
@ -279,15 +288,25 @@ void wpa_auth_sta_local_mic_failure_report(struct wpa_state_machine *sm);
|
||||
const u8 * wpa_auth_get_wpa_ie(struct wpa_authenticator *wpa_auth,
|
||||
size_t *len);
|
||||
int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
|
||||
unsigned int pmk_len,
|
||||
int session_timeout, struct eapol_state_machine *eapol);
|
||||
int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
|
||||
const u8 *pmk, size_t len, const u8 *sta_addr,
|
||||
int session_timeout,
|
||||
struct eapol_state_machine *eapol);
|
||||
int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr,
|
||||
const u8 *pmk);
|
||||
const u8 *pmk, const u8 *pmkid);
|
||||
void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
|
||||
const u8 *sta_addr);
|
||||
int wpa_auth_pmksa_list(struct wpa_authenticator *wpa_auth, char *buf,
|
||||
size_t len);
|
||||
void wpa_auth_pmksa_flush(struct wpa_authenticator *wpa_auth);
|
||||
struct rsn_pmksa_cache_entry *
|
||||
wpa_auth_pmksa_get(struct wpa_authenticator *wpa_auth, const u8 *sta_addr);
|
||||
void wpa_auth_pmksa_set_to_sm(struct rsn_pmksa_cache_entry *pmksa,
|
||||
struct wpa_state_machine *sm,
|
||||
struct wpa_authenticator *wpa_auth,
|
||||
u8 *pmkid, u8 *pmk);
|
||||
int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id);
|
||||
void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_state_machine *sm, int ack);
|
||||
@ -325,4 +344,7 @@ int wpa_auth_radius_das_disconnect_pmksa(struct wpa_authenticator *wpa_auth,
|
||||
struct radius_das_attrs *attr);
|
||||
void wpa_auth_reconfig_group_keys(struct wpa_authenticator *wpa_auth);
|
||||
|
||||
int wpa_auth_ensure_group(struct wpa_authenticator *wpa_auth, int vlan_id);
|
||||
int wpa_auth_release_group(struct wpa_authenticator *wpa_auth, int vlan_id);
|
||||
|
||||
#endif /* WPA_AUTH_H */
|
||||
|
@ -720,11 +720,6 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
|
||||
ftie_len = res;
|
||||
pos += res;
|
||||
|
||||
os_free(sm->assoc_resp_ftie);
|
||||
sm->assoc_resp_ftie = os_malloc(ftie_len);
|
||||
if (sm->assoc_resp_ftie)
|
||||
os_memcpy(sm->assoc_resp_ftie, ftie, ftie_len);
|
||||
|
||||
_ftie = (struct rsn_ftie *) (ftie + 2);
|
||||
if (auth_alg == WLAN_AUTH_FT)
|
||||
_ftie->mic_control[1] = 3; /* Information element count */
|
||||
@ -750,6 +745,11 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
|
||||
_ftie->mic) < 0)
|
||||
wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
|
||||
|
||||
os_free(sm->assoc_resp_ftie);
|
||||
sm->assoc_resp_ftie = os_malloc(ftie_len);
|
||||
if (sm->assoc_resp_ftie)
|
||||
os_memcpy(sm->assoc_resp_ftie, ftie, ftie_len);
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "common/ieee802_11_defs.h"
|
||||
#include "common/sae.h"
|
||||
#include "common/wpa_ctrl.h"
|
||||
#include "crypto/sha1.h"
|
||||
#include "eapol_auth/eapol_auth_sm.h"
|
||||
#include "eapol_auth/eapol_auth_sm_i.h"
|
||||
#include "eap_server/eap.h"
|
||||
@ -246,6 +247,13 @@ static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr,
|
||||
struct hostapd_sta_wpa_psk_short *pos;
|
||||
psk = sta->psk->psk;
|
||||
for (pos = sta->psk; pos; pos = pos->next) {
|
||||
if (pos->is_passphrase) {
|
||||
pbkdf2_sha1(pos->passphrase,
|
||||
hapd->conf->ssid.ssid,
|
||||
hapd->conf->ssid.ssid_len, 4096,
|
||||
pos->psk, PMK_LEN);
|
||||
pos->is_passphrase = 0;
|
||||
}
|
||||
if (pos->psk == prev_psk) {
|
||||
psk = pos->next ? pos->next->psk : NULL;
|
||||
break;
|
||||
@ -413,6 +421,8 @@ static int hostapd_wpa_auth_ft_iter(struct hostapd_iface *iface, void *ctx)
|
||||
hapd = iface->bss[j];
|
||||
if (hapd == idata->src_hapd)
|
||||
continue;
|
||||
if (!hapd->wpa_auth)
|
||||
continue;
|
||||
if (os_memcmp(hapd->own_addr, idata->dst, ETH_ALEN) == 0) {
|
||||
wpa_printf(MSG_DEBUG, "FT: Send RRB data directly to "
|
||||
"locally managed BSS " MACSTR "@%s -> "
|
||||
@ -563,6 +573,9 @@ static void hostapd_rrb_receive(void *ctx, const u8 *src_addr, const u8 *buf,
|
||||
ethhdr = (struct l2_ethhdr *) buf;
|
||||
wpa_printf(MSG_DEBUG, "FT: RRB received packet " MACSTR " -> "
|
||||
MACSTR, MAC2STR(ethhdr->h_source), MAC2STR(ethhdr->h_dest));
|
||||
if (!is_multicast_ether_addr(ethhdr->h_dest) &&
|
||||
os_memcmp(hapd->own_addr, ethhdr->h_dest, ETH_ALEN) != 0)
|
||||
return;
|
||||
wpa_ft_rrb_rx(hapd->wpa_auth, ethhdr->h_source, buf + sizeof(*ethhdr),
|
||||
len - sizeof(*ethhdr));
|
||||
}
|
||||
@ -637,7 +650,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IEEE80211R
|
||||
if (!hostapd_drv_none(hapd) && hapd->conf->ft_over_ds &&
|
||||
if (!hostapd_drv_none(hapd) &&
|
||||
wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt)) {
|
||||
hapd->l2 = l2_packet_init(hapd->conf->bridge[0] ?
|
||||
hapd->conf->bridge :
|
||||
@ -674,13 +687,14 @@ void hostapd_deinit_wpa(struct hostapd_data *hapd)
|
||||
wpa_deinit(hapd->wpa_auth);
|
||||
hapd->wpa_auth = NULL;
|
||||
|
||||
if (hostapd_set_privacy(hapd, 0)) {
|
||||
if (hapd->drv_priv && hostapd_set_privacy(hapd, 0)) {
|
||||
wpa_printf(MSG_DEBUG, "Could not disable "
|
||||
"PrivacyInvoked for interface %s",
|
||||
hapd->conf->iface);
|
||||
}
|
||||
|
||||
if (hostapd_set_generic_elem(hapd, (u8 *) "", 0)) {
|
||||
if (hapd->drv_priv &&
|
||||
hostapd_set_generic_elem(hapd, (u8 *) "", 0)) {
|
||||
wpa_printf(MSG_DEBUG, "Could not remove generic "
|
||||
"information element from interface %s",
|
||||
hapd->conf->iface);
|
||||
|
@ -60,7 +60,8 @@ struct wpa_state_machine {
|
||||
u8 SNonce[WPA_NONCE_LEN];
|
||||
u8 alt_SNonce[WPA_NONCE_LEN];
|
||||
u8 alt_replay_counter[WPA_REPLAY_COUNTER_LEN];
|
||||
u8 PMK[PMK_LEN];
|
||||
u8 PMK[PMK_LEN_MAX];
|
||||
unsigned int pmk_len;
|
||||
struct wpa_ptk PTK;
|
||||
Boolean PTK_valid;
|
||||
Boolean pairwise_set;
|
||||
@ -171,6 +172,7 @@ struct wpa_group {
|
||||
#endif /* CONFIG_IEEE80211W */
|
||||
/* Number of references except those in struct wpa_group->next */
|
||||
unsigned int references;
|
||||
unsigned int num_setup_iface;
|
||||
};
|
||||
|
||||
|
||||
|
@ -251,7 +251,7 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
|
||||
pos += 2;
|
||||
|
||||
if (pmkid) {
|
||||
if (pos + 2 + PMKID_LEN > buf + len)
|
||||
if (2 + PMKID_LEN > buf + len - pos)
|
||||
return -1;
|
||||
/* PMKID Count */
|
||||
WPA_PUT_LE16(pos, 1);
|
||||
@ -263,7 +263,7 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
|
||||
#ifdef CONFIG_IEEE80211W
|
||||
if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION &&
|
||||
conf->group_mgmt_cipher != WPA_CIPHER_AES_128_CMAC) {
|
||||
if (pos + 2 + 4 > buf + len)
|
||||
if (2 + 4 > buf + len - pos)
|
||||
return -1;
|
||||
if (pmkid == NULL) {
|
||||
/* PMKID Count */
|
||||
@ -712,11 +712,14 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
|
||||
}
|
||||
}
|
||||
if (sm->pmksa && pmkid) {
|
||||
struct vlan_description *vlan;
|
||||
|
||||
vlan = sm->pmksa->vlan_desc;
|
||||
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
|
||||
"PMKID found from PMKSA cache "
|
||||
"eap_type=%d vlan_id=%d",
|
||||
"PMKID found from PMKSA cache eap_type=%d vlan=%d%s",
|
||||
sm->pmksa->eap_type_authsrv,
|
||||
sm->pmksa->vlan_id);
|
||||
vlan ? vlan->untagged : 0,
|
||||
(vlan && vlan->tagged[0]) ? "+" : "");
|
||||
os_memcpy(wpa_auth->dot11RSNAPMKIDUsed, pmkid, PMKID_LEN);
|
||||
}
|
||||
|
||||
@ -791,7 +794,7 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pos + 1 + RSN_SELECTOR_LEN < end &&
|
||||
if (1 + RSN_SELECTOR_LEN < end - pos &&
|
||||
pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
|
||||
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
|
||||
ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
|
||||
@ -887,13 +890,13 @@ int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
|
||||
int ret = 0;
|
||||
|
||||
os_memset(ie, 0, sizeof(*ie));
|
||||
for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) {
|
||||
for (pos = buf, end = pos + len; end - pos > 1; pos += 2 + pos[1]) {
|
||||
if (pos[0] == 0xdd &&
|
||||
((pos == buf + len - 1) || pos[1] == 0)) {
|
||||
/* Ignore padding */
|
||||
break;
|
||||
}
|
||||
if (pos + 2 + pos[1] > end) {
|
||||
if (2 + pos[1] > end - pos) {
|
||||
wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
|
||||
"underflow (ie=%d len=%d pos=%d)",
|
||||
pos[0], pos[1], (int) (pos - buf));
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* hostapd / WPS integration
|
||||
* Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2008-2016, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -269,12 +269,6 @@ static void hostapd_wps_enrollee_seen_cb(void *ctx, const u8 *addr,
|
||||
}
|
||||
|
||||
|
||||
static int str_starts(const char *str, const char *start)
|
||||
{
|
||||
return os_strncmp(str, start, os_strlen(start)) == 0;
|
||||
}
|
||||
|
||||
|
||||
static void wps_reload_config(void *eloop_data, void *user_ctx)
|
||||
{
|
||||
struct hostapd_iface *iface = eloop_data;
|
||||
@ -445,6 +439,8 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
|
||||
os_memcpy(hapd->wps->ssid, cred->ssid, cred->ssid_len);
|
||||
hapd->wps->ssid_len = cred->ssid_len;
|
||||
hapd->wps->encr_types = cred->encr_type;
|
||||
hapd->wps->encr_types_rsn = cred->encr_type;
|
||||
hapd->wps->encr_types_wpa = cred->encr_type;
|
||||
hapd->wps->auth_types = cred->auth_type;
|
||||
hapd->wps->ap_encr_type = cred->encr_type;
|
||||
hapd->wps->ap_auth_type = cred->auth_type;
|
||||
@ -872,7 +868,8 @@ static void hostapd_wps_clear_ies(struct hostapd_data *hapd, int deinit_only)
|
||||
hapd->wps_probe_resp_ie = NULL;
|
||||
|
||||
if (deinit_only) {
|
||||
hostapd_reset_ap_wps_ie(hapd);
|
||||
if (hapd->drv_priv)
|
||||
hostapd_reset_ap_wps_ie(hapd);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1067,10 +1064,14 @@ int hostapd_init_wps(struct hostapd_data *hapd,
|
||||
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X)
|
||||
wps->auth_types |= WPS_AUTH_WPA2;
|
||||
|
||||
if (conf->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP))
|
||||
if (conf->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) {
|
||||
wps->encr_types |= WPS_ENCR_AES;
|
||||
if (conf->rsn_pairwise & WPA_CIPHER_TKIP)
|
||||
wps->encr_types_rsn |= WPS_ENCR_AES;
|
||||
}
|
||||
if (conf->rsn_pairwise & WPA_CIPHER_TKIP) {
|
||||
wps->encr_types |= WPS_ENCR_TKIP;
|
||||
wps->encr_types_rsn |= WPS_ENCR_TKIP;
|
||||
}
|
||||
}
|
||||
|
||||
if (conf->wpa & WPA_PROTO_WPA) {
|
||||
@ -1079,10 +1080,14 @@ int hostapd_init_wps(struct hostapd_data *hapd,
|
||||
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X)
|
||||
wps->auth_types |= WPS_AUTH_WPA;
|
||||
|
||||
if (conf->wpa_pairwise & WPA_CIPHER_CCMP)
|
||||
if (conf->wpa_pairwise & WPA_CIPHER_CCMP) {
|
||||
wps->encr_types |= WPS_ENCR_AES;
|
||||
if (conf->wpa_pairwise & WPA_CIPHER_TKIP)
|
||||
wps->encr_types_wpa |= WPS_ENCR_AES;
|
||||
}
|
||||
if (conf->wpa_pairwise & WPA_CIPHER_TKIP) {
|
||||
wps->encr_types |= WPS_ENCR_TKIP;
|
||||
wps->encr_types_wpa |= WPS_ENCR_TKIP;
|
||||
}
|
||||
}
|
||||
|
||||
if (conf->ssid.security_policy == SECURITY_PLAINTEXT) {
|
||||
@ -1122,6 +1127,8 @@ int hostapd_init_wps(struct hostapd_data *hapd,
|
||||
/* Override parameters to enable security by default */
|
||||
wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK;
|
||||
wps->encr_types = WPS_ENCR_AES | WPS_ENCR_TKIP;
|
||||
wps->encr_types_rsn = WPS_ENCR_AES | WPS_ENCR_TKIP;
|
||||
wps->encr_types_wpa = WPS_ENCR_AES | WPS_ENCR_TKIP;
|
||||
}
|
||||
|
||||
wps->ap_settings = conf->ap_settings;
|
||||
@ -1614,7 +1621,8 @@ const char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout)
|
||||
unsigned int pin;
|
||||
struct wps_ap_pin_data data;
|
||||
|
||||
pin = wps_generate_pin();
|
||||
if (wps_generate_pin(&pin) < 0)
|
||||
return NULL;
|
||||
os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%08u", pin);
|
||||
data.timeout = timeout;
|
||||
hostapd_wps_for_each(hapd, wps_ap_pin_set, &data);
|
||||
|
267
src/common/cli.c
Normal file
267
src/common/cli.c
Normal file
@ -0,0 +1,267 @@
|
||||
/*
|
||||
* Common hostapd/wpa_supplicant command line interface functions
|
||||
* Copyright (c) 2004-2016, 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 "utils/common.h"
|
||||
#include "common/cli.h"
|
||||
|
||||
|
||||
const char *const cli_license =
|
||||
"This software may be distributed under the terms of the BSD license.\n"
|
||||
"See README for more details.\n";
|
||||
|
||||
const char *const cli_full_license =
|
||||
"This software may be distributed under the terms of the BSD license.\n"
|
||||
"\n"
|
||||
"Redistribution and use in source and binary forms, with or without\n"
|
||||
"modification, are permitted provided that the following conditions are\n"
|
||||
"met:\n"
|
||||
"\n"
|
||||
"1. Redistributions of source code must retain the above copyright\n"
|
||||
" notice, this list of conditions and the following disclaimer.\n"
|
||||
"\n"
|
||||
"2. Redistributions in binary form must reproduce the above copyright\n"
|
||||
" notice, this list of conditions and the following disclaimer in the\n"
|
||||
" documentation and/or other materials provided with the distribution.\n"
|
||||
"\n"
|
||||
"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
|
||||
" names of its contributors may be used to endorse or promote products\n"
|
||||
" derived from this software without specific prior written permission.\n"
|
||||
"\n"
|
||||
"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
|
||||
"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
|
||||
"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
|
||||
"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
|
||||
"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
|
||||
"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
|
||||
"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
|
||||
"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
|
||||
"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
|
||||
"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
|
||||
"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
|
||||
"\n";
|
||||
|
||||
|
||||
void cli_txt_list_free(struct cli_txt_entry *e)
|
||||
{
|
||||
dl_list_del(&e->list);
|
||||
os_free(e->txt);
|
||||
os_free(e);
|
||||
}
|
||||
|
||||
|
||||
void cli_txt_list_flush(struct dl_list *list)
|
||||
{
|
||||
struct cli_txt_entry *e;
|
||||
|
||||
while ((e = dl_list_first(list, struct cli_txt_entry, list)))
|
||||
cli_txt_list_free(e);
|
||||
}
|
||||
|
||||
|
||||
struct cli_txt_entry * cli_txt_list_get(struct dl_list *txt_list,
|
||||
const char *txt)
|
||||
{
|
||||
struct cli_txt_entry *e;
|
||||
|
||||
dl_list_for_each(e, txt_list, struct cli_txt_entry, list) {
|
||||
if (os_strcmp(e->txt, txt) == 0)
|
||||
return e;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void cli_txt_list_del(struct dl_list *txt_list, const char *txt)
|
||||
{
|
||||
struct cli_txt_entry *e;
|
||||
|
||||
e = cli_txt_list_get(txt_list, txt);
|
||||
if (e)
|
||||
cli_txt_list_free(e);
|
||||
}
|
||||
|
||||
|
||||
void cli_txt_list_del_addr(struct dl_list *txt_list, const char *txt)
|
||||
{
|
||||
u8 addr[ETH_ALEN];
|
||||
char buf[18];
|
||||
|
||||
if (hwaddr_aton(txt, addr) < 0)
|
||||
return;
|
||||
os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
|
||||
cli_txt_list_del(txt_list, buf);
|
||||
}
|
||||
|
||||
|
||||
void cli_txt_list_del_word(struct dl_list *txt_list, const char *txt,
|
||||
int separator)
|
||||
{
|
||||
const char *end;
|
||||
char *buf;
|
||||
|
||||
end = os_strchr(txt, separator);
|
||||
if (end == NULL)
|
||||
end = txt + os_strlen(txt);
|
||||
buf = dup_binstr(txt, end - txt);
|
||||
if (buf == NULL)
|
||||
return;
|
||||
cli_txt_list_del(txt_list, buf);
|
||||
os_free(buf);
|
||||
}
|
||||
|
||||
|
||||
int cli_txt_list_add(struct dl_list *txt_list, const char *txt)
|
||||
{
|
||||
struct cli_txt_entry *e;
|
||||
|
||||
e = cli_txt_list_get(txt_list, txt);
|
||||
if (e)
|
||||
return 0;
|
||||
e = os_zalloc(sizeof(*e));
|
||||
if (e == NULL)
|
||||
return -1;
|
||||
e->txt = os_strdup(txt);
|
||||
if (e->txt == NULL) {
|
||||
os_free(e);
|
||||
return -1;
|
||||
}
|
||||
dl_list_add(txt_list, &e->list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int cli_txt_list_add_addr(struct dl_list *txt_list, const char *txt)
|
||||
{
|
||||
u8 addr[ETH_ALEN];
|
||||
char buf[18];
|
||||
|
||||
if (hwaddr_aton(txt, addr) < 0)
|
||||
return -1;
|
||||
os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
|
||||
return cli_txt_list_add(txt_list, buf);
|
||||
}
|
||||
|
||||
|
||||
int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt,
|
||||
int separator)
|
||||
{
|
||||
const char *end;
|
||||
char *buf;
|
||||
int ret;
|
||||
|
||||
end = os_strchr(txt, separator);
|
||||
if (end == NULL)
|
||||
end = txt + os_strlen(txt);
|
||||
buf = dup_binstr(txt, end - txt);
|
||||
if (buf == NULL)
|
||||
return -1;
|
||||
ret = cli_txt_list_add(txt_list, buf);
|
||||
os_free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
char ** cli_txt_list_array(struct dl_list *txt_list)
|
||||
{
|
||||
unsigned int i, count = dl_list_len(txt_list);
|
||||
char **res;
|
||||
struct cli_txt_entry *e;
|
||||
|
||||
res = os_calloc(count + 1, sizeof(char *));
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
|
||||
i = 0;
|
||||
dl_list_for_each(e, txt_list, struct cli_txt_entry, list) {
|
||||
res[i] = os_strdup(e->txt);
|
||||
if (res[i] == NULL)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
int get_cmd_arg_num(const char *str, int pos)
|
||||
{
|
||||
int arg = 0, i;
|
||||
|
||||
for (i = 0; i <= pos; i++) {
|
||||
if (str[i] != ' ') {
|
||||
arg++;
|
||||
while (i <= pos && str[i] != ' ')
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (arg > 0)
|
||||
arg--;
|
||||
return arg;
|
||||
}
|
||||
|
||||
|
||||
int write_cmd(char *buf, size_t buflen, const char *cmd, int argc, char *argv[])
|
||||
{
|
||||
int i, res;
|
||||
char *pos, *end;
|
||||
|
||||
pos = buf;
|
||||
end = buf + buflen;
|
||||
|
||||
res = os_snprintf(pos, end - pos, "%s", cmd);
|
||||
if (os_snprintf_error(end - pos, res))
|
||||
goto fail;
|
||||
pos += res;
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
res = os_snprintf(pos, end - pos, " %s", argv[i]);
|
||||
if (os_snprintf_error(end - pos, res))
|
||||
goto fail;
|
||||
pos += res;
|
||||
}
|
||||
|
||||
buf[buflen - 1] = '\0';
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
printf("Too long command\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int tokenize_cmd(char *cmd, char *argv[])
|
||||
{
|
||||
char *pos;
|
||||
int argc = 0;
|
||||
|
||||
pos = cmd;
|
||||
for (;;) {
|
||||
while (*pos == ' ')
|
||||
pos++;
|
||||
if (*pos == '\0')
|
||||
break;
|
||||
argv[argc] = pos;
|
||||
argc++;
|
||||
if (argc == max_args)
|
||||
break;
|
||||
if (*pos == '"') {
|
||||
char *pos2 = os_strrchr(pos, '"');
|
||||
if (pos2)
|
||||
pos = pos2 + 1;
|
||||
}
|
||||
while (*pos != '\0' && *pos != ' ')
|
||||
pos++;
|
||||
if (*pos == ' ')
|
||||
*pos++ = '\0';
|
||||
}
|
||||
|
||||
return argc;
|
||||
}
|
47
src/common/cli.h
Normal file
47
src/common/cli.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Common hostapd/wpa_supplicant command line interface functionality
|
||||
* Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef CLI_H
|
||||
#define CLI_H
|
||||
|
||||
#include "utils/list.h"
|
||||
|
||||
extern const char *const cli_license;
|
||||
extern const char *const cli_full_license;
|
||||
|
||||
struct cli_txt_entry {
|
||||
struct dl_list list;
|
||||
char *txt;
|
||||
};
|
||||
|
||||
void cli_txt_list_free(struct cli_txt_entry *e);
|
||||
void cli_txt_list_flush(struct dl_list *list);
|
||||
|
||||
struct cli_txt_entry *
|
||||
cli_txt_list_get(struct dl_list *txt_list, const char *txt);
|
||||
|
||||
void cli_txt_list_del(struct dl_list *txt_list, const char *txt);
|
||||
void cli_txt_list_del_addr(struct dl_list *txt_list, const char *txt);
|
||||
void cli_txt_list_del_word(struct dl_list *txt_list, const char *txt,
|
||||
int separator);
|
||||
|
||||
int cli_txt_list_add(struct dl_list *txt_list, const char *txt);
|
||||
int cli_txt_list_add_addr(struct dl_list *txt_list, const char *txt);
|
||||
int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt,
|
||||
int separator);
|
||||
|
||||
char ** cli_txt_list_array(struct dl_list *txt_list);
|
||||
|
||||
int get_cmd_arg_num(const char *str, int pos);
|
||||
int write_cmd(char *buf, size_t buflen, const char *cmd, int argc,
|
||||
char *argv[]);
|
||||
|
||||
#define max_args 10
|
||||
int tokenize_cmd(char *cmd, char *argv[]);
|
||||
|
||||
#endif /* CLI_H */
|
@ -9,6 +9,7 @@
|
||||
#include "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "utils/module_tests.h"
|
||||
#include "ieee802_11_common.h"
|
||||
#include "ieee802_11_defs.h"
|
||||
#include "gas.h"
|
||||
|
173
src/common/ctrl_iface_common.c
Normal file
173
src/common/ctrl_iface_common.c
Normal file
@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Common hostapd/wpa_supplicant ctrl iface code.
|
||||
* Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2015, 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 <netdb.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "ctrl_iface_common.h"
|
||||
|
||||
static int sockaddr_compare(struct sockaddr_storage *a, socklen_t a_len,
|
||||
struct sockaddr_storage *b, socklen_t b_len)
|
||||
{
|
||||
if (a->ss_family != b->ss_family)
|
||||
return 1;
|
||||
|
||||
switch (a->ss_family) {
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP
|
||||
case AF_INET:
|
||||
{
|
||||
struct sockaddr_in *in_a, *in_b;
|
||||
|
||||
in_a = (struct sockaddr_in *) a;
|
||||
in_b = (struct sockaddr_in *) b;
|
||||
|
||||
if (in_a->sin_port != in_b->sin_port)
|
||||
return 1;
|
||||
if (in_a->sin_addr.s_addr != in_b->sin_addr.s_addr)
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
case AF_INET6:
|
||||
{
|
||||
struct sockaddr_in6 *in6_a, *in6_b;
|
||||
|
||||
in6_a = (struct sockaddr_in6 *) a;
|
||||
in6_b = (struct sockaddr_in6 *) b;
|
||||
|
||||
if (in6_a->sin6_port != in6_b->sin6_port)
|
||||
return 1;
|
||||
if (os_memcmp(&in6_a->sin6_addr, &in6_b->sin6_addr,
|
||||
sizeof(in6_a->sin6_addr)) != 0)
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP */
|
||||
#ifdef CONFIG_CTRL_IFACE_UNIX
|
||||
case AF_UNIX:
|
||||
{
|
||||
struct sockaddr_un *u_a, *u_b;
|
||||
|
||||
u_a = (struct sockaddr_un *) a;
|
||||
u_b = (struct sockaddr_un *) b;
|
||||
|
||||
if (a_len != b_len ||
|
||||
os_memcmp(u_a->sun_path, u_b->sun_path,
|
||||
a_len - offsetof(struct sockaddr_un, sun_path))
|
||||
!= 0)
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
#endif /* CONFIG_CTRL_IFACE_UNIX */
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void sockaddr_print(int level, const char *msg, struct sockaddr_storage *sock,
|
||||
socklen_t socklen)
|
||||
{
|
||||
switch (sock->ss_family) {
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP
|
||||
case AF_INET:
|
||||
case AF_INET6:
|
||||
{
|
||||
char host[NI_MAXHOST] = { 0 };
|
||||
char service[NI_MAXSERV] = { 0 };
|
||||
|
||||
getnameinfo((struct sockaddr *) sock, socklen,
|
||||
host, sizeof(host),
|
||||
service, sizeof(service),
|
||||
NI_NUMERICHOST);
|
||||
|
||||
wpa_printf(level, "%s %s:%s", msg, host, service);
|
||||
break;
|
||||
}
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP */
|
||||
#ifdef CONFIG_CTRL_IFACE_UNIX
|
||||
case AF_UNIX:
|
||||
{
|
||||
char addr_txt[200];
|
||||
|
||||
printf_encode(addr_txt, sizeof(addr_txt),
|
||||
(u8 *) ((struct sockaddr_un *) sock)->sun_path,
|
||||
socklen - offsetof(struct sockaddr_un, sun_path));
|
||||
wpa_printf(level, "%s %s", msg, addr_txt);
|
||||
break;
|
||||
}
|
||||
#endif /* CONFIG_CTRL_IFACE_UNIX */
|
||||
default:
|
||||
wpa_printf(level, "%s", msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int ctrl_iface_attach(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
|
||||
socklen_t fromlen)
|
||||
{
|
||||
struct wpa_ctrl_dst *dst;
|
||||
|
||||
dst = os_zalloc(sizeof(*dst));
|
||||
if (dst == NULL)
|
||||
return -1;
|
||||
os_memcpy(&dst->addr, from, fromlen);
|
||||
dst->addrlen = fromlen;
|
||||
dst->debug_level = MSG_INFO;
|
||||
dl_list_add(ctrl_dst, &dst->list);
|
||||
|
||||
sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor attached", from, fromlen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int ctrl_iface_detach(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
|
||||
socklen_t fromlen)
|
||||
{
|
||||
struct wpa_ctrl_dst *dst;
|
||||
|
||||
dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) {
|
||||
if (!sockaddr_compare(from, fromlen,
|
||||
&dst->addr, dst->addrlen)) {
|
||||
sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor detached",
|
||||
from, fromlen);
|
||||
dl_list_del(&dst->list);
|
||||
os_free(dst);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int ctrl_iface_level(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
|
||||
socklen_t fromlen, const char *level)
|
||||
{
|
||||
struct wpa_ctrl_dst *dst;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
|
||||
|
||||
dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) {
|
||||
if (!sockaddr_compare(from, fromlen,
|
||||
&dst->addr, dst->addrlen)) {
|
||||
sockaddr_print(MSG_DEBUG,
|
||||
"CTRL_IFACE changed monitor level",
|
||||
from, fromlen);
|
||||
dst->debug_level = atoi(level);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
38
src/common/ctrl_iface_common.h
Normal file
38
src/common/ctrl_iface_common.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Common hostapd/wpa_supplicant ctrl iface code.
|
||||
* Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2015, Qualcomm Atheros, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
#ifndef CONTROL_IFACE_COMMON_H
|
||||
#define CONTROL_IFACE_COMMON_H
|
||||
|
||||
#include "utils/list.h"
|
||||
|
||||
/**
|
||||
* struct wpa_ctrl_dst - Data structure of control interface monitors
|
||||
*
|
||||
* This structure is used to store information about registered control
|
||||
* interface monitors into struct wpa_supplicant.
|
||||
*/
|
||||
struct wpa_ctrl_dst {
|
||||
struct dl_list list;
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addrlen;
|
||||
int debug_level;
|
||||
int errors;
|
||||
};
|
||||
|
||||
void sockaddr_print(int level, const char *msg, struct sockaddr_storage *sock,
|
||||
socklen_t socklen);
|
||||
|
||||
int ctrl_iface_attach(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
|
||||
socklen_t fromlen);
|
||||
int ctrl_iface_detach(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
|
||||
socklen_t fromlen);
|
||||
int ctrl_iface_level(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
|
||||
socklen_t fromlen, const char *level);
|
||||
|
||||
#endif /* CONTROL_IFACE_COMMON_H */
|
@ -312,6 +312,7 @@ enum wpa_ctrl_req_type {
|
||||
WPA_CTRL_REQ_EAP_PASSPHRASE,
|
||||
WPA_CTRL_REQ_SIM,
|
||||
WPA_CTRL_REQ_PSK_PASSPHRASE,
|
||||
WPA_CTRL_REQ_EXT_CERT_CHECK,
|
||||
NUM_WPA_CTRL_REQS
|
||||
};
|
||||
|
||||
@ -319,13 +320,13 @@ enum wpa_ctrl_req_type {
|
||||
#define EAP_MAX_METHODS 8
|
||||
|
||||
enum mesh_plink_state {
|
||||
PLINK_LISTEN = 1,
|
||||
PLINK_OPEN_SENT,
|
||||
PLINK_OPEN_RCVD,
|
||||
PLINK_IDLE = 1,
|
||||
PLINK_OPN_SNT,
|
||||
PLINK_OPN_RCVD,
|
||||
PLINK_CNF_RCVD,
|
||||
PLINK_ESTAB,
|
||||
PLINK_HOLDING,
|
||||
PLINK_BLOCKED,
|
||||
PLINK_BLOCKED, /* not defined in the IEEE 802.11 standard */
|
||||
};
|
||||
|
||||
enum set_band {
|
||||
@ -334,4 +335,10 @@ enum set_band {
|
||||
WPA_SETBAND_2G
|
||||
};
|
||||
|
||||
enum wpa_radio_work_band {
|
||||
BAND_2_4_GHZ = BIT(0),
|
||||
BAND_5_GHZ = BIT(1),
|
||||
BAND_60_GHZ = BIT(2),
|
||||
};
|
||||
|
||||
#endif /* DEFS_H */
|
||||
|
@ -25,7 +25,7 @@ struct ieee802_1x_hdr {
|
||||
struct ieee8023_hdr {
|
||||
u8 dest[ETH_ALEN];
|
||||
u8 src[ETH_ALEN];
|
||||
u16 ethertype;
|
||||
be16 ethertype;
|
||||
} STRUCT_PACKED;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
@ -115,6 +115,11 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
|
||||
elems->osen = pos;
|
||||
elems->osen_len = elen;
|
||||
break;
|
||||
case MBO_OUI_TYPE:
|
||||
/* MBO-OCE */
|
||||
elems->mbo = pos;
|
||||
elems->mbo_len = elen;
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_MSGDUMP, "Unknown WFA "
|
||||
"information element ignored "
|
||||
@ -366,6 +371,14 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
|
||||
elems->mb_ies.ies[elems->mb_ies.nof_ies].ie_len = elen;
|
||||
elems->mb_ies.nof_ies++;
|
||||
break;
|
||||
case WLAN_EID_SUPPORTED_OPERATING_CLASSES:
|
||||
elems->supp_op_classes = pos;
|
||||
elems->supp_op_classes_len = elen;
|
||||
break;
|
||||
case WLAN_EID_RRM_ENABLED_CAPABILITIES:
|
||||
elems->rrm_enabled = pos;
|
||||
elems->rrm_enabled_len = elen;
|
||||
break;
|
||||
default:
|
||||
unknown++;
|
||||
if (!show_errors)
|
||||
@ -398,8 +411,8 @@ int ieee802_11_ie_count(const u8 *ies, size_t ies_len)
|
||||
pos = ies;
|
||||
end = ies + ies_len;
|
||||
|
||||
while (pos + 2 <= end) {
|
||||
if (pos + 2 + pos[1] > end)
|
||||
while (end - pos >= 2) {
|
||||
if (2 + pos[1] > end - pos)
|
||||
break;
|
||||
count++;
|
||||
pos += 2 + pos[1];
|
||||
@ -419,8 +432,8 @@ struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
|
||||
end = ies + ies_len;
|
||||
ie = NULL;
|
||||
|
||||
while (pos + 1 < end) {
|
||||
if (pos + 2 + pos[1] > end)
|
||||
while (end - pos > 1) {
|
||||
if (2 + pos[1] > end - pos)
|
||||
return NULL;
|
||||
if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
|
||||
WPA_GET_BE32(&pos[2]) == oui_type) {
|
||||
@ -441,8 +454,8 @@ struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
|
||||
* There may be multiple vendor IEs in the message, so need to
|
||||
* concatenate their data fields.
|
||||
*/
|
||||
while (pos + 1 < end) {
|
||||
if (pos + 2 + pos[1] > end)
|
||||
while (end - pos > 1) {
|
||||
if (2 + pos[1] > end - pos)
|
||||
break;
|
||||
if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
|
||||
WPA_GET_BE32(&pos[2]) == oui_type)
|
||||
@ -570,7 +583,8 @@ enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
|
||||
{
|
||||
u8 op_class;
|
||||
|
||||
return ieee80211_freq_to_channel_ext(freq, 0, 0, &op_class, channel);
|
||||
return ieee80211_freq_to_channel_ext(freq, 0, VHT_CHANWIDTH_USE_HT,
|
||||
&op_class, channel);
|
||||
}
|
||||
|
||||
|
||||
@ -579,7 +593,7 @@ enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
|
||||
* for HT40 and VHT. DFS channels are not covered.
|
||||
* @freq: Frequency (MHz) to convert
|
||||
* @sec_channel: 0 = non-HT40, 1 = sec. channel above, -1 = sec. channel below
|
||||
* @vht: 0 - non-VHT, 1 - 80 MHz
|
||||
* @vht: VHT channel width (VHT_CHANWIDTH_*)
|
||||
* @op_class: Buffer for returning operating class
|
||||
* @channel: Buffer for returning channel number
|
||||
* Returns: hw_mode on success, NUM_HOSTAPD_MODES on failure
|
||||
@ -588,6 +602,8 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
|
||||
int sec_channel, int vht,
|
||||
u8 *op_class, u8 *channel)
|
||||
{
|
||||
u8 vht_opclass;
|
||||
|
||||
/* TODO: more operating classes */
|
||||
|
||||
if (sec_channel > 1 || sec_channel < -1)
|
||||
@ -631,17 +647,32 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
|
||||
return HOSTAPD_MODE_IEEE80211A;
|
||||
}
|
||||
|
||||
switch (vht) {
|
||||
case VHT_CHANWIDTH_80MHZ:
|
||||
vht_opclass = 128;
|
||||
break;
|
||||
case VHT_CHANWIDTH_160MHZ:
|
||||
vht_opclass = 129;
|
||||
break;
|
||||
case VHT_CHANWIDTH_80P80MHZ:
|
||||
vht_opclass = 130;
|
||||
break;
|
||||
default:
|
||||
vht_opclass = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* 5 GHz, channels 36..48 */
|
||||
if (freq >= 5180 && freq <= 5240) {
|
||||
if ((freq - 5000) % 5)
|
||||
return NUM_HOSTAPD_MODES;
|
||||
|
||||
if (sec_channel == 1)
|
||||
if (vht_opclass)
|
||||
*op_class = vht_opclass;
|
||||
else if (sec_channel == 1)
|
||||
*op_class = 116;
|
||||
else if (sec_channel == -1)
|
||||
*op_class = 117;
|
||||
else if (vht)
|
||||
*op_class = 128;
|
||||
else
|
||||
*op_class = 115;
|
||||
|
||||
@ -650,31 +681,40 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
|
||||
return HOSTAPD_MODE_IEEE80211A;
|
||||
}
|
||||
|
||||
/* 5 GHz, channels 149..161 */
|
||||
if (freq >= 5745 && freq <= 5805) {
|
||||
if ((freq - 5000) % 5)
|
||||
return NUM_HOSTAPD_MODES;
|
||||
|
||||
if (sec_channel == 1)
|
||||
*op_class = 126;
|
||||
else if (sec_channel == -1)
|
||||
*op_class = 127;
|
||||
else if (vht)
|
||||
*op_class = 128;
|
||||
else
|
||||
*op_class = 124;
|
||||
|
||||
*channel = (freq - 5000) / 5;
|
||||
|
||||
return HOSTAPD_MODE_IEEE80211A;
|
||||
}
|
||||
|
||||
/* 5 GHz, channels 149..169 */
|
||||
if (freq >= 5745 && freq <= 5845) {
|
||||
if ((freq - 5000) % 5)
|
||||
return NUM_HOSTAPD_MODES;
|
||||
|
||||
*op_class = 125;
|
||||
if (vht_opclass)
|
||||
*op_class = vht_opclass;
|
||||
else if (sec_channel == 1)
|
||||
*op_class = 126;
|
||||
else if (sec_channel == -1)
|
||||
*op_class = 127;
|
||||
else if (freq <= 5805)
|
||||
*op_class = 124;
|
||||
else
|
||||
*op_class = 125;
|
||||
|
||||
*channel = (freq - 5000) / 5;
|
||||
|
||||
return HOSTAPD_MODE_IEEE80211A;
|
||||
}
|
||||
|
||||
/* 5 GHz, channels 100..140 */
|
||||
if (freq >= 5000 && freq <= 5700) {
|
||||
if ((freq - 5000) % 5)
|
||||
return NUM_HOSTAPD_MODES;
|
||||
|
||||
if (vht_opclass)
|
||||
*op_class = vht_opclass;
|
||||
else if (sec_channel == 1)
|
||||
*op_class = 122;
|
||||
else if (sec_channel == -1)
|
||||
*op_class = 123;
|
||||
else
|
||||
*op_class = 121;
|
||||
|
||||
*channel = (freq - 5000) / 5;
|
||||
|
||||
@ -1145,3 +1185,135 @@ struct wpabuf * mb_ies_by_info(struct mb_ies_info *info)
|
||||
|
||||
return mb_ies;
|
||||
}
|
||||
|
||||
|
||||
const struct oper_class_map global_op_class[] = {
|
||||
{ HOSTAPD_MODE_IEEE80211G, 81, 1, 13, 1, BW20, P2P_SUPP },
|
||||
{ HOSTAPD_MODE_IEEE80211G, 82, 14, 14, 1, BW20, NO_P2P_SUPP },
|
||||
|
||||
/* Do not enable HT40 on 2.4 GHz for P2P use for now */
|
||||
{ HOSTAPD_MODE_IEEE80211G, 83, 1, 9, 1, BW40PLUS, NO_P2P_SUPP },
|
||||
{ HOSTAPD_MODE_IEEE80211G, 84, 5, 13, 1, BW40MINUS, NO_P2P_SUPP },
|
||||
|
||||
{ HOSTAPD_MODE_IEEE80211A, 115, 36, 48, 4, BW20, P2P_SUPP },
|
||||
{ HOSTAPD_MODE_IEEE80211A, 116, 36, 44, 8, BW40PLUS, P2P_SUPP },
|
||||
{ HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS, P2P_SUPP },
|
||||
{ HOSTAPD_MODE_IEEE80211A, 118, 52, 64, 4, BW20, NO_P2P_SUPP },
|
||||
{ HOSTAPD_MODE_IEEE80211A, 119, 52, 60, 8, BW40PLUS, NO_P2P_SUPP },
|
||||
{ HOSTAPD_MODE_IEEE80211A, 120, 56, 64, 8, BW40MINUS, NO_P2P_SUPP },
|
||||
{ HOSTAPD_MODE_IEEE80211A, 121, 100, 140, 4, BW20, NO_P2P_SUPP },
|
||||
{ HOSTAPD_MODE_IEEE80211A, 122, 100, 132, 8, BW40PLUS, NO_P2P_SUPP },
|
||||
{ HOSTAPD_MODE_IEEE80211A, 123, 104, 136, 8, BW40MINUS, NO_P2P_SUPP },
|
||||
{ HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20, P2P_SUPP },
|
||||
{ HOSTAPD_MODE_IEEE80211A, 125, 149, 169, 4, BW20, P2P_SUPP },
|
||||
{ HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8, BW40PLUS, P2P_SUPP },
|
||||
{ HOSTAPD_MODE_IEEE80211A, 127, 153, 161, 8, BW40MINUS, P2P_SUPP },
|
||||
|
||||
/*
|
||||
* IEEE P802.11ac/D7.0 Table E-4 actually talks about channel center
|
||||
* frequency index 42, 58, 106, 122, 138, 155 with channel spacing of
|
||||
* 80 MHz, but currently use the following definition for simplicity
|
||||
* (these center frequencies are not actual channels, which makes
|
||||
* wpas_p2p_allow_channel() fail). wpas_p2p_verify_80mhz() should take
|
||||
* care of removing invalid channels.
|
||||
*/
|
||||
{ HOSTAPD_MODE_IEEE80211A, 128, 36, 161, 4, BW80, P2P_SUPP },
|
||||
{ HOSTAPD_MODE_IEEE80211A, 129, 50, 114, 16, BW160, P2P_SUPP },
|
||||
{ HOSTAPD_MODE_IEEE80211A, 130, 36, 161, 4, BW80P80, P2P_SUPP },
|
||||
{ HOSTAPD_MODE_IEEE80211AD, 180, 1, 4, 1, BW2160, P2P_SUPP },
|
||||
{ -1, 0, 0, 0, 0, BW20, NO_P2P_SUPP }
|
||||
};
|
||||
|
||||
|
||||
static enum phy_type ieee80211_phy_type_by_freq(int freq)
|
||||
{
|
||||
enum hostapd_hw_mode hw_mode;
|
||||
u8 channel;
|
||||
|
||||
hw_mode = ieee80211_freq_to_chan(freq, &channel);
|
||||
|
||||
switch (hw_mode) {
|
||||
case HOSTAPD_MODE_IEEE80211A:
|
||||
return PHY_TYPE_OFDM;
|
||||
case HOSTAPD_MODE_IEEE80211B:
|
||||
return PHY_TYPE_HRDSSS;
|
||||
case HOSTAPD_MODE_IEEE80211G:
|
||||
return PHY_TYPE_ERP;
|
||||
case HOSTAPD_MODE_IEEE80211AD:
|
||||
return PHY_TYPE_DMG;
|
||||
default:
|
||||
return PHY_TYPE_UNSPECIFIED;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/* ieee80211_get_phy_type - Derive the phy type by freq and bandwidth */
|
||||
enum phy_type ieee80211_get_phy_type(int freq, int ht, int vht)
|
||||
{
|
||||
if (vht)
|
||||
return PHY_TYPE_VHT;
|
||||
if (ht)
|
||||
return PHY_TYPE_HT;
|
||||
|
||||
return ieee80211_phy_type_by_freq(freq);
|
||||
}
|
||||
|
||||
|
||||
size_t global_op_class_size = ARRAY_SIZE(global_op_class);
|
||||
|
||||
|
||||
/**
|
||||
* get_ie - Fetch a specified information element from IEs buffer
|
||||
* @ies: Information elements buffer
|
||||
* @len: Information elements buffer length
|
||||
* @eid: Information element identifier (WLAN_EID_*)
|
||||
* Returns: Pointer to the information element (id field) or %NULL if not found
|
||||
*
|
||||
* This function returns the first matching information element in the IEs
|
||||
* buffer or %NULL in case the element is not found.
|
||||
*/
|
||||
const u8 * get_ie(const u8 *ies, size_t len, u8 eid)
|
||||
{
|
||||
const u8 *end;
|
||||
|
||||
if (!ies)
|
||||
return NULL;
|
||||
|
||||
end = ies + len;
|
||||
|
||||
while (end - ies > 1) {
|
||||
if (2 + ies[1] > end - ies)
|
||||
break;
|
||||
|
||||
if (ies[0] == eid)
|
||||
return ies;
|
||||
|
||||
ies += 2 + ies[1];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len)
|
||||
{
|
||||
/*
|
||||
* MBO IE requires 6 bytes without the attributes: EID (1), length (1),
|
||||
* OUI (3), OUI type (1).
|
||||
*/
|
||||
if (len < 6 + attr_len) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"MBO: Not enough room in buffer for MBO IE: buf len = %zu, attr_len = %zu",
|
||||
len, attr_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*buf++ = WLAN_EID_VENDOR_SPECIFIC;
|
||||
*buf++ = attr_len + 4;
|
||||
WPA_PUT_BE24(buf, OUI_WFA);
|
||||
buf += 3;
|
||||
*buf++ = MBO_OUI_TYPE;
|
||||
os_memcpy(buf, attr, attr_len);
|
||||
|
||||
return 6 + attr_len;
|
||||
}
|
||||
|
@ -9,6 +9,8 @@
|
||||
#ifndef IEEE802_11_COMMON_H
|
||||
#define IEEE802_11_COMMON_H
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
#define MAX_NOF_MB_IES_SUPPORTED 5
|
||||
|
||||
struct mb_ies_info {
|
||||
@ -56,9 +58,12 @@ struct ieee802_11_elems {
|
||||
const u8 *bss_max_idle_period;
|
||||
const u8 *ssid_list;
|
||||
const u8 *osen;
|
||||
const u8 *mbo;
|
||||
const u8 *ampe;
|
||||
const u8 *mic;
|
||||
const u8 *pref_freq_list;
|
||||
const u8 *supp_op_classes;
|
||||
const u8 *rrm_enabled;
|
||||
|
||||
u8 ssid_len;
|
||||
u8 supp_rates_len;
|
||||
@ -85,9 +90,13 @@ struct ieee802_11_elems {
|
||||
u8 ext_capab_len;
|
||||
u8 ssid_list_len;
|
||||
u8 osen_len;
|
||||
u8 mbo_len;
|
||||
u8 ampe_len;
|
||||
u8 mic_len;
|
||||
u8 pref_freq_list_len;
|
||||
u8 supp_op_classes_len;
|
||||
u8 rrm_enabled_len;
|
||||
|
||||
struct mb_ies_info mb_ies;
|
||||
};
|
||||
|
||||
@ -118,6 +127,7 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
|
||||
int sec_channel, int vht,
|
||||
u8 *op_class, u8 *channel);
|
||||
int ieee80211_is_dfs(int freq);
|
||||
enum phy_type ieee80211_get_phy_type(int freq, int ht, int vht);
|
||||
|
||||
int supp_rates_11b_only(struct ieee802_11_elems *elems);
|
||||
int mb_ies_info_by_ies(struct mb_ies_info *info, const u8 *ies_buf,
|
||||
@ -125,4 +135,22 @@ int mb_ies_info_by_ies(struct mb_ies_info *info, const u8 *ies_buf,
|
||||
struct wpabuf * mb_ies_by_info(struct mb_ies_info *info);
|
||||
|
||||
const char * fc2str(u16 fc);
|
||||
|
||||
struct oper_class_map {
|
||||
enum hostapd_hw_mode mode;
|
||||
u8 op_class;
|
||||
u8 min_chan;
|
||||
u8 max_chan;
|
||||
u8 inc;
|
||||
enum { BW20, BW40PLUS, BW40MINUS, BW80, BW2160, BW160, BW80P80 } bw;
|
||||
enum { P2P_SUPP, NO_P2P_SUPP } p2p;
|
||||
};
|
||||
|
||||
extern const struct oper_class_map global_op_class[];
|
||||
extern size_t global_op_class_size;
|
||||
|
||||
const u8 * get_ie(const u8 *ies, size_t len, u8 eid);
|
||||
|
||||
size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len);
|
||||
|
||||
#endif /* IEEE802_11_COMMON_H */
|
||||
|
@ -94,8 +94,13 @@
|
||||
#define WLAN_CAPABILITY_PBCC BIT(6)
|
||||
#define WLAN_CAPABILITY_CHANNEL_AGILITY BIT(7)
|
||||
#define WLAN_CAPABILITY_SPECTRUM_MGMT BIT(8)
|
||||
#define WLAN_CAPABILITY_QOS BIT(9)
|
||||
#define WLAN_CAPABILITY_SHORT_SLOT_TIME BIT(10)
|
||||
#define WLAN_CAPABILITY_APSD BIT(11)
|
||||
#define WLAN_CAPABILITY_RADIO_MEASUREMENT BIT(12)
|
||||
#define WLAN_CAPABILITY_DSSS_OFDM BIT(13)
|
||||
#define WLAN_CAPABILITY_DELAYED_BLOCK_ACK BIT(14)
|
||||
#define WLAN_CAPABILITY_IMM_BLOCK_ACK BIT(15)
|
||||
|
||||
/* Status codes (IEEE 802.11-2007, 7.3.1.9, Table 7-23) */
|
||||
#define WLAN_STATUS_SUCCESS 0
|
||||
@ -247,6 +252,7 @@
|
||||
#define WLAN_EID_TIMEOUT_INTERVAL 56
|
||||
#define WLAN_EID_RIC_DATA 57
|
||||
#define WLAN_EID_SUPPORTED_OPERATING_CLASSES 59
|
||||
#define WLAN_EID_EXT_CHANSWITCH_ANN 60
|
||||
#define WLAN_EID_HT_OPERATION 61
|
||||
#define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62
|
||||
#define WLAN_EID_WAPI 68
|
||||
@ -360,6 +366,16 @@
|
||||
/* byte 1 (out of 5) */
|
||||
#define WLAN_RRM_CAPS_LINK_MEASUREMENT BIT(0)
|
||||
#define WLAN_RRM_CAPS_NEIGHBOR_REPORT BIT(1)
|
||||
/* byte 2 (out of 5) */
|
||||
#define WLAN_RRM_CAPS_LCI_MEASUREMENT BIT(4)
|
||||
/* byte 5 (out of 5) */
|
||||
#define WLAN_RRM_CAPS_FTM_RANGE_REPORT BIT(2)
|
||||
|
||||
/*
|
||||
* IEEE P802.11-REVmc/D5.0, 9.4.2.21.19 (Fine Timing Measurement Range
|
||||
* request) - Minimum AP count
|
||||
*/
|
||||
#define WLAN_RRM_RANGE_REQ_MAX_MIN_AP 15
|
||||
|
||||
/* Timeout Interval Type */
|
||||
#define WLAN_TIMEOUT_REASSOC_DEADLINE 1
|
||||
@ -407,7 +423,12 @@ enum anqp_info_id {
|
||||
ANQP_AP_LOCATION_PUBLIC_URI = 267,
|
||||
ANQP_DOMAIN_NAME = 268,
|
||||
ANQP_EMERGENCY_ALERT_URI = 269,
|
||||
ANQP_TDLS_CAPABILITY = 270,
|
||||
ANQP_EMERGENCY_NAI = 271,
|
||||
ANQP_NEIGHBOR_REPORT = 272,
|
||||
ANQP_VENUE_URL = 277,
|
||||
ANQP_ADVICE_OF_CHARGE = 278,
|
||||
ANQP_LOCAL_CONTENT = 279,
|
||||
ANQP_VENDOR_SPECIFIC = 56797
|
||||
};
|
||||
|
||||
@ -442,6 +463,48 @@ enum nai_realm_eap_cred_type {
|
||||
NAI_REALM_CRED_TYPE_VENDOR_SPECIFIC = 10
|
||||
};
|
||||
|
||||
/*
|
||||
* IEEE P802.11-REVmc/D5.0 Table 9-81 - Measurement type definitions for
|
||||
* measurement requests
|
||||
*/
|
||||
enum measure_type {
|
||||
MEASURE_TYPE_BASIC = 0,
|
||||
MEASURE_TYPE_CCA = 1,
|
||||
MEASURE_TYPE_RPI_HIST = 2,
|
||||
MEASURE_TYPE_CHANNEL_LOAD = 3,
|
||||
MEASURE_TYPE_NOISE_HIST = 4,
|
||||
MEASURE_TYPE_BEACON = 5,
|
||||
MEASURE_TYPE_FRAME = 6,
|
||||
MEASURE_TYPE_STA_STATISTICS = 7,
|
||||
MEASURE_TYPE_LCI = 8,
|
||||
MEASURE_TYPE_TRANSMIT_STREAM = 9,
|
||||
MEASURE_TYPE_MULTICAST_DIAG = 10,
|
||||
MEASURE_TYPE_LOCATION_CIVIC = 11,
|
||||
MEASURE_TYPE_LOCATION_ID = 12,
|
||||
MEASURE_TYPE_DIRECTIONAL_CHAN_QUALITY = 13,
|
||||
MEASURE_TYPE_DIRECTIONAL_MEASURE = 14,
|
||||
MEASURE_TYPE_DIRECTIONAL_STATS = 15,
|
||||
MEASURE_TYPE_FTM_RANGE = 16,
|
||||
MEASURE_TYPE_MEASURE_PAUSE = 255,
|
||||
};
|
||||
|
||||
/* IEEE Std 802.11-2012 Table 8-71 - Location subject definition */
|
||||
enum location_subject {
|
||||
LOCATION_SUBJECT_LOCAL = 0,
|
||||
LOCATION_SUBJECT_REMOTE = 1,
|
||||
LOCATION_SUBJECT_3RD_PARTY = 2,
|
||||
};
|
||||
|
||||
/*
|
||||
* IEEE P802.11-REVmc/D5.0 Table 9-94 - Optional subelement IDs for LCI request
|
||||
*/
|
||||
enum lci_req_subelem {
|
||||
LCI_REQ_SUBELEM_AZIMUTH_REQ = 1,
|
||||
LCI_REQ_SUBELEM_ORIGINATOR_MAC_ADDR = 2,
|
||||
LCI_REQ_SUBELEM_TARGET_MAC_ADDR = 3,
|
||||
LCI_REQ_SUBELEM_MAX_AGE = 4,
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(push, 1)
|
||||
#endif /* _MSC_VER */
|
||||
@ -516,10 +579,7 @@ struct ieee80211_mgmt {
|
||||
* FH Params, DS Params, CF Params, IBSS Params, TIM */
|
||||
u8 variable[];
|
||||
} STRUCT_PACKED beacon;
|
||||
struct {
|
||||
/* only variable items: SSID, Supported rates */
|
||||
u8 variable[0];
|
||||
} STRUCT_PACKED probe_req;
|
||||
/* probe_req: only variable items: SSID, Supported rates */
|
||||
struct {
|
||||
u8 timestamp[8];
|
||||
le16 beacon_int;
|
||||
@ -625,12 +685,19 @@ struct ieee80211_mgmt {
|
||||
u8 action;
|
||||
u8 variable[];
|
||||
} STRUCT_PACKED fst_action;
|
||||
struct {
|
||||
u8 action;
|
||||
u8 dialog_token;
|
||||
u8 variable[];
|
||||
} STRUCT_PACKED rrm;
|
||||
} u;
|
||||
} STRUCT_PACKED action;
|
||||
} u;
|
||||
} STRUCT_PACKED;
|
||||
|
||||
|
||||
#define IEEE80211_MAX_MMPDU_SIZE 2304
|
||||
|
||||
/* Rx MCS bitmask is in the first 77 bits of supported_mcs_set */
|
||||
#define IEEE80211_HT_MCS_MASK_LEN 10
|
||||
|
||||
@ -690,9 +757,14 @@ struct ieee80211_ampe_ie {
|
||||
u8 selected_pairwise_suite[4];
|
||||
u8 local_nonce[32];
|
||||
u8 peer_nonce[32];
|
||||
u8 mgtk[16];
|
||||
u8 key_rsc[8];
|
||||
u8 key_expiration[4];
|
||||
/* Followed by
|
||||
* Key Replay Counter[8] (optional)
|
||||
* (only in Mesh Group Key Inform/Acknowledge frames)
|
||||
* GTKdata[variable] (optional)
|
||||
* (MGTK[variable] || Key RSC[8] || GTKExpirationTime[4])
|
||||
* IGTKdata[variable] (optional)
|
||||
* (Key ID[2], IPN[6], IGTK[variable] in IGTK KDE format)
|
||||
*/
|
||||
} STRUCT_PACKED;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
@ -879,6 +951,8 @@ struct ieee80211_ampe_ie {
|
||||
#define WFD_OUI_TYPE 10
|
||||
#define HS20_IE_VENDOR_TYPE 0x506f9a10
|
||||
#define OSEN_IE_VENDOR_TYPE 0x506f9a12
|
||||
#define MBO_IE_VENDOR_TYPE 0x506f9a16
|
||||
#define MBO_OUI_TYPE 22
|
||||
|
||||
#define WMM_OUI_TYPE 2
|
||||
#define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0
|
||||
@ -1021,6 +1095,95 @@ enum wmm_ac {
|
||||
#define HS20_DEAUTH_REASON_CODE_BSS 0
|
||||
#define HS20_DEAUTH_REASON_CODE_ESS 1
|
||||
|
||||
/* MBO v0.0_r19, 4.2: MBO Attributes */
|
||||
/* Table 4-5: MBO Attributes */
|
||||
enum mbo_attr_id {
|
||||
MBO_ATTR_ID_AP_CAPA_IND = 1,
|
||||
MBO_ATTR_ID_NON_PREF_CHAN_REPORT = 2,
|
||||
MBO_ATTR_ID_CELL_DATA_CAPA = 3,
|
||||
MBO_ATTR_ID_ASSOC_DISALLOW = 4,
|
||||
MBO_ATTR_ID_CELL_DATA_PREF = 5,
|
||||
MBO_ATTR_ID_TRANSITION_REASON = 6,
|
||||
MBO_ATTR_ID_TRANSITION_REJECT_REASON = 7,
|
||||
MBO_ATTR_ID_ASSOC_RETRY_DELAY = 8,
|
||||
};
|
||||
|
||||
/* MBO v0.0_r19, 4.2.1: MBO AP Capability Indication Attribute */
|
||||
/* Table 4-7: MBO AP Capability Indication Field Values */
|
||||
#define MBO_AP_CAPA_CELL_AWARE BIT(6)
|
||||
|
||||
/* MBO v0.0_r19, 4.2.2: Non-preferred Channel Report Attribute */
|
||||
/* Table 4-10: Reason Code Field Values */
|
||||
enum mbo_non_pref_chan_reason {
|
||||
MBO_NON_PREF_CHAN_REASON_UNSPECIFIED = 0,
|
||||
MBO_NON_PREF_CHAN_REASON_RSSI = 1,
|
||||
MBO_NON_PREF_CHAN_REASON_EXT_INTERFERENCE = 2,
|
||||
MBO_NON_PREF_CHAN_REASON_INT_INTERFERENCE = 3,
|
||||
};
|
||||
|
||||
/* MBO v0.0_r19, 4.2.3: Cellular Data Capabilities Attribute */
|
||||
/* Table 4-13: Cellular Data Connectivity Field */
|
||||
enum mbo_cellular_capa {
|
||||
MBO_CELL_CAPA_AVAILABLE = 1,
|
||||
MBO_CELL_CAPA_NOT_AVAILABLE = 2,
|
||||
MBO_CELL_CAPA_NOT_SUPPORTED = 3,
|
||||
};
|
||||
|
||||
/* MBO v0.0_r19, 4.2.4: Association Disallowed Attribute */
|
||||
/* Table 4-15: Reason Code Field Values */
|
||||
enum mbo_assoc_disallow_reason {
|
||||
MBO_ASSOC_DISALLOW_REASON_UNSPECIFIED = 1,
|
||||
MBO_ASSOC_DISALLOW_REASON_MAX_STA = 2,
|
||||
MBO_ASSOC_DISALLOW_REASON_AIR_INTERFERENCE = 3,
|
||||
MBO_ASSOC_DISALLOW_REASON_AUTH_SERVER_OVERLOAD = 4,
|
||||
MBO_ASSOC_DISALLOW_REASON_LOW_RSSI = 5,
|
||||
};
|
||||
|
||||
/* MBO v0.0_r19, 4.2.5: Cellular Data Connection Preference Attribute */
|
||||
/* Table 4-17: Cellular Preference Field Values */
|
||||
enum mbo_cell_pref {
|
||||
MBO_CELL_PREF_EXCLUDED = 0,
|
||||
MBO_CELL_PREF_NO_USE = 1,
|
||||
MBO_CELL_PREF_USE = 255
|
||||
};
|
||||
|
||||
/* MBO v0.0_r19, 4.2.6: Transition Reason Code Attribute */
|
||||
/* Table 4-19: Transition Reason Code Field Values */
|
||||
enum mbo_transition_reason {
|
||||
MBO_TRANSITION_REASON_UNSPECIFIED = 0,
|
||||
MBO_TRANSITION_REASON_FRAME_LOSS = 1,
|
||||
MBO_TRANSITION_REASON_DELAY = 2,
|
||||
MBO_TRANSITION_REASON_BANDWIDTH = 3,
|
||||
MBO_TRANSITION_REASON_LOAD_BALANCE = 4,
|
||||
MBO_TRANSITION_REASON_RSSI = 5,
|
||||
MBO_TRANSITION_REASON_RETRANSMISSIONS = 6,
|
||||
MBO_TRANSITION_REASON_INTERFERENCE = 7,
|
||||
MBO_TRANSITION_REASON_GRAY_ZONE = 8,
|
||||
MBO_TRANSITION_REASON_PREMIUM_AP = 9,
|
||||
};
|
||||
|
||||
/* MBO v0.0_r19, 4.2.7: Transition Rejection Reason Code Attribute */
|
||||
/* Table 4-21: Transition Rejection Reason Code Field Values */
|
||||
enum mbo_transition_reject_reason {
|
||||
MBO_TRANSITION_REJECT_REASON_UNSPECIFIED = 0,
|
||||
MBO_TRANSITION_REJECT_REASON_FRAME_LOSS = 1,
|
||||
MBO_TRANSITION_REJECT_REASON_DELAY = 2,
|
||||
MBO_TRANSITION_REJECT_REASON_QOS_CAPACITY = 3,
|
||||
MBO_TRANSITION_REJECT_REASON_RSSI = 4,
|
||||
MBO_TRANSITION_REJECT_REASON_INTERFERENCE = 5,
|
||||
MBO_TRANSITION_REJECT_REASON_SERVICES = 6,
|
||||
};
|
||||
|
||||
/* MBO v0.0_r19, 4.4: WNM-Notification vendor subelements */
|
||||
enum wfa_wnm_notif_subelem_id {
|
||||
WFA_WNM_NOTIF_SUBELEM_NON_PREF_CHAN_REPORT = 2,
|
||||
WFA_WNM_NOTIF_SUBELEM_CELL_DATA_CAPA = 3,
|
||||
};
|
||||
|
||||
/* MBO v0.0_r25, 4.3: MBO ANQP-elements */
|
||||
#define MBO_ANQP_OUI_TYPE 0x12
|
||||
#define MBO_ANQP_SUBTYPE_CELL_CONN_PREF 1
|
||||
|
||||
/* Wi-Fi Direct (P2P) */
|
||||
|
||||
#define P2P_OUI_TYPE 9
|
||||
@ -1178,6 +1341,14 @@ enum wifi_display_subelem {
|
||||
#define MESH_PATH_PROTOCOL_VENDOR 255
|
||||
#define MESH_PATH_METRIC_AIRTIME 1
|
||||
#define MESH_PATH_METRIC_VENDOR 255
|
||||
/* IEEE 802.11s - Mesh Capability */
|
||||
#define MESH_CAP_ACCEPT_ADDITIONAL_PEER BIT(0)
|
||||
#define MESH_CAP_MCCA_SUPPORTED BIT(1)
|
||||
#define MESH_CAP_MCCA_ENABLED BIT(2)
|
||||
#define MESH_CAP_FORWARDING BIT(3)
|
||||
#define MESH_CAP_MBCA_ENABLED BIT(4)
|
||||
#define MESH_CAP_TBTT_ADJUSTING BIT(5)
|
||||
#define MESH_CAP_MESH_PS_LEVEL BIT(6)
|
||||
|
||||
enum plink_action_field {
|
||||
PLINK_OPEN = 1,
|
||||
@ -1280,14 +1451,25 @@ enum bss_trans_mgmt_status_code {
|
||||
WNM_BSS_TM_REJECT_LEAVING_ESS = 8
|
||||
};
|
||||
|
||||
/*
|
||||
* IEEE P802.11-REVmc/D5.0 Table 9-150 - Optional subelement IDs for
|
||||
* neighbor report
|
||||
*/
|
||||
#define WNM_NEIGHBOR_TSF 1
|
||||
#define WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING 2
|
||||
#define WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE 3
|
||||
#define WNM_NEIGHBOR_BSS_TERMINATION_DURATION 4
|
||||
#define WNM_NEIGHBOR_BEARING 5
|
||||
#define WNM_NEIGHBOR_WIDE_BW_CHAN 6
|
||||
#define WNM_NEIGHBOR_MEASUREMENT_REPORT 39
|
||||
#define WNM_NEIGHBOR_HT_CAPAB 45
|
||||
#define WNM_NEIGHBOR_HT_OPER 61
|
||||
#define WNM_NEIGHBOR_SEC_CHAN_OFFSET 62
|
||||
#define WNM_NEIGHBOR_MEASUREMENT_PILOT 66
|
||||
#define WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES 70
|
||||
#define WNM_NEIGHBOR_MULTIPLE_BSSID 71
|
||||
#define WNM_NEIGHBOR_VHT_CAPAB 191
|
||||
#define WNM_NEIGHBOR_VHT_OPER 192
|
||||
|
||||
/* QoS action */
|
||||
enum qos_action {
|
||||
@ -1356,6 +1538,8 @@ struct tpc_report {
|
||||
u8 link_margin;
|
||||
} STRUCT_PACKED;
|
||||
|
||||
#define RRM_CAPABILITIES_IE_LEN 5
|
||||
|
||||
/* IEEE Std 802.11-2012, 8.5.7.4 - Link Measurement Request frame format */
|
||||
struct rrm_link_measurement_request {
|
||||
u8 dialog_token;
|
||||
@ -1375,8 +1559,6 @@ struct rrm_link_measurement_report {
|
||||
u8 variable[0];
|
||||
} STRUCT_PACKED;
|
||||
|
||||
#define SSID_MAX_LEN 32
|
||||
|
||||
/* IEEE Std 802.11ad-2012 - Multi-band element */
|
||||
struct multi_band_ie {
|
||||
u8 eid; /* WLAN_EID_MULTI_BAND */
|
||||
@ -1433,4 +1615,49 @@ enum fst_action {
|
||||
FST_ACTION_ON_CHANNEL_TUNNEL = 5,
|
||||
};
|
||||
|
||||
/* IEEE Std 802.11ac-2013, Annex C - dot11PHYType */
|
||||
enum phy_type {
|
||||
PHY_TYPE_UNSPECIFIED = 0,
|
||||
PHY_TYPE_FHSS = 1,
|
||||
PHY_TYPE_DSSS = 2,
|
||||
PHY_TYPE_IRBASEBAND = 3,
|
||||
PHY_TYPE_OFDM = 4,
|
||||
PHY_TYPE_HRDSSS = 5,
|
||||
PHY_TYPE_ERP = 6,
|
||||
PHY_TYPE_HT = 7,
|
||||
PHY_TYPE_DMG = 8,
|
||||
PHY_TYPE_VHT = 9,
|
||||
};
|
||||
|
||||
/* IEEE P802.11-REVmc/D5.0, 9.4.2.37 - Neighbor Report element */
|
||||
/* BSSID Information Field */
|
||||
#define NEI_REP_BSSID_INFO_AP_NOT_REACH BIT(0)
|
||||
#define NEI_REP_BSSID_INFO_AP_UNKNOWN_REACH BIT(1)
|
||||
#define NEI_REP_BSSID_INFO_AP_REACHABLE (BIT(0) | BIT(1))
|
||||
#define NEI_REP_BSSID_INFO_SECURITY BIT(2)
|
||||
#define NEI_REP_BSSID_INFO_KEY_SCOPE BIT(3)
|
||||
#define NEI_REP_BSSID_INFO_SPECTRUM_MGMT BIT(4)
|
||||
#define NEI_REP_BSSID_INFO_QOS BIT(5)
|
||||
#define NEI_REP_BSSID_INFO_APSD BIT(6)
|
||||
#define NEI_REP_BSSID_INFO_RM BIT(7)
|
||||
#define NEI_REP_BSSID_INFO_DELAYED_BA BIT(8)
|
||||
#define NEI_REP_BSSID_INFO_IMM_BA BIT(9)
|
||||
#define NEI_REP_BSSID_INFO_MOBILITY_DOMAIN BIT(10)
|
||||
#define NEI_REP_BSSID_INFO_HT BIT(11)
|
||||
#define NEI_REP_BSSID_INFO_VHT BIT(12)
|
||||
#define NEI_REP_BSSID_INFO_FTM BIT(13)
|
||||
|
||||
/*
|
||||
* IEEE P802.11-REVmc/D5.0 Table 9-152 - HT/VHT Operation Information
|
||||
* subfields.
|
||||
* Note: These definitions are not the same as other VHT_CHANWIDTH_*.
|
||||
*/
|
||||
enum nr_chan_width {
|
||||
NR_CHAN_WIDTH_20 = 0,
|
||||
NR_CHAN_WIDTH_40 = 1,
|
||||
NR_CHAN_WIDTH_80 = 2,
|
||||
NR_CHAN_WIDTH_160 = 3,
|
||||
NR_CHAN_WIDTH_80P80 = 4,
|
||||
};
|
||||
|
||||
#endif /* IEEE802_11_DEFS_H */
|
||||
|
@ -10,7 +10,7 @@
|
||||
#define IEEE802_1X_DEFS_H
|
||||
|
||||
#define CS_ID_LEN 8
|
||||
#define CS_ID_GCM_AES_128 {0x00, 0x80, 0x02, 0x00, 0x01, 0x00, 0x00, 0x01}
|
||||
#define CS_ID_GCM_AES_128 0x0080020001000001ULL
|
||||
#define CS_NAME_GCM_AES_128 "GCM-AES-128"
|
||||
|
||||
enum macsec_policy {
|
||||
|
24
src/common/linux_bridge.h
Normal file
24
src/common/linux_bridge.h
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Linux bridge configuration kernel interface
|
||||
* 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 LINUX_BRIDGE_H
|
||||
#define LINUX_BRIDGE_H
|
||||
|
||||
/* This interface is defined in linux/if_bridge.h */
|
||||
|
||||
#define BRCTL_GET_VERSION 0
|
||||
#define BRCTL_GET_BRIDGES 1
|
||||
#define BRCTL_ADD_BRIDGE 2
|
||||
#define BRCTL_DEL_BRIDGE 3
|
||||
#define BRCTL_ADD_IF 4
|
||||
#define BRCTL_DEL_IF 5
|
||||
#define BRCTL_GET_BRIDGE_INFO 6
|
||||
#define BRCTL_GET_PORT_LIST 7
|
||||
#define BRCTL_SET_BRIDGE_FORWARD_DELAY 8
|
||||
|
||||
#endif /* LINUX_BRIDGE_H */
|
52
src/common/linux_vlan.h
Normal file
52
src/common/linux_vlan.h
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Linux VLAN configuration kernel interface
|
||||
* 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 LINUX_VLAN_H
|
||||
#define LINUX_VLAN_H
|
||||
|
||||
/* This ioctl is defined in linux/sockios.h */
|
||||
|
||||
#ifndef SIOCSIFVLAN
|
||||
#define SIOCSIFVLAN 0x8983
|
||||
#endif /* SIOCSIFVLAN */
|
||||
|
||||
/* This interface is defined in linux/if_vlan.h */
|
||||
|
||||
#define ADD_VLAN_CMD 0
|
||||
#define DEL_VLAN_CMD 1
|
||||
#define SET_VLAN_INGRESS_PRIORITY_CMD 2
|
||||
#define SET_VLAN_EGRESS_PRIORITY_CMD 3
|
||||
#define GET_VLAN_INGRESS_PRIORITY_CMD 4
|
||||
#define GET_VLAN_EGRESS_PRIORITY_CMD 5
|
||||
#define SET_VLAN_NAME_TYPE_CMD 6
|
||||
#define SET_VLAN_FLAG_CMD 7
|
||||
#define GET_VLAN_REALDEV_NAME_CMD 8
|
||||
#define GET_VLAN_VID_CMD 9
|
||||
|
||||
#define VLAN_NAME_TYPE_PLUS_VID 0
|
||||
#define VLAN_NAME_TYPE_RAW_PLUS_VID 1
|
||||
#define VLAN_NAME_TYPE_PLUS_VID_NO_PAD 2
|
||||
#define VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD 3
|
||||
|
||||
struct vlan_ioctl_args {
|
||||
int cmd;
|
||||
char device1[24];
|
||||
|
||||
union {
|
||||
char device2[24];
|
||||
int VID;
|
||||
unsigned int skb_priority;
|
||||
unsigned int name_type;
|
||||
unsigned int bind_type;
|
||||
unsigned int flag;
|
||||
} u;
|
||||
|
||||
short vlan_qos;
|
||||
};
|
||||
|
||||
#endif /* LINUX_VLAN_H */
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Simultaneous authentication of equals
|
||||
* Copyright (c) 2012-2015, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2012-2016, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -275,8 +275,9 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
|
||||
|
||||
/* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */
|
||||
bits = crypto_ec_prime_len_bits(sae->tmp->ec);
|
||||
sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
|
||||
prime, sae->tmp->prime_len, pwd_value, bits);
|
||||
if (sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
|
||||
prime, sae->tmp->prime_len, pwd_value, bits) < 0)
|
||||
return -1;
|
||||
if (bits % 8)
|
||||
buf_shift_right(pwd_value, sizeof(pwd_value), 8 - bits % 8);
|
||||
wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value",
|
||||
@ -318,11 +319,10 @@ static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed,
|
||||
wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
|
||||
|
||||
/* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */
|
||||
sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
|
||||
sae->tmp->dh->prime, sae->tmp->prime_len, pwd_value,
|
||||
bits);
|
||||
if (bits % 8)
|
||||
buf_shift_right(pwd_value, sizeof(pwd_value), 8 - bits % 8);
|
||||
if (sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
|
||||
sae->tmp->dh->prime, sae->tmp->prime_len, pwd_value,
|
||||
bits) < 0)
|
||||
return -1;
|
||||
wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value", pwd_value,
|
||||
sae->tmp->prime_len);
|
||||
|
||||
@ -811,11 +811,13 @@ static int sae_derive_keys(struct sae_data *sae, const u8 *k)
|
||||
crypto_bignum_mod(tmp, sae->tmp->order, tmp);
|
||||
crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->prime_len);
|
||||
wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_LEN);
|
||||
sha256_prf(keyseed, sizeof(keyseed), "SAE KCK and PMK",
|
||||
val, sae->tmp->prime_len, keys, sizeof(keys));
|
||||
if (sha256_prf(keyseed, sizeof(keyseed), "SAE KCK and PMK",
|
||||
val, sae->tmp->prime_len, keys, sizeof(keys)) < 0)
|
||||
goto fail;
|
||||
os_memset(keyseed, 0, sizeof(keyseed));
|
||||
os_memcpy(sae->tmp->kck, keys, SAE_KCK_LEN);
|
||||
os_memcpy(sae->pmk, keys + SAE_KCK_LEN, SAE_PMK_LEN);
|
||||
os_memcpy(sae->pmkid, val, SAE_PMKID_LEN);
|
||||
os_memset(keys, 0, sizeof(keys));
|
||||
wpa_hexdump_key(MSG_DEBUG, "SAE: KCK", sae->tmp->kck, SAE_KCK_LEN);
|
||||
wpa_hexdump_key(MSG_DEBUG, "SAE: PMK", sae->pmk, SAE_PMK_LEN);
|
||||
@ -923,7 +925,7 @@ static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos,
|
||||
const u8 *end, const u8 **token,
|
||||
size_t *token_len)
|
||||
{
|
||||
if (*pos + (sae->tmp->ec ? 3 : 2) * sae->tmp->prime_len < end) {
|
||||
if ((sae->tmp->ec ? 3 : 2) * sae->tmp->prime_len < end - *pos) {
|
||||
size_t tlen = end - (*pos + (sae->tmp->ec ? 3 : 2) *
|
||||
sae->tmp->prime_len);
|
||||
wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token", *pos, tlen);
|
||||
@ -946,7 +948,7 @@ static u16 sae_parse_commit_scalar(struct sae_data *sae, const u8 **pos,
|
||||
{
|
||||
struct crypto_bignum *peer_scalar;
|
||||
|
||||
if (*pos + sae->tmp->prime_len > end) {
|
||||
if (sae->tmp->prime_len > end - *pos) {
|
||||
wpa_printf(MSG_DEBUG, "SAE: Not enough data for scalar");
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
}
|
||||
@ -994,7 +996,7 @@ static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 *pos,
|
||||
{
|
||||
u8 prime[SAE_MAX_ECC_PRIME_LEN];
|
||||
|
||||
if (pos + 2 * sae->tmp->prime_len > end) {
|
||||
if (2 * sae->tmp->prime_len > end - pos) {
|
||||
wpa_printf(MSG_DEBUG, "SAE: Not enough data for "
|
||||
"commit-element");
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
@ -1040,7 +1042,7 @@ static u16 sae_parse_commit_element_ffc(struct sae_data *sae, const u8 *pos,
|
||||
struct crypto_bignum *res, *one;
|
||||
const u8 one_bin[1] = { 0x01 };
|
||||
|
||||
if (pos + sae->tmp->prime_len > end) {
|
||||
if (sae->tmp->prime_len > end - pos) {
|
||||
wpa_printf(MSG_DEBUG, "SAE: Not enough data for "
|
||||
"commit-element");
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
@ -1098,7 +1100,7 @@ u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
|
||||
u16 res;
|
||||
|
||||
/* Check Finite Cyclic Group */
|
||||
if (pos + 2 > end)
|
||||
if (end - pos < 2)
|
||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||
res = sae_group_allowed(sae, allowed_groups, WPA_GET_LE16(pos));
|
||||
if (res != WLAN_STATUS_SUCCESS)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user