Import wpa_supplicant/hostapd 2.6.

This commit is contained in:
Cy Schubert 2017-10-18 03:44:27 +00:00
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
495 changed files with 51488 additions and 10220 deletions

View File

@ -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

View File

@ -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
View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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)

View File

@ -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

View File

@ -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
View 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

View File

@ -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

View File

@ -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

View File

@ -9,6 +9,7 @@
#include "utils/includes.h"
#include "utils/common.h"
#include "utils/module_tests.h"
int hapd_module_tests(void)
{

View File

@ -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>] "

View 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

View File

@ -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"

View File

@ -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 */

View File

@ -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();

View File

@ -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

View File

@ -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)

View File

@ -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;

View File

@ -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) {

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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 *

View File

@ -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, &params);
}
@ -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;

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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, &params)) {
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 "

View File

@ -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;
}

View File

@ -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 */

View File

@ -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);
}

View File

@ -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 */

View File

@ -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;
}

View File

@ -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)

View File

@ -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 */

View File

@ -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;
}
}

View File

@ -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 \

View File

@ -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)
{

View File

@ -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,

View File

@ -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 "

View File

@ -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

View File

@ -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 */

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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);
}

View File

@ -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;

View File

@ -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,

View File

@ -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
View 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
View 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 */

View File

@ -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
View 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
View 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 */

View File

@ -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;
}

View File

@ -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
View 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
View 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 */

View File

@ -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;

View File

@ -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
View 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
View 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
View 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
View 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
View 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
View 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

View File

@ -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
View 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;
}

View File

@ -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;
}

View File

@ -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 */

View File

@ -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");

View File

@ -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 */

View File

@ -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;

View File

@ -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 */

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
};

View File

@ -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));

View File

@ -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
View 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
View 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 */

View File

@ -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"

View 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;
}

View 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 */

View File

@ -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 */

View File

@ -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

View File

@ -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;
}

View File

@ -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 */

View File

@ -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 */

View File

@ -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
View 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
View 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

View File

@ -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