am 0ba3bc84: am 0a217de1: Don\'t write to wpa_supplicant.conf directly
* commit '0ba3bc8468786818a30a9e8e530246ce936cd458':
Don't write to wpa_supplicant.conf directly
diff --git a/CONTRIBUTIONS b/CONTRIBUTIONS
index d20a556..ca09bae 100644
--- a/CONTRIBUTIONS
+++ b/CONTRIBUTIONS
@@ -112,7 +112,7 @@
Modified BSD license (no advertisement clause):
-Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/COPYING b/COPYING
index 8a98582..5962e2f 100644
--- a/COPYING
+++ b/COPYING
@@ -1,7 +1,7 @@
wpa_supplicant and hostapd
--------------------------
-Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
diff --git a/README b/README
index 8de14a6..07d1d25 100644
--- a/README
+++ b/README
@@ -1,7 +1,7 @@
wpa_supplicant and hostapd
--------------------------
-Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
These programs are licensed under the BSD license (the one with
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index a0e0e5d..df4bb41 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -94,6 +94,7 @@
OBJS += src/ap/pmksa_cache_auth.c
OBJS += src/ap/ieee802_11_shared.c
OBJS += src/ap/beacon.c
+OBJS += src/ap/bss_load.c
OBJS_d =
OBJS_p =
LIBS =
@@ -132,6 +133,7 @@
OBJS += src/common/ieee802_11_common.c
OBJS += src/common/wpa_common.c
+OBJS += src/common/hw_features_common.c
OBJS += src/eapol_auth/eapol_auth_sm.c
@@ -199,6 +201,22 @@
ifdef CONFIG_HS20
NEED_AES_OMAC1=y
+CONFIG_PROXYARP=y
+endif
+
+ifdef CONFIG_PROXYARP
+CONFIG_L2_PACKET=y
+endif
+
+ifdef CONFIG_SUITEB
+L_CFLAGS += -DCONFIG_SUITEB
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
+ifdef CONFIG_SUITEB192
+L_CFLAGS += -DCONFIG_SUITEB192
+NEED_SHA384=y
endif
ifdef CONFIG_IEEE80211W
@@ -552,22 +570,6 @@
CONFIG_INTERNAL_DH_GROUP5=y
endif
-ifeq ($(CONFIG_TLS), nss)
-ifdef TLS_FUNCS
-OBJS += src/crypto/tls_nss.c
-LIBS += -lssl3
-endif
-OBJS += src/crypto/crypto_nss.c
-ifdef NEED_FIPS186_2_PRF
-OBJS += src/crypto/fips_prf_internal.c
-OBJS += src/crypto/sha1-internal.c
-endif
-LIBS += -lnss3
-LIBS_h += -lnss3
-CONFIG_INTERNAL_MD4=y
-CONFIG_INTERNAL_DH_GROUP5=y
-endif
-
ifeq ($(CONFIG_TLS), internal)
ifndef CONFIG_CRYPTO
CONFIG_CRYPTO=internal
@@ -770,6 +772,9 @@
OBJS += src/crypto/sha256-tlsprf.c
endif
endif
+ifdef NEED_SHA384
+L_CFLAGS += -DCONFIG_SHA384
+endif
ifdef NEED_DH_GROUPS
OBJS += src/crypto/dh_groups.c
@@ -853,6 +858,15 @@
OBJS += src/ap/gas_serv.c
endif
+ifdef CONFIG_PROXYARP
+L_CFLAGS += -DCONFIG_PROXYARP
+OBJS += src/ap/x_snoop.c
+OBJS += src/ap/dhcp_snoop.c
+ifdef CONFIG_IPV6
+OBJS += src/ap/ndisc_snoop.c
+endif
+endif
+
OBJS += src/drivers/driver_common.c
ifdef CONFIG_ACS
diff --git a/hostapd/Makefile b/hostapd/Makefile
index ac6373e..894b652 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -9,6 +9,8 @@
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
@@ -59,6 +61,7 @@
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_c = hostapd_cli.o ../src/common/wpa_ctrl.o ../src/utils/os_$(CONFIG_OS).o
@@ -112,6 +115,7 @@
OBJS += ../src/common/ieee802_11_common.o
OBJS += ../src/common/wpa_common.o
+OBJS += ../src/common/hw_features_common.o
OBJS += ../src/eapol_auth/eapol_auth_sm.o
@@ -187,6 +191,22 @@
ifdef CONFIG_HS20
NEED_AES_OMAC1=y
+CONFIG_PROXYARP=y
+endif
+
+ifdef CONFIG_PROXYARP
+CONFIG_L2_PACKET=y
+endif
+
+ifdef CONFIG_SUITEB
+CFLAGS += -DCONFIG_SUITEB
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
+ifdef CONFIG_SUITEB192
+CFLAGS += -DCONFIG_SUITEB192
+NEED_SHA384=y
endif
ifdef CONFIG_IEEE80211W
@@ -246,6 +266,12 @@
endif
+ifdef CONFIG_ERP
+CFLAGS += -DCONFIG_ERP
+NEED_SHA256=y
+NEED_HMAC_SHA256_KDF=y
+endif
+
ifdef CONFIG_EAP_MD5
CFLAGS += -DEAP_SERVER_MD5
OBJS += ../src/eap_server/eap_server_md5.o
@@ -539,22 +565,6 @@
CONFIG_INTERNAL_DH_GROUP5=y
endif
-ifeq ($(CONFIG_TLS), nss)
-ifdef TLS_FUNCS
-OBJS += ../src/crypto/tls_nss.o
-LIBS += -lssl3
-endif
-OBJS += ../src/crypto/crypto_nss.o
-ifdef NEED_FIPS186_2_PRF
-OBJS += ../src/crypto/fips_prf_internal.o
-SHA1OBJS += ../src/crypto/sha1-internal.o
-endif
-LIBS += -lnss3
-LIBS_h += -lnss3
-CONFIG_INTERNAL_MD4=y
-CONFIG_INTERNAL_DH_GROUP5=y
-endif
-
ifeq ($(CONFIG_TLS), internal)
ifndef CONFIG_CRYPTO
CONFIG_CRYPTO=internal
@@ -755,6 +765,12 @@
ifdef NEED_TLS_PRF_SHA256
OBJS += ../src/crypto/sha256-tlsprf.o
endif
+ifdef NEED_HMAC_SHA256_KDF
+OBJS += ../src/crypto/sha256-kdf.o
+endif
+endif
+ifdef NEED_SHA384
+CFLAGS += -DCONFIG_SHA384
endif
ifdef NEED_DH_GROUPS
@@ -839,6 +855,15 @@
OBJS += ../src/ap/gas_serv.o
endif
+ifdef CONFIG_PROXYARP
+CFLAGS += -DCONFIG_PROXYARP
+OBJS += ../src/ap/x_snoop.o
+OBJS += ../src/ap/dhcp_snoop.o
+ifdef CONFIG_IPV6
+OBJS += ../src/ap/ndisc_snoop.o
+endif
+endif
+
OBJS += ../src/drivers/driver_common.o
ifdef CONFIG_WPA_CLI_EDIT
@@ -881,6 +906,10 @@
Q=
E=true
endif
+ifeq ($(QUIET), 1)
+Q=@
+E=true
+endif
ifdef CONFIG_CODE_COVERAGE
%.o: %.c
@@ -901,9 +930,10 @@
exit 1; \
fi
-install: all
- mkdir -p $(DESTDIR)/usr/local/bin
- for i in $(ALL); do cp -f $$i $(DESTDIR)/usr/local/bin/$$i; done
+$(DESTDIR)$(BINDIR)/%: %
+ install -D $(<) $(@)
+
+install: $(addprefix $(DESTDIR)$(BINDIR)/,$(ALL))
../src/drivers/build.hostapd:
@if [ -f ../src/drivers/build.wpa_supplicant ]; then \
@@ -925,6 +955,7 @@
@$(E) " LD " $@
NOBJS = nt_password_hash.o ../src/crypto/ms_funcs.o $(SHA1OBJS) ../src/crypto/md5.o
+NOBJS += ../src/utils/common.o
ifdef NEED_RC4
ifdef CONFIG_INTERNAL_RC4
NOBJS += ../src/crypto/rc4.o
diff --git a/hostapd/README b/hostapd/README
index 50868ee..366b199 100644
--- a/hostapd/README
+++ b/hostapd/README
@@ -2,7 +2,7 @@
Authenticator and RADIUS authentication server
================================================================
-Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
This program is licensed under the BSD license (the one with
@@ -74,12 +74,6 @@
Please note that station firmware version needs to be 1.7.0 or newer
to work in WPA mode.
- madwifi driver for cards based on Atheros chip set (ar521x)
- (http://sourceforge.net/projects/madwifi/)
- Please note that you will need to add the correct path for
- madwifi driver root directory in .config (see defconfig file for
- an example: CFLAGS += -I<path>)
-
mac80211-based drivers that support AP mode (with driver=nl80211).
This includes drivers for Atheros (ath9k) and Broadcom (b43)
chipsets.
diff --git a/hostapd/README-WPS b/hostapd/README-WPS
index bb7d35f..d5f713a 100644
--- a/hostapd/README-WPS
+++ b/hostapd/README-WPS
@@ -58,10 +58,9 @@
WPS is an optional component that needs to be enabled in hostapd build
configuration (.config). Here is an example configuration that
-includes WPS support and uses madwifi driver interface:
+includes WPS support and uses nl80211 driver interface:
-CONFIG_DRIVER_MADWIFI=y
-CFLAGS += -I/usr/src/madwifi-0.9.3
+CONFIG_DRIVER_NL80211=y
CONFIG_WPS=y
CONFIG_WPS_UPNP=y
@@ -74,8 +73,8 @@
(hostapd.conf) that enables WPS:
# Configure the driver and network interface
-driver=madwifi
-interface=ath0
+driver=nl80211
+interface=wlan0
# WPA2-Personal configuration for the AP
ssid=wps-test
diff --git a/hostapd/android.config b/hostapd/android.config
index ad83308..938aa54 100644
--- a/hostapd/android.config
+++ b/hostapd/android.config
@@ -15,10 +15,6 @@
# Driver interface for wired authenticator
#CONFIG_DRIVER_WIRED=y
-# Driver interface for madwifi driver
-#CONFIG_DRIVER_MADWIFI=y
-#CFLAGS += -I../../madwifi # change to the madwifi source directory
-
# 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
@@ -132,7 +128,7 @@
#CONFIG_IEEE80211R=y
# Use the hostapd's IEEE 802.11 authentication (ACL), but without
-# the IEEE 802.11 Management capability (e.g., madwifi or FreeBSD/net80211)
+# the IEEE 802.11 Management capability (e.g., FreeBSD/net80211)
#CONFIG_DRIVER_RADIUS_ACL=y
# IEEE 802.11n (High Throughput) support
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 44de826..7cbb46b 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -1,6 +1,6 @@
/*
* hostapd / Configuration file parser
- * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -680,6 +680,14 @@
else if (os_strcmp(start, "FT-SAE") == 0)
val |= WPA_KEY_MGMT_FT_SAE;
#endif /* CONFIG_SAE */
+#ifdef CONFIG_SUITEB
+ else if (os_strcmp(start, "WPA-EAP-SUITE-B") == 0)
+ val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B;
+#endif /* CONFIG_SUITEB */
+#ifdef CONFIG_SUITEB192
+ else if (os_strcmp(start, "WPA-EAP-SUITE-B-192") == 0)
+ val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
+#endif /* CONFIG_SUITEB192 */
else {
wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
line, start);
@@ -1865,6 +1873,9 @@
line, pos);
return 1;
}
+ } else if (os_strcmp(buf, "driver_params") == 0) {
+ os_free(conf->driver_params);
+ conf->driver_params = os_strdup(pos);
} else if (os_strcmp(buf, "debug") == 0) {
wpa_printf(MSG_DEBUG, "Line %d: DEPRECATED: 'debug' configuration variable is not used anymore",
line);
@@ -1984,6 +1995,9 @@
} else if (os_strcmp(buf, "dh_file") == 0) {
os_free(bss->dh_file);
bss->dh_file = os_strdup(pos);
+ } else if (os_strcmp(buf, "openssl_ciphers") == 0) {
+ os_free(bss->openssl_ciphers);
+ bss->openssl_ciphers = os_strdup(pos);
} else if (os_strcmp(buf, "fragment_size") == 0) {
bss->fragment_size = atoi(pos);
#ifdef EAP_SERVER_FAST
@@ -2044,6 +2058,8 @@
} else if (os_strcmp(buf, "pwd_group") == 0) {
bss->pwd_group = atoi(pos);
#endif /* EAP_SERVER_PWD */
+ } else if (os_strcmp(buf, "eap_server_erp") == 0) {
+ bss->eap_server_erp = atoi(pos);
#endif /* EAP_SERVER */
} else if (os_strcmp(buf, "eap_message") == 0) {
char *term;
@@ -2063,6 +2079,11 @@
(term - bss->eap_req_id_text) - 1);
bss->eap_req_id_text_len--;
}
+ } else if (os_strcmp(buf, "erp_send_reauth_start") == 0) {
+ bss->erp_send_reauth_start = atoi(pos);
+ } else if (os_strcmp(buf, "erp_domain") == 0) {
+ os_free(bss->erp_domain);
+ bss->erp_domain = os_strdup(pos);
} else if (os_strcmp(buf, "wep_key_len_broadcast") == 0) {
bss->default_wep_key_len = atoi(pos);
if (bss->default_wep_key_len > 13) {
@@ -2405,9 +2426,6 @@
} else if (os_strcmp(buf, "radius_server_ipv6") == 0) {
bss->radius_server_ipv6 = atoi(pos);
#endif /* RADIUS_SERVER */
- } else if (os_strcmp(buf, "test_socket") == 0) {
- os_free(bss->test_socket);
- bss->test_socket = os_strdup(pos);
} else if (os_strcmp(buf, "use_pae_group_addr") == 0) {
bss->use_pae_group_addr = atoi(pos);
} else if (os_strcmp(buf, "hw_mode") == 0) {
@@ -2486,6 +2504,15 @@
line, bss->dtim_period);
return 1;
}
+ } else if (os_strcmp(buf, "bss_load_update_period") == 0) {
+ bss->bss_load_update_period = atoi(pos);
+ if (bss->bss_load_update_period < 0 ||
+ bss->bss_load_update_period > 100) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid bss_load_update_period %d",
+ line, bss->bss_load_update_period);
+ return 1;
+ }
} else if (os_strcmp(buf, "rts_threshold") == 0) {
conf->rts_threshold = atoi(pos);
if (conf->rts_threshold < 0 || conf->rts_threshold > 2347) {
@@ -2669,6 +2696,8 @@
conf->vht_oper_centr_freq_seg0_idx = atoi(pos);
} else if (os_strcmp(buf, "vht_oper_centr_freq_seg1_idx") == 0) {
conf->vht_oper_centr_freq_seg1_idx = atoi(pos);
+ } else if (os_strcmp(buf, "vendor_vht") == 0) {
+ bss->vendor_vht = atoi(pos);
#endif /* CONFIG_IEEE80211AC */
} else if (os_strcmp(buf, "max_listen_interval") == 0) {
bss->max_listen_interval = atoi(pos);
@@ -2996,6 +3025,8 @@
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, "osen") == 0) {
bss->osen = atoi(pos);
} else if (os_strcmp(buf, "anqp_domain_id") == 0) {
@@ -3106,6 +3137,8 @@
pos++;
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);
#endif /* CONFIG_TESTING_OPTIONS */
} else if (os_strcmp(buf, "vendor_elements") == 0) {
struct wpabuf *elems;
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 591c395..54b17dc 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -1,6 +1,6 @@
/*
* hostapd / UNIX domain socket -based control interface
- * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,6 +10,11 @@
#ifndef CONFIG_NATIVE_WINDOWS
+#ifdef CONFIG_TESTING_OPTIONS
+#include <net/ethernet.h>
+#include <netinet/ip.h>
+#endif /* CONFIG_TESTING_OPTIONS */
+
#include <sys/un.h>
#include <sys/stat.h>
#include <stddef.h>
@@ -18,9 +23,11 @@
#include "utils/eloop.h"
#include "common/version.h"
#include "common/ieee802_11_defs.h"
+#include "crypto/tls.h"
#include "drivers/driver.h"
#include "radius/radius_client.h"
#include "radius/radius_server.h"
+#include "l2_packet/l2_packet.h"
#include "ap/hostapd.h"
#include "ap/ap_config.h"
#include "ap/ieee802_1x.h"
@@ -240,14 +247,14 @@
if (!wps_pin_valid(pin_val)) {
wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
- if (ret < 0 || (size_t) ret >= buflen)
+ if (os_snprintf_error(buflen, ret))
return -1;
return ret;
}
}
ret = os_snprintf(buf, buflen, "%s", pin);
- if (ret < 0 || (size_t) ret >= buflen)
+ if (os_snprintf_error(buflen, ret))
return -1;
return ret;
@@ -578,7 +585,7 @@
ret = os_snprintf(pos, end - pos, "PBC Status: %s\n",
pbc_status_str(hapd->wps_stats.pbc_status));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -588,7 +595,7 @@
(hapd->wps_stats.status == WPS_STATUS_FAILURE ?
"Failed" : "None")));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -599,7 +606,7 @@
"Failure Reason: %s\n",
wps_ei_str(hapd->wps_stats.failure_reason));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -608,7 +615,7 @@
ret = os_snprintf(pos, end - pos, "Peer Address: " MACSTR "\n",
MAC2STR(hapd->wps_stats.peer_addr));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -857,6 +864,193 @@
return wnm_send_ess_disassoc_imminent(hapd, sta, url, disassoc_timer);
}
+
+static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
+ const char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ const char *pos, *end;
+ int disassoc_timer = 0;
+ struct sta_info *sta;
+ u8 req_mode = 0, valid_int = 0x01;
+ u8 bss_term_dur[12];
+ char *url = NULL;
+ int ret;
+ u8 nei_rep[1000];
+ u8 *nei_pos = nei_rep;
+
+ if (hwaddr_aton(cmd, addr)) {
+ wpa_printf(MSG_DEBUG, "Invalid STA MAC address");
+ return -1;
+ }
+
+ sta = ap_get_sta(hapd, addr);
+ if (sta == NULL) {
+ wpa_printf(MSG_DEBUG, "Station " MACSTR
+ " not found for BSS TM Request message",
+ MAC2STR(addr));
+ return -1;
+ }
+
+ pos = os_strstr(cmd, " disassoc_timer=");
+ if (pos) {
+ pos += 16;
+ disassoc_timer = atoi(pos);
+ if (disassoc_timer < 0 || disassoc_timer > 65535) {
+ wpa_printf(MSG_DEBUG, "Invalid disassoc_timer");
+ return -1;
+ }
+ }
+
+ pos = os_strstr(cmd, " valid_int=");
+ if (pos) {
+ pos += 11;
+ valid_int = atoi(pos);
+ }
+
+ pos = os_strstr(cmd, " bss_term=");
+ if (pos) {
+ pos += 10;
+ req_mode |= WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED;
+ /* TODO: TSF configurable/learnable */
+ bss_term_dur[0] = 4; /* Subelement ID */
+ bss_term_dur[1] = 10; /* Length */
+ os_memset(bss_term_dur, 2, 8);
+ end = os_strchr(pos, ',');
+ if (end == NULL) {
+ wpa_printf(MSG_DEBUG, "Invalid bss_term data");
+ return -1;
+ }
+ end++;
+ WPA_PUT_LE16(&bss_term_dur[10], atoi(end));
+ }
+
+
+ /*
+ * BSS Transition Candidate List Entries - Neighbor Report elements
+ * neighbor=<BSSID>,<BSSID Information>,<Operating Class>,
+ * <Channel Number>,<PHY Type>[,<hexdump of Optional Subelements>]
+ */
+ pos = cmd;
+ while (pos) {
+ u8 *nei_start;
+ long int val;
+ char *endptr, *tmp;
+
+ pos = os_strstr(pos, " neighbor=");
+ if (!pos)
+ break;
+ if (nei_pos + 15 > nei_rep + sizeof(nei_rep)) {
+ wpa_printf(MSG_DEBUG,
+ "Not enough room for additional neighbor");
+ return -1;
+ }
+ pos += 10;
+
+ nei_start = nei_pos;
+ *nei_pos++ = WLAN_EID_NEIGHBOR_REPORT;
+ nei_pos++; /* length to be filled in */
+
+ if (hwaddr_aton(pos, nei_pos)) {
+ wpa_printf(MSG_DEBUG, "Invalid BSSID");
+ return -1;
+ }
+ nei_pos += ETH_ALEN;
+ pos += 17;
+ if (*pos != ',') {
+ wpa_printf(MSG_DEBUG, "Missing BSSID Information");
+ return -1;
+ }
+ pos++;
+
+ val = strtol(pos, &endptr, 0);
+ WPA_PUT_LE32(nei_pos, val);
+ nei_pos += 4;
+ if (*endptr != ',') {
+ wpa_printf(MSG_DEBUG, "Missing Operating Class");
+ return -1;
+ }
+ pos = endptr + 1;
+
+ *nei_pos++ = atoi(pos); /* Operating Class */
+ pos = os_strchr(pos, ',');
+ if (pos == NULL) {
+ wpa_printf(MSG_DEBUG, "Missing Channel Number");
+ return -1;
+ }
+ pos++;
+
+ *nei_pos++ = atoi(pos); /* Channel Number */
+ pos = os_strchr(pos, ',');
+ if (pos == NULL) {
+ wpa_printf(MSG_DEBUG, "Missing PHY Type");
+ return -1;
+ }
+ pos++;
+
+ *nei_pos++ = atoi(pos); /* PHY Type */
+ end = os_strchr(pos, ' ');
+ tmp = os_strchr(pos, ',');
+ if (tmp && (!end || tmp < end)) {
+ /* Optional Subelements (hexdump) */
+ size_t len;
+
+ pos = tmp + 1;
+ end = os_strchr(pos, ' ');
+ if (end)
+ len = end - pos;
+ else
+ len = os_strlen(pos);
+ if (nei_pos + len / 2 > nei_rep + sizeof(nei_rep)) {
+ wpa_printf(MSG_DEBUG,
+ "Not enough room for neighbor subelements");
+ return -1;
+ }
+ if (len & 0x01 ||
+ hexstr2bin(pos, nei_pos, len / 2) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "Invalid neighbor subelement info");
+ return -1;
+ }
+ nei_pos += len / 2;
+ pos = end;
+ }
+
+ nei_start[1] = nei_pos - nei_start - 2;
+ }
+
+ pos = os_strstr(cmd, " url=");
+ if (pos) {
+ size_t len;
+ pos += 5;
+ end = os_strchr(pos, ' ');
+ if (end)
+ len = end - pos;
+ else
+ len = os_strlen(pos);
+ url = os_malloc(len + 1);
+ if (url == NULL)
+ return -1;
+ os_memcpy(url, pos, len);
+ url[len] = '\0';
+ req_mode |= WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
+ }
+
+ if (os_strstr(cmd, " pref=1"))
+ req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED;
+ if (os_strstr(cmd, " abridged=1"))
+ req_mode |= WNM_BSS_TM_REQ_ABRIDGED;
+ if (os_strstr(cmd, " disassoc_imminent=1"))
+ req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
+
+ ret = wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer,
+ valid_int, bss_term_dur, url,
+ nei_pos > nei_rep ? nei_rep : NULL,
+ nei_pos - nei_rep);
+ os_free(url);
+ return ret;
+}
+
#endif /* CONFIG_WNM */
@@ -874,7 +1068,7 @@
MAC2STR(hapd->own_addr),
wpa_ssid_txt(hapd->conf->ssid.ssid,
hapd->conf->ssid.ssid_len));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -883,7 +1077,7 @@
hapd->conf->wps_state == 0 ? "disabled" :
(hapd->conf->wps_state == 1 ? "not configured" :
"configured"));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -891,7 +1085,7 @@
hapd->conf->ssid.wpa_passphrase) {
ret = os_snprintf(pos, end - pos, "passphrase=%s\n",
hapd->conf->ssid.wpa_passphrase);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -903,7 +1097,7 @@
wpa_snprintf_hex(hex, sizeof(hex),
hapd->conf->ssid.wpa_psk->psk, PMK_LEN);
ret = os_snprintf(pos, end - pos, "psk=%s\n", hex);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -911,39 +1105,39 @@
if (hapd->conf->wpa && hapd->conf->wpa_key_mgmt) {
ret = os_snprintf(pos, end - pos, "key_mgmt=");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
ret = os_snprintf(pos, end - pos, "WPA-PSK ");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
ret = os_snprintf(pos, end - pos, "WPA-EAP ");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
#ifdef CONFIG_IEEE80211R
if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
ret = os_snprintf(pos, end - pos, "FT-PSK ");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
ret = os_snprintf(pos, end - pos, "FT-EAP ");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
#ifdef CONFIG_SAE
if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) {
ret = os_snprintf(pos, end - pos, "FT-SAE ");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -952,13 +1146,13 @@
#ifdef CONFIG_IEEE80211W
if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
ret = os_snprintf(pos, end - pos, "WPA-PSK-SHA256 ");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
ret = os_snprintf(pos, end - pos, "WPA-EAP-SHA256 ");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -966,14 +1160,28 @@
#ifdef CONFIG_SAE
if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) {
ret = os_snprintf(pos, end - pos, "SAE ");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
#endif /* CONFIG_SAE */
+ if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
+ ret = os_snprintf(pos, end - pos, "WPA-EAP-SUITE-B ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+ if (hapd->conf->wpa_key_mgmt &
+ WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
+ ret = os_snprintf(pos, end - pos,
+ "WPA-EAP-SUITE-B-192 ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
ret = os_snprintf(pos, end - pos, "\n");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -981,14 +1189,14 @@
if (hapd->conf->wpa) {
ret = os_snprintf(pos, end - pos, "group_cipher=%s\n",
wpa_cipher_txt(hapd->conf->wpa_group));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->rsn_pairwise) {
ret = os_snprintf(pos, end - pos, "rsn_pairwise_cipher=");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -999,14 +1207,14 @@
pos += ret;
ret = os_snprintf(pos, end - pos, "\n");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
if ((hapd->conf->wpa & WPA_PROTO_WPA) && hapd->conf->wpa_pairwise) {
ret = os_snprintf(pos, end - pos, "wpa_pairwise_cipher=");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -1017,7 +1225,7 @@
pos += ret;
ret = os_snprintf(pos, end - pos, "\n");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -1074,6 +1282,8 @@
#ifdef CONFIG_TESTING_OPTIONS
} else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) {
hapd->ext_mgmt_frame_handling = atoi(value);
+ } else if (os_strcasecmp(cmd, "ext_eapol_frame_io") == 0) {
+ hapd->ext_eapol_frame_io = atoi(value);
#endif /* CONFIG_TESTING_OPTIONS */
} else {
struct sta_info *sta;
@@ -1122,7 +1332,12 @@
if (os_strcmp(cmd, "version") == 0) {
res = os_snprintf(buf, buflen, "%s", VERSION_STR);
- if (res < 0 || (unsigned int) res >= buflen)
+ if (os_snprintf_error(buflen, res))
+ return -1;
+ return res;
+ } else if (os_strcmp(cmd, "tls_library") == 0) {
+ res = tls_get_library_version(buf, buflen);
+ if (os_snprintf_error(buflen, res))
return -1;
return res;
}
@@ -1249,6 +1464,287 @@
return res;
}
+
+static int hostapd_ctrl_iface_eapol_rx(struct hostapd_data *hapd, char *cmd)
+{
+ char *pos;
+ u8 src[ETH_ALEN], *buf;
+ int used;
+ size_t len;
+
+ wpa_printf(MSG_DEBUG, "External EAPOL RX: %s", cmd);
+
+ pos = cmd;
+ used = hwaddr_aton2(pos, src);
+ if (used < 0)
+ return -1;
+ pos += used;
+ while (*pos == ' ')
+ pos++;
+
+ len = os_strlen(pos);
+ if (len & 1)
+ return -1;
+ len /= 2;
+
+ buf = os_malloc(len);
+ if (buf == NULL)
+ return -1;
+
+ if (hexstr2bin(pos, buf, len) < 0) {
+ os_free(buf);
+ return -1;
+ }
+
+ ieee802_1x_receive(hapd, src, buf, len);
+ os_free(buf);
+
+ return 0;
+}
+
+
+static u16 ipv4_hdr_checksum(const void *buf, size_t len)
+{
+ size_t i;
+ u32 sum = 0;
+ const u16 *pos = buf;
+
+ for (i = 0; i < len / 2; i++)
+ sum += *pos++;
+
+ while (sum >> 16)
+ sum = (sum & 0xffff) + (sum >> 16);
+
+ return sum ^ 0xffff;
+}
+
+
+#define HWSIM_PACKETLEN 1500
+#define HWSIM_IP_LEN (HWSIM_PACKETLEN - sizeof(struct ether_header))
+
+void hostapd_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
+ size_t len)
+{
+ struct hostapd_data *hapd = ctx;
+ const struct ether_header *eth;
+ const struct iphdr *ip;
+ const u8 *pos;
+ unsigned int i;
+
+ if (len != HWSIM_PACKETLEN)
+ return;
+
+ eth = (const struct ether_header *) buf;
+ ip = (const struct iphdr *) (eth + 1);
+ pos = (const u8 *) (ip + 1);
+
+ if (ip->ihl != 5 || ip->version != 4 ||
+ ntohs(ip->tot_len) != HWSIM_IP_LEN)
+ return;
+
+ for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++) {
+ if (*pos != (u8) i)
+ return;
+ pos++;
+ }
+
+ wpa_msg(hapd->msg_ctx, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR,
+ MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost));
+}
+
+
+static int hostapd_ctrl_iface_data_test_config(struct hostapd_data *hapd,
+ char *cmd)
+{
+ int enabled = atoi(cmd);
+ char *pos;
+ const char *ifname;
+
+ if (!enabled) {
+ if (hapd->l2_test) {
+ l2_packet_deinit(hapd->l2_test);
+ hapd->l2_test = NULL;
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
+ "test data: Disabled");
+ }
+ return 0;
+ }
+
+ if (hapd->l2_test)
+ return 0;
+
+ pos = os_strstr(cmd, " ifname=");
+ if (pos)
+ ifname = pos + 8;
+ else
+ ifname = hapd->conf->iface;
+
+ hapd->l2_test = l2_packet_init(ifname, hapd->own_addr,
+ ETHERTYPE_IP, hostapd_data_test_rx,
+ hapd, 1);
+ if (hapd->l2_test == NULL)
+ return -1;
+
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: Enabled");
+
+ return 0;
+}
+
+
+static int hostapd_ctrl_iface_data_test_tx(struct hostapd_data *hapd, char *cmd)
+{
+ u8 dst[ETH_ALEN], src[ETH_ALEN];
+ char *pos;
+ int used;
+ long int val;
+ u8 tos;
+ u8 buf[HWSIM_PACKETLEN];
+ struct ether_header *eth;
+ struct iphdr *ip;
+ u8 *dpos;
+ unsigned int i;
+
+ if (hapd->l2_test == NULL)
+ return -1;
+
+ /* format: <dst> <src> <tos> */
+
+ pos = cmd;
+ used = hwaddr_aton2(pos, dst);
+ if (used < 0)
+ return -1;
+ pos += used;
+ while (*pos == ' ')
+ pos++;
+ used = hwaddr_aton2(pos, src);
+ if (used < 0)
+ return -1;
+ pos += used;
+
+ val = strtol(pos, NULL, 0);
+ if (val < 0 || val > 0xff)
+ return -1;
+ tos = val;
+
+ eth = (struct ether_header *) buf;
+ os_memcpy(eth->ether_dhost, dst, ETH_ALEN);
+ os_memcpy(eth->ether_shost, src, ETH_ALEN);
+ eth->ether_type = htons(ETHERTYPE_IP);
+ ip = (struct iphdr *) (eth + 1);
+ os_memset(ip, 0, sizeof(*ip));
+ ip->ihl = 5;
+ ip->version = 4;
+ ip->ttl = 64;
+ ip->tos = tos;
+ ip->tot_len = htons(HWSIM_IP_LEN);
+ ip->protocol = 1;
+ ip->saddr = htonl(192 << 24 | 168 << 16 | 1 << 8 | 1);
+ ip->daddr = htonl(192 << 24 | 168 << 16 | 1 << 8 | 2);
+ ip->check = ipv4_hdr_checksum(ip, sizeof(*ip));
+ dpos = (u8 *) (ip + 1);
+ for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++)
+ *dpos++ = i;
+
+ if (l2_packet_send(hapd->l2_test, dst, ETHERTYPE_IP, buf,
+ HWSIM_PACKETLEN) < 0)
+ return -1;
+
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: TX dst=" MACSTR
+ " src=" MACSTR " tos=0x%x", MAC2STR(dst), MAC2STR(src), tos);
+
+ return 0;
+}
+
+
+static int hostapd_ctrl_iface_data_test_frame(struct hostapd_data *hapd,
+ char *cmd)
+{
+ u8 *buf;
+ struct ether_header *eth;
+ struct l2_packet_data *l2 = NULL;
+ size_t len;
+ u16 ethertype;
+ int res = -1;
+ const char *ifname = hapd->conf->iface;
+
+ if (os_strncmp(cmd, "ifname=", 7) == 0) {
+ cmd += 7;
+ ifname = cmd;
+ cmd = os_strchr(cmd, ' ');
+ if (cmd == NULL)
+ return -1;
+ *cmd++ = '\0';
+ }
+
+ len = os_strlen(cmd);
+ if (len & 1 || len < ETH_HLEN * 2)
+ return -1;
+ len /= 2;
+
+ buf = os_malloc(len);
+ if (buf == NULL)
+ return -1;
+
+ if (hexstr2bin(cmd, buf, len) < 0)
+ goto done;
+
+ eth = (struct ether_header *) buf;
+ ethertype = ntohs(eth->ether_type);
+
+ l2 = l2_packet_init(ifname, hapd->own_addr, ethertype,
+ hostapd_data_test_rx, hapd, 1);
+ if (l2 == NULL)
+ goto done;
+
+ res = l2_packet_send(l2, eth->ether_dhost, ethertype, buf, len);
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: TX frame res=%d", res);
+done:
+ if (l2)
+ l2_packet_deinit(l2);
+ os_free(buf);
+
+ return res < 0 ? -1 : 0;
+}
+
+
+static int hostapd_ctrl_test_alloc_fail(struct hostapd_data *hapd, char *cmd)
+{
+#ifdef WPA_TRACE_BFD
+ extern char wpa_trace_fail_func[256];
+ extern unsigned int wpa_trace_fail_after;
+ char *pos;
+
+ wpa_trace_fail_after = atoi(cmd);
+ pos = os_strchr(cmd, ':');
+ if (pos) {
+ pos++;
+ os_strlcpy(wpa_trace_fail_func, pos,
+ sizeof(wpa_trace_fail_func));
+ } else {
+ wpa_trace_fail_after = 0;
+ }
+
+ return 0;
+#else /* WPA_TRACE_BFD */
+ return -1;
+#endif /* WPA_TRACE_BFD */
+}
+
+
+static int hostapd_ctrl_get_alloc_fail(struct hostapd_data *hapd,
+ char *buf, size_t buflen)
+{
+#ifdef WPA_TRACE_BFD
+ extern char wpa_trace_fail_func[256];
+ extern unsigned int wpa_trace_fail_after;
+
+ return os_snprintf(buf, buflen, "%u:%s", wpa_trace_fail_after,
+ wpa_trace_fail_func);
+#else /* WPA_TRACE_BFD */
+ return -1;
+#endif /* WPA_TRACE_BFD */
+}
+
#endif /* CONFIG_TESTING_OPTIONS */
@@ -1366,7 +1862,8 @@
res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
(struct sockaddr *) &from, &fromlen);
if (res < 0) {
- perror("recvfrom(ctrl_iface)");
+ wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
+ strerror(errno));
return;
}
buf[res] = '\0';
@@ -1376,8 +1873,11 @@
reply = os_malloc(reply_size);
if (reply == NULL) {
- sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
- fromlen);
+ if (sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
+ fromlen) < 0) {
+ wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
+ strerror(errno));
+ }
return;
}
@@ -1525,6 +2025,9 @@
} else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) {
if (hostapd_ctrl_iface_ess_disassoc(hapd, buf + 13))
reply_len = -1;
+ } else if (os_strncmp(buf, "BSS_TM_REQ ", 11) == 0) {
+ if (hostapd_ctrl_iface_bss_tm_req(hapd, buf + 11))
+ reply_len = -1;
#endif /* CONFIG_WNM */
} else if (os_strcmp(buf, "GET_CONFIG") == 0) {
reply_len = hostapd_ctrl_iface_get_config(hapd, reply,
@@ -1551,6 +2054,24 @@
} else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) {
if (hostapd_ctrl_iface_mgmt_tx(hapd, buf + 8))
reply_len = -1;
+ } else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) {
+ if (hostapd_ctrl_iface_eapol_rx(hapd, buf + 9) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DATA_TEST_CONFIG ", 17) == 0) {
+ if (hostapd_ctrl_iface_data_test_config(hapd, buf + 17) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DATA_TEST_TX ", 13) == 0) {
+ if (hostapd_ctrl_iface_data_test_tx(hapd, buf + 13) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DATA_TEST_FRAME ", 16) == 0) {
+ if (hostapd_ctrl_iface_data_test_frame(hapd, buf + 16) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "TEST_ALLOC_FAIL ", 16) == 0) {
+ if (hostapd_ctrl_test_alloc_fail(hapd, buf + 16) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "GET_ALLOC_FAIL") == 0) {
+ reply_len = hostapd_ctrl_get_alloc_fail(hapd, reply,
+ reply_size);
#endif /* CONFIG_TESTING_OPTIONS */
} else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12))
@@ -1558,7 +2079,11 @@
} else if (os_strncmp(buf, "VENDOR ", 7) == 0) {
reply_len = hostapd_ctrl_iface_vendor(hapd, buf + 7, reply,
reply_size);
-
+ } else if (os_strcmp(buf, "ERP_FLUSH") == 0) {
+ ieee802_1x_erp_flush(hapd);
+#ifdef RADIUS_SERVER
+ radius_server_erp_flush(hapd->radius_srv);
+#endif /* RADIUS_SERVER */
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
@@ -1568,7 +2093,11 @@
os_memcpy(reply, "FAIL\n", 5);
reply_len = 5;
}
- sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
+ if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
+ fromlen) < 0) {
+ wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
+ strerror(errno));
+ }
os_free(reply);
}
@@ -1623,7 +2152,8 @@
wpa_printf(MSG_DEBUG, "Using existing control "
"interface directory.");
} else {
- perror("mkdir[ctrl_interface]");
+ wpa_printf(MSG_ERROR, "mkdir[ctrl_interface]: %s",
+ strerror(errno));
goto fail;
}
}
@@ -1631,7 +2161,8 @@
if (hapd->conf->ctrl_interface_gid_set &&
chown(hapd->conf->ctrl_interface, -1,
hapd->conf->ctrl_interface_gid) < 0) {
- perror("chown[ctrl_interface]");
+ wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
+ strerror(errno));
return -1;
}
@@ -1639,7 +2170,8 @@
hapd->iface->interfaces->ctrl_iface_group &&
chown(hapd->conf->ctrl_interface, -1,
hapd->iface->interfaces->ctrl_iface_group) < 0) {
- perror("chown[ctrl_interface]");
+ wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
+ strerror(errno));
return -1;
}
@@ -1664,7 +2196,7 @@
s = socket(PF_UNIX, SOCK_DGRAM, 0);
if (s < 0) {
- perror("socket(PF_UNIX)");
+ wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
goto fail;
}
@@ -1685,15 +2217,16 @@
" allow connections - assuming it was left"
"over from forced program termination");
if (unlink(fname) < 0) {
- perror("unlink[ctrl_iface]");
- wpa_printf(MSG_ERROR, "Could not unlink "
- "existing ctrl_iface socket '%s'",
- fname);
+ wpa_printf(MSG_ERROR,
+ "Could not unlink existing ctrl_iface socket '%s': %s",
+ fname, strerror(errno));
goto fail;
}
if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
0) {
- perror("hostapd-ctrl-iface: bind(PF_UNIX)");
+ wpa_printf(MSG_ERROR,
+ "hostapd-ctrl-iface: bind(PF_UNIX): %s",
+ strerror(errno));
goto fail;
}
wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
@@ -1711,26 +2244,32 @@
if (hapd->conf->ctrl_interface_gid_set &&
chown(fname, -1, hapd->conf->ctrl_interface_gid) < 0) {
- perror("chown[ctrl_interface/ifname]");
+ wpa_printf(MSG_ERROR, "chown[ctrl_interface/ifname]: %s",
+ strerror(errno));
goto fail;
}
if (!hapd->conf->ctrl_interface_gid_set &&
hapd->iface->interfaces->ctrl_iface_group &&
chown(fname, -1, hapd->iface->interfaces->ctrl_iface_group) < 0) {
- perror("chown[ctrl_interface/ifname]");
+ wpa_printf(MSG_ERROR, "chown[ctrl_interface/ifname]: %s",
+ strerror(errno));
goto fail;
}
if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
- perror("chmod[ctrl_interface/ifname]");
+ wpa_printf(MSG_ERROR, "chmod[ctrl_interface/ifname]: %s",
+ strerror(errno));
goto fail;
}
os_free(fname);
hapd->ctrl_sock = s;
- eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
- NULL);
+ if (eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
+ NULL) < 0) {
+ hostapd_ctrl_iface_deinit(hapd);
+ return -1;
+ }
hapd->msg_ctx = hapd;
wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
@@ -1777,11 +2316,17 @@
}
dst = hapd->ctrl_dst;
+ hapd->ctrl_dst = NULL;
while (dst) {
prev = dst;
dst = dst->next;
os_free(prev);
}
+
+#ifdef CONFIG_TESTING_OPTIONS
+ l2_packet_deinit(hapd->l2_test);
+ hapd->l2_test = NULL;
+#endif /* CONFIG_TESTING_OPTIONS */
}
@@ -1831,7 +2376,8 @@
res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
(struct sockaddr *) &from, &fromlen);
if (res < 0) {
- perror("recvfrom(ctrl_iface)");
+ wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
+ strerror(errno));
return;
}
buf[res] = '\0';
@@ -1871,7 +2417,11 @@
reply_len = 5;
}
- sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
+ if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
+ fromlen) < 0) {
+ wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
+ strerror(errno));
+ }
}
@@ -1912,13 +2462,15 @@
wpa_printf(MSG_DEBUG, "Using existing control "
"interface directory.");
} else {
- perror("mkdir[ctrl_interface]");
+ wpa_printf(MSG_ERROR, "mkdir[ctrl_interface]: %s",
+ strerror(errno));
goto fail;
}
} else if (interface->ctrl_iface_group &&
chown(interface->global_iface_path, -1,
interface->ctrl_iface_group) < 0) {
- perror("chown[ctrl_interface]");
+ wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
+ strerror(errno));
goto fail;
}
@@ -1928,7 +2480,7 @@
s = socket(PF_UNIX, SOCK_DGRAM, 0);
if (s < 0) {
- perror("socket(PF_UNIX)");
+ wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
goto fail;
}
@@ -1949,15 +2501,15 @@
" allow connections - assuming it was left"
"over from forced program termination");
if (unlink(fname) < 0) {
- perror("unlink[ctrl_iface]");
- wpa_printf(MSG_ERROR, "Could not unlink "
- "existing ctrl_iface socket '%s'",
- fname);
+ wpa_printf(MSG_ERROR,
+ "Could not unlink existing ctrl_iface socket '%s': %s",
+ fname, strerror(errno));
goto fail;
}
if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
0) {
- perror("bind(PF_UNIX)");
+ wpa_printf(MSG_ERROR, "bind(PF_UNIX): %s",
+ strerror(errno));
goto fail;
}
wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
@@ -1975,12 +2527,14 @@
if (interface->ctrl_iface_group &&
chown(fname, -1, interface->ctrl_iface_group) < 0) {
- perror("chown[ctrl_interface]");
+ wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
+ strerror(errno));
goto fail;
}
if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
- perror("chmod[ctrl_interface/ifname]");
+ wpa_printf(MSG_ERROR, "chmod[ctrl_interface/ifname]: %s",
+ strerror(errno));
goto fail;
}
os_free(fname);
diff --git a/hostapd/defconfig b/hostapd/defconfig
index 5b74b64..4cde2b5 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -15,10 +15,6 @@
# Driver interface for wired authenticator
#CONFIG_DRIVER_WIRED=y
-# Driver interface for madwifi driver
-#CONFIG_DRIVER_MADWIFI=y
-#CFLAGS += -I../../madwifi # change to the madwifi source directory
-
# Driver interface for drivers using the nl80211 kernel interface
CONFIG_DRIVER_NL80211=y
@@ -60,6 +56,9 @@
# Integrated EAP server
CONFIG_EAP=y
+# EAP Re-authentication Protocol (ERP) in integrated EAP server
+CONFIG_ERP=y
+
# EAP-MD5 for the integrated EAP server
CONFIG_EAP_MD5=y
@@ -142,7 +141,7 @@
#CONFIG_IEEE80211R=y
# Use the hostapd's IEEE 802.11 authentication (ACL), but without
-# the IEEE 802.11 Management capability (e.g., madwifi or FreeBSD/net80211)
+# the IEEE 802.11 Management capability (e.g., FreeBSD/net80211)
#CONFIG_DRIVER_RADIUS_ACL=y
# IEEE 802.11n (High Throughput) support
diff --git a/hostapd/hlr_auc_gw.c b/hostapd/hlr_auc_gw.c
index c041887..42d59db 100644
--- a/hostapd/hlr_auc_gw.c
+++ b/hostapd/hlr_auc_gw.c
@@ -711,7 +711,7 @@
rend = resp + resp_len;
rpos = resp;
ret = os_snprintf(rpos, rend - rpos, "GSM-AUTH-RESP %s", imsi);
- if (ret < 0 || ret >= rend - rpos)
+ if (os_snprintf_error(rend - rpos, ret))
return -1;
rpos += ret;
@@ -737,7 +737,7 @@
printf("No GSM triplets found for %s\n", imsi);
ret = os_snprintf(rpos, rend - rpos, " FAILURE");
- if (ret < 0 || ret >= rend - rpos)
+ if (os_snprintf_error(rend - rpos, ret))
return -1;
rpos += ret;
diff --git a/hostapd/hostapd.8 b/hostapd/hostapd.8
index b4456bb..d19d862 100644
--- a/hostapd/hostapd.8
+++ b/hostapd/hostapd.8
@@ -12,7 +12,7 @@
.B hostapd
is a user space daemon for access point and authentication servers.
It implements IEEE 802.11 access point management, IEEE 802.1X/WPA/WPA2/EAP Authenticators and RADIUS authentication server.
-The current version supports Linux (Host AP, madwifi, mac80211-based drivers) and FreeBSD (net80211).
+The current version supports Linux (Host AP, mac80211-based drivers) and FreeBSD (net80211).
.B hostapd
is designed to be a "daemon" program that runs in the background and acts as the backend component controlling authentication.
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index a7ab0f6..b370f21 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -2,10 +2,10 @@
# Empty lines and lines starting with # are ignored
# AP netdevice name (without 'ap' postfix, i.e., wlan0 uses wlan0ap for
-# management frames); ath0 for madwifi
+# management frames with the Host AP driver); wlan0 with many nl80211 drivers
interface=wlan0
-# In case of madwifi, atheros, and nl80211 driver interfaces, an additional
+# In case of atheros and nl80211 driver interfaces, an additional
# configuration parameter, bridge, may be used to notify hostapd if the
# interface is included in a bridge. This parameter is not used with Host AP
# driver. If the bridge parameter is not set, the drivers will automatically
@@ -18,12 +18,15 @@
# interface is also created.
#bridge=br0
-# Driver interface type (hostap/wired/madwifi/test/none/nl80211/bsd);
+# Driver interface type (hostap/wired/none/nl80211/bsd);
# default: hostap). nl80211 is used with all Linux mac80211 drivers.
# Use driver=none if building hostapd as a standalone RADIUS server that does
# not control any wireless/wired driver.
# driver=hostap
+# Driver interface parameters (mainly for development testing use)
+# driver_params=<params>
+
# hostapd event logger configuration
#
# Two output method: syslog and stdout (only usable if not forking to
@@ -155,10 +158,7 @@
#acs_num_scans=5
# Channel list restriction. This option allows hostapd to select one of the
-# provided channels when a channel should be automatically selected. This
-# is currently only used for DFS when the current channels becomes unavailable
-# due to radar interference, and is currently only useful when ieee80211h=1 is
-# set.
+# provided channels when a channel should be automatically selected.
# Default: not set (allow any enabled channel to be selected)
#chanlist=100 104 108 112 116
@@ -221,7 +221,7 @@
# Station MAC address -based authentication
# Please note that this kind of access control requires a driver that uses
# hostapd to take care of management frame processing and as such, this can be
-# used with driver=hostap or driver=nl80211, but not with driver=madwifi.
+# used with driver=hostap or driver=nl80211, but not with driver=atheros.
# 0 = accept unless in deny list
# 1 = deny unless in accept list
# 2 = use external RADIUS server (accept/deny lists are searched first)
@@ -435,6 +435,11 @@
# associated stations in the BSS. By default, this bridging is allowed.
#ap_isolate=1
+# BSS Load update period (in BUs)
+# This field is used to enable and configure adding a BSS Load element into
+# Beacon and Probe Response frames.
+#bss_load_update_period=50
+
# Fixed BSS Load value for testing purposes
# This field can be used to configure hostapd to add a fixed BSS Load element
# into Beacon and Probe Response frames for testing purposes. The format is
@@ -688,6 +693,17 @@
# is only used by one station.
#use_pae_group_addr=1
+# EAP Re-authentication Protocol (ERP) authenticator (RFC 6696)
+#
+# Whether to initiate EAP authentication with EAP-Initiate/Re-auth-Start before
+# EAP-Identity/Request
+#erp_send_reauth_start=1
+#
+# Domain name for EAP-Initiate/Re-auth-Start. Omitted from the message if not
+# set (no local ER server). This is also used by the integrated EAP server if
+# ERP is enabled (eap_server_erp=1).
+#erp_domain=example.com
+
##### Integrated EAP server ###################################################
# Optionally, hostapd can be configured to use an integrated EAP server
@@ -763,6 +779,15 @@
# "openssl dhparam -out /etc/hostapd.dh.pem 1024"
#dh_file=/etc/hostapd.dh.pem
+# OpenSSL cipher string
+#
+# This is an OpenSSL specific configuration option for configuring the default
+# ciphers. If not set, "DEFAULT:!EXP:!LOW" is used as the default.
+# See https://www.openssl.org/docs/apps/ciphers.html for OpenSSL documentation
+# on cipher suite configuration. This is applicable only if hostapd is built to
+# use OpenSSL.
+#openssl_ciphers=DEFAULT:!EXP:!LOW
+
# Fragment size for EAP methods
#fragment_size=1400
@@ -824,6 +849,10 @@
# EAP method is enabled, the peer will be allowed to connect without TNC.
#tnc=1
+# EAP Re-authentication Protocol (ERP) - RFC 6696
+#
+# Whether to enable ERP on the EAP server.
+#eap_server_erp=1
##### IEEE 802.11f - Inter-Access Point Protocol (IAPP) #######################
@@ -1439,6 +1468,11 @@
# 1 = enabled
#bss_transition=1
+# Proxy ARP
+# 0 = disabled (default)
+# 1 = enabled
+#proxy_arp=1
+
##### IEEE 802.11u-2011 #######################################################
# Enable Interworking service
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index 9e62bef..3f00cbb 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -1,6 +1,6 @@
/*
* hostapd - command line interface for hostapd daemon
- * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -18,7 +18,7 @@
static const char *hostapd_cli_version =
"hostapd_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> and contributors";
static const char *hostapd_cli_license =
@@ -393,7 +393,7 @@
else
res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s",
argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ if (os_snprintf_error(sizeof(cmd), res)) {
printf("Too long WPS_CHECK_PIN command.\n");
return -1;
}
@@ -456,7 +456,7 @@
res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_CONFIG_TOKEN %s",
argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ if (os_snprintf_error(sizeof(cmd), res)) {
printf("Too long WPS_NFC_CONFIG_TOKEN command.\n");
return -1;
}
@@ -477,7 +477,7 @@
}
res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ if (os_snprintf_error(sizeof(cmd), res)) {
printf("Too long WPS_NFC_TOKEN command.\n");
return -1;
}
@@ -499,7 +499,7 @@
res = os_snprintf(cmd, sizeof(cmd), "NFC_GET_HANDOVER_SEL %s %s",
argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ if (os_snprintf_error(sizeof(cmd), res)) {
printf("Too long NFC_GET_HANDOVER_SEL command.\n");
return -1;
}
@@ -596,7 +596,7 @@
res = os_snprintf(buf, sizeof(buf), "DISASSOC_IMMINENT %s %s",
argv[0], argv[1]);
- if (res < 0 || res >= (int) sizeof(buf))
+ if (os_snprintf_error(sizeof(buf), res))
return -1;
return wpa_ctrl_command(ctrl, buf);
}
@@ -616,12 +616,39 @@
res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s %s",
argv[0], argv[1], argv[2]);
- if (res < 0 || res >= (int) sizeof(buf))
+ if (os_snprintf_error(sizeof(buf), res))
return -1;
return wpa_ctrl_command(ctrl, buf);
}
+static int hostapd_cli_cmd_bss_tm_req(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char buf[2000], *tmp;
+ int res, i, total;
+
+ if (argc < 1) {
+ printf("Invalid 'bss_tm_req' command - at least one argument (STA addr) is needed\n");
+ return -1;
+ }
+
+ res = os_snprintf(buf, sizeof(buf), "BSS_TM_REQ %s", argv[0]);
+ if (os_snprintf_error(sizeof(buf), res))
+ return -1;
+
+ total = res;
+ for (i = 1; i < argc; i++) {
+ tmp = &buf[total];
+ res = os_snprintf(tmp, sizeof(buf) - total, " %s", argv[i]);
+ if (os_snprintf_error(sizeof(buf) - total, res))
+ return -1;
+ total += res;
+ }
+ return wpa_ctrl_command(ctrl, buf);
+}
+
+
static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -709,7 +736,7 @@
}
res = os_snprintf(buf, sizeof(buf), "SET_QOS_MAP_SET %s", argv[0]);
- if (res < 0 || res >= (int) sizeof(buf))
+ if (os_snprintf_error(sizeof(buf), res))
return -1;
return wpa_ctrl_command(ctrl, buf);
}
@@ -728,7 +755,7 @@
}
res = os_snprintf(buf, sizeof(buf), "SEND_QOS_MAP_CONF %s", argv[0]);
- if (res < 0 || res >= (int) sizeof(buf))
+ if (os_snprintf_error(sizeof(buf), res))
return -1;
return wpa_ctrl_command(ctrl, buf);
}
@@ -748,7 +775,7 @@
res = os_snprintf(buf, sizeof(buf), "HS20_WNM_NOTIF %s %s",
argv[0], argv[1]);
- if (res < 0 || res >= (int) sizeof(buf))
+ if (os_snprintf_error(sizeof(buf), res))
return -1;
return wpa_ctrl_command(ctrl, buf);
}
@@ -773,7 +800,7 @@
res = os_snprintf(buf, sizeof(buf),
"HS20_DEAUTH_REQ %s %s %s",
argv[0], argv[1], argv[2]);
- if (res < 0 || res >= (int) sizeof(buf))
+ if (os_snprintf_error(sizeof(buf), res))
return -1;
return wpa_ctrl_command(ctrl, buf);
}
@@ -866,7 +893,7 @@
}
res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ if (os_snprintf_error(sizeof(cmd), res)) {
printf("Too long SET command.\n");
return -1;
}
@@ -886,7 +913,7 @@
}
res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ if (os_snprintf_error(sizeof(cmd), res)) {
printf("Too long GET command.\n");
return -1;
}
@@ -914,7 +941,7 @@
res = os_snprintf(cmd, sizeof(cmd), "CHAN_SWITCH %s %s",
argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ if (os_snprintf_error(sizeof(cmd), res)) {
printf("Too long CHAN_SWITCH command.\n");
return -1;
}
@@ -923,7 +950,7 @@
for (i = 2; i < argc; i++) {
tmp = cmd + total;
res = os_snprintf(tmp, sizeof(cmd) - total, " %s", argv[i]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - total - 1) {
+ if (os_snprintf_error(sizeof(cmd) - total, res)) {
printf("Too long CHAN_SWITCH command.\n");
return -1;
}
@@ -933,6 +960,27 @@
}
+static int hostapd_cli_cmd_enable(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "ENABLE");
+}
+
+
+static int hostapd_cli_cmd_reload(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "RELOAD");
+}
+
+
+static int hostapd_cli_cmd_disable(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "DISABLE");
+}
+
+
static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char cmd[256];
@@ -946,7 +994,7 @@
res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s", argv[0], argv[1],
argc == 3 ? argv[2] : "");
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ if (os_snprintf_error(sizeof(cmd), res)) {
printf("Too long VENDOR command.\n");
return -1;
}
@@ -954,6 +1002,13 @@
}
+static int hostapd_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "ERP_FLUSH");
+}
+
+
struct hostapd_cli_cmd {
const char *cmd;
int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
@@ -989,6 +1044,7 @@
#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 },
@@ -1003,6 +1059,10 @@
{ "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 },
{ NULL, NULL }
};
diff --git a/hostapd/main.c b/hostapd/main.c
index c3af704..dd389a8 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -1,6 +1,6 @@
/*
* hostapd / main()
- * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -28,8 +28,6 @@
#include "eap_register.h"
#include "ctrl_iface.h"
-struct wowlan_triggers *wpa_get_wowlan_triggers(const char *wowlan_triggers,
- struct wpa_driver_capa *capa);
struct hapd_global {
void **drv_priv;
@@ -186,9 +184,7 @@
}
params.bssid = b;
params.ifname = hapd->conf->iface;
- params.ssid = hapd->conf->ssid.ssid;
- params.ssid_len = hapd->conf->ssid.ssid_len;
- params.test_socket = hapd->conf->test_socket;
+ params.driver_params = hapd->iconf->driver_params;
params.use_pae_group_addr = hapd->conf->use_pae_group_addr;
params.num_bridge = hapd->iface->num_bss;
@@ -217,6 +213,7 @@
struct wowlan_triggers *triggs;
iface->drv_flags = capa.flags;
+ iface->smps_modes = capa.smps_modes;
iface->probe_resp_offloads = capa.probe_resp_offloads;
iface->extended_capa = capa.extended_capa;
iface->extended_capa_mask = capa.extended_capa_mask;
@@ -411,7 +408,7 @@
#endif /* EAP_SERVER_TNC */
if (daemonize && os_daemonize(pid_file)) {
- perror("daemon");
+ wpa_printf(MSG_ERROR, "daemon: %s", strerror(errno));
return -1;
}
@@ -427,7 +424,7 @@
"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-2014, Jouni Malinen <j@w1.fi> "
+ "Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> "
"and contributors\n");
}
@@ -641,6 +638,8 @@
if (log_file)
wpa_debug_open_file(log_file);
+ else
+ wpa_debug_setup_stdout();
#ifdef CONFIG_DEBUG_LINUX_TRACING
if (enable_trace_dbg) {
int tret = wpa_debug_open_linux_tracing();
diff --git a/hs20/client/osu_client.c b/hs20/client/osu_client.c
index a439bde..e452aa7 100644
--- a/hs20/client/osu_client.c
+++ b/hs20/client/osu_client.c
@@ -397,9 +397,9 @@
}
node = get_child_node(ctx->xml, pps,
- "PolicyUpdate/TrustRoot");
+ "Policy/PolicyUpdate/TrustRoot");
if (node == NULL) {
- wpa_printf(MSG_INFO, "No PolicyUpdate/TrustRoot/CertURL found from PPS");
+ wpa_printf(MSG_INFO, "No Policy/PolicyUpdate/TrustRoot/CertURL found from PPS");
xml_node_free(ctx->xml, pps);
return -1;
}
@@ -2343,8 +2343,8 @@
}
-static void cmd_sub_rem(struct hs20_osu_client *ctx, const char *address,
- const char *pps_fname, const char *ca_fname)
+static int cmd_sub_rem(struct hs20_osu_client *ctx, const char *address,
+ const char *pps_fname, const char *ca_fname)
{
xml_node_t *pps, *node;
char pps_fname_buf[300];
@@ -2371,12 +2371,12 @@
} else if (get_wpa_status(ctx->ifname, "provisioning_sp", buf,
sizeof(buf)) < 0) {
wpa_printf(MSG_INFO, "Could not get provisioning Home SP FQDN from wpa_supplicant");
- return;
+ return -1;
}
os_free(ctx->fqdn);
ctx->fqdn = os_strdup(buf);
if (ctx->fqdn == NULL)
- return;
+ return -1;
wpa_printf(MSG_INFO, "Home SP FQDN for current credential: %s",
buf);
os_snprintf(pps_fname_buf, sizeof(pps_fname_buf),
@@ -2391,14 +2391,14 @@
if (!os_file_exists(pps_fname)) {
wpa_printf(MSG_INFO, "PPS file '%s' does not exist or is not accessible",
pps_fname);
- return;
+ return -1;
}
wpa_printf(MSG_INFO, "Using PPS file: %s", pps_fname);
if (ca_fname && !os_file_exists(ca_fname)) {
wpa_printf(MSG_INFO, "CA file '%s' does not exist or is not accessible",
ca_fname);
- return;
+ return -1;
}
wpa_printf(MSG_INFO, "Using server trust root: %s", ca_fname);
ctx->ca_fname = ca_fname;
@@ -2406,7 +2406,7 @@
pps = node_from_file(ctx->xml, pps_fname);
if (pps == NULL) {
wpa_printf(MSG_INFO, "Could not read PPS MO");
- return;
+ return -1;
}
if (!ctx->fqdn) {
@@ -2414,18 +2414,18 @@
node = get_child_node(ctx->xml, pps, "HomeSP/FQDN");
if (node == NULL) {
wpa_printf(MSG_INFO, "No HomeSP/FQDN found from PPS");
- return;
+ return -1;
}
tmp = xml_node_get_text(ctx->xml, node);
if (tmp == NULL) {
wpa_printf(MSG_INFO, "No HomeSP/FQDN text found from PPS");
- return;
+ return -1;
}
ctx->fqdn = os_strdup(tmp);
xml_node_get_text_free(ctx->xml, tmp);
if (!ctx->fqdn) {
wpa_printf(MSG_INFO, "No FQDN known");
- return;
+ return -1;
}
}
@@ -2474,7 +2474,7 @@
}
if (!address) {
wpa_printf(MSG_INFO, "Server URL not known");
- return;
+ return -1;
}
write_summary(ctx, "Wait for IP address for subscriptiom remediation");
@@ -2497,6 +2497,7 @@
xml_node_get_text_free(ctx->xml, cred_username);
str_clear_free(cred_password);
xml_node_free(ctx->xml, pps);
+ return 0;
}
@@ -3066,10 +3067,11 @@
if (argc - optind < 2)
wpa_printf(MSG_ERROR, "Server URL missing from command line");
else
- 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();
diff --git a/src/ap/accounting.c b/src/ap/accounting.c
index 6290d3f..7c55146 100644
--- a/src/ap/accounting.c
+++ b/src/ap/accounting.c
@@ -10,6 +10,8 @@
#include "utils/common.h"
#include "utils/eloop.h"
+#include "eapol_auth/eapol_auth_sm.h"
+#include "eapol_auth/eapol_auth_sm_i.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "hostapd.h"
@@ -50,12 +52,19 @@
if (sta) {
radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta));
- os_snprintf(buf, sizeof(buf), "%08X-%08X",
- sta->acct_session_id_hi, sta->acct_session_id_lo);
- if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
- (u8 *) buf, os_strlen(buf))) {
- wpa_printf(MSG_INFO, "Could not add Acct-Session-Id");
- goto fail;
+ 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));
diff --git a/src/ap/acs.c b/src/ap/acs.c
index b94b8a4..e4c834c 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -455,6 +455,22 @@
}
+static int is_in_chanlist(struct hostapd_iface *iface,
+ struct hostapd_channel_data *chan)
+{
+ int *entry;
+
+ if (!iface->conf->chanlist)
+ return 1;
+
+ for (entry = iface->conf->chanlist; *entry != -1; entry++) {
+ if (*entry == chan->chan)
+ return 1;
+ }
+ return 0;
+}
+
+
static void acs_survey_all_chans_intereference_factor(
struct hostapd_iface *iface)
{
@@ -467,6 +483,9 @@
if (!acs_usable_chan(chan))
continue;
+ if (!is_in_chanlist(iface, chan))
+ continue;
+
wpa_printf(MSG_DEBUG, "ACS: Survey analysis for channel %d (%d MHz)",
chan->chan, chan->freq);
@@ -543,6 +562,8 @@
if (chan->flag & HOSTAPD_CHAN_DISABLED)
continue;
+ if (!is_in_chanlist(iface, chan))
+ continue;
/* HT40 on 5 GHz has a limited set of primary channels as per
* 11n Annex J */
@@ -816,6 +837,14 @@
wpa_printf(MSG_INFO, "ACS: Automatic channel selection started, this may take a bit");
+ if (iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) {
+ wpa_printf(MSG_INFO, "ACS: Offloading to driver");
+ err = hostapd_drv_do_acs(iface->bss[0]);
+ if (err)
+ return HOSTAPD_CHAN_INVALID;
+ return HOSTAPD_CHAN_ACS;
+ }
+
acs_cleanup(iface);
err = acs_request_scan(iface);
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index c7da69e..1c0ed7a 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -425,6 +425,7 @@
os_free(conf->eap_user_sqlite);
os_free(conf->eap_req_id_text);
+ os_free(conf->erp_domain);
os_free(conf->accept_mac);
os_free(conf->deny_mac);
os_free(conf->nas_identifier);
@@ -444,12 +445,12 @@
os_free(conf->private_key_passwd);
os_free(conf->ocsp_stapling_response);
os_free(conf->dh_file);
+ os_free(conf->openssl_ciphers);
os_free(conf->pac_opaque_encr_key);
os_free(conf->eap_fast_a_id);
os_free(conf->eap_fast_a_id_info);
os_free(conf->eap_sim_db);
os_free(conf->radius_server_clients);
- os_free(conf->test_socket);
os_free(conf->radius);
os_free(conf->radius_das_shared_secret);
hostapd_config_free_vlan(conf);
@@ -495,6 +496,12 @@
os_free(conf->model_description);
os_free(conf->model_url);
os_free(conf->upc);
+ {
+ unsigned int i;
+
+ for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++)
+ wpabuf_free(conf->wps_vendor_ext[i]);
+ }
wpabuf_free(conf->wps_nfc_dh_pubkey);
wpabuf_free(conf->wps_nfc_dh_privkey);
wpabuf_free(conf->wps_nfc_dev_pw);
@@ -566,6 +573,7 @@
os_free(conf->supported_rates);
os_free(conf->basic_rates);
os_free(conf->chanlist);
+ os_free(conf->driver_params);
os_free(conf);
}
@@ -888,12 +896,20 @@
int cipher = WPA_CIPHER_NONE;
bss->ssid.security_policy = SECURITY_IEEE_802_1X;
bss->ssid.wep.default_len = bss->default_wep_key_len;
- if (bss->default_wep_key_len)
+ if (full_config && bss->default_wep_key_len) {
cipher = bss->default_wep_key_len >= 13 ?
WPA_CIPHER_WEP104 : WPA_CIPHER_WEP40;
+ } else if (full_config && bss->ssid.wep.keys_set) {
+ if (bss->ssid.wep.len[0] >= 13)
+ cipher = WPA_CIPHER_WEP104;
+ else
+ cipher = WPA_CIPHER_WEP40;
+ }
bss->wpa_group = cipher;
bss->wpa_pairwise = cipher;
bss->rsn_pairwise = cipher;
+ if (full_config)
+ bss->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_NO_WPA;
} else if (bss->ssid.wep.keys_set) {
int cipher = WPA_CIPHER_WEP40;
if (bss->ssid.wep.len[0] >= 13)
@@ -902,6 +918,8 @@
bss->wpa_group = cipher;
bss->wpa_pairwise = cipher;
bss->rsn_pairwise = cipher;
+ if (full_config)
+ bss->wpa_key_mgmt = WPA_KEY_MGMT_NONE;
} else if (bss->osen) {
bss->ssid.security_policy = SECURITY_OSEN;
bss->wpa_group = WPA_CIPHER_CCMP;
@@ -912,5 +930,7 @@
bss->wpa_group = WPA_CIPHER_NONE;
bss->wpa_pairwise = WPA_CIPHER_NONE;
bss->rsn_pairwise = WPA_CIPHER_NONE;
+ if (full_config)
+ bss->wpa_key_mgmt = WPA_KEY_MGMT_NONE;
}
}
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 2858c6e..e5215c5 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -15,6 +15,34 @@
#include "common/ieee802_11_common.h"
#include "wps/wps.h"
+/**
+ * mesh_conf - local MBSS state and settings
+ */
+struct mesh_conf {
+ u8 meshid[32];
+ u8 meshid_len;
+ /* Active Path Selection Protocol Identifier */
+ u8 mesh_pp_id;
+ /* Active Path Selection Metric Identifier */
+ u8 mesh_pm_id;
+ /* Congestion Control Mode Identifier */
+ u8 mesh_cc_id;
+ /* Synchronization Protocol Identifier */
+ u8 mesh_sp_id;
+ /* Authentication Protocol Identifier */
+ u8 mesh_auth_id;
+ u8 *ies;
+ int ie_len;
+#define MESH_CONF_SEC_NONE BIT(0)
+#define MESH_CONF_SEC_AUTH BIT(1)
+#define MESH_CONF_SEC_AMPE BIT(2)
+ unsigned int security;
+ int dot11MeshMaxRetries;
+ int dot11MeshRetryTimeout; /* msec */
+ int dot11MeshConfirmTimeout; /* msec */
+ int dot11MeshHoldingTimeout; /* msec */
+};
+
#define MAX_STA_COUNT 2007
#define MAX_VLAN_ID 4094
@@ -196,6 +224,7 @@
int max_num_sta; /* maximum number of STAs in station table */
int dtim_period;
+ int bss_load_update_period;
int ieee802_1x; /* use IEEE 802.1X */
int eapol_version;
@@ -204,6 +233,7 @@
struct hostapd_eap_user *eap_user;
char *eap_user_sqlite;
char *eap_sim_db;
+ int eap_server_erp; /* Whether ERP is enabled on internal EAP server */
struct hostapd_ip_addr own_ip_addr;
char *nas_identifier;
struct hostapd_radius_servers *radius;
@@ -230,6 +260,8 @@
int wep_rekeying_period;
int broadcast_key_idx_min, broadcast_key_idx_max;
int eap_reauth_period;
+ int erp_send_reauth_start;
+ char *erp_domain;
int ieee802_11f; /* use IEEE 802.11f (IAPP) */
char iapp_iface[IFNAMSIZ + 1]; /* interface used with IAPP broadcast
@@ -302,6 +334,7 @@
int check_crl;
char *ocsp_stapling_response;
char *dh_file;
+ char *openssl_ciphers;
u8 *pac_opaque_encr_key;
u8 *eap_fast_a_id;
size_t eap_fast_a_id_len;
@@ -319,8 +352,6 @@
int radius_server_acct_port;
int radius_server_ipv6;
- char *test_socket; /* UNIX domain socket path for driver_test */
-
int use_pae_group_addr; /* Whether to send EAPOL frames to PAE group
* address instead of individual address
* (for driver_wired.c).
@@ -458,6 +489,7 @@
unsigned int qos_map_set_len;
int osen;
+ int proxy_arp;
#ifdef CONFIG_HS20
int hs20;
int disable_dgaf;
@@ -514,6 +546,13 @@
u8 bss_load_test[5];
u8 bss_load_test_set;
#endif /* CONFIG_TESTING_OPTIONS */
+
+#define MESH_ENABLED BIT(0)
+ int mesh;
+
+ int radio_measurements;
+
+ int vendor_vht;
};
@@ -540,6 +579,7 @@
int *basic_rates;
const struct wpa_driver_ops *driver;
+ char *driver_params;
int ap_table_max_size;
int ap_table_expiration_time;
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index cc4ac10..8514cbe 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -477,7 +477,8 @@
}
-int hostapd_set_freq_params(struct hostapd_freq_params *data, int mode,
+int hostapd_set_freq_params(struct hostapd_freq_params *data,
+ enum hostapd_hw_mode mode,
int freq, int channel, int ht_enabled,
int vht_enabled, int sec_channel_offset,
int vht_oper_chwidth, int center_segment0,
@@ -562,8 +563,8 @@
}
-int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq,
- int channel, int ht_enabled, int vht_enabled,
+int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
+ int freq, int channel, int ht_enabled, int vht_enabled,
int sec_channel_offset, int vht_oper_chwidth,
int center_segment0, int center_segment1)
{
@@ -573,7 +574,8 @@
vht_enabled, sec_channel_offset,
vht_oper_chwidth,
center_segment0, center_segment1,
- hapd->iface->current_mode->vht_capab))
+ hapd->iface->current_mode ?
+ hapd->iface->current_mode->vht_capab : 0))
return -1;
if (hapd->driver == NULL)
@@ -747,7 +749,8 @@
}
-int hostapd_start_dfs_cac(struct hostapd_iface *iface, int mode, int freq,
+int hostapd_start_dfs_cac(struct hostapd_iface *iface,
+ enum hostapd_hw_mode mode, int freq,
int channel, int ht_enabled, int vht_enabled,
int sec_channel_offset, int vht_oper_chwidth,
int center_segment0, int center_segment1)
@@ -792,3 +795,18 @@
return hapd->driver->set_qos_map(hapd->drv_priv, qos_map_set,
qos_map_set_len);
}
+
+
+int hostapd_drv_do_acs(struct hostapd_data *hapd)
+{
+ struct drv_acs_params params;
+
+ if (hapd->driver == NULL || hapd->driver->do_acs == NULL)
+ return 0;
+ os_memset(¶ms, 0, sizeof(params));
+ params.hw_mode = hapd->iface->conf->hw_mode;
+ params.ht_enabled = !!(hapd->iface->conf->ieee80211n);
+ params.ht40_enabled = !!(hapd->iface->conf->ht_capab &
+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET);
+ return hapd->driver->do_acs(hapd->drv_priv, ¶ms);
+}
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 7cc9d7d..c133be7 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -57,8 +57,8 @@
int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
const u8 *addr, int idx, u8 *seq);
int hostapd_flush(struct hostapd_data *hapd);
-int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq,
- int channel, int ht_enabled, int vht_enabled,
+int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
+ int freq, int channel, int ht_enabled, int vht_enabled,
int sec_channel_offset, int vht_oper_chwidth,
int center_segment0, int center_segment1);
int hostapd_set_rts(struct hostapd_data *hapd, int rts);
@@ -102,15 +102,18 @@
int reassoc, u16 status, const u8 *ie, size_t len);
int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr,
u8 *tspec_ie, size_t tspec_ielen);
-int hostapd_start_dfs_cac(struct hostapd_iface *iface, int mode, int freq,
+int hostapd_start_dfs_cac(struct hostapd_iface *iface,
+ enum hostapd_hw_mode mode, int freq,
int channel, int ht_enabled, int vht_enabled,
int sec_channel_offset, int vht_oper_chwidth,
int center_segment0, int center_segment1);
-int hostapd_set_freq_params(struct hostapd_freq_params *data, int mode,
+int hostapd_set_freq_params(struct hostapd_freq_params *data,
+ enum hostapd_hw_mode mode,
int freq, int channel, int ht_enabled,
int vht_enabled, int sec_channel_offset,
int vht_oper_chwidth, int center_segment0,
int center_segment1, u32 vht_caps);
+int hostapd_drv_do_acs(struct hostapd_data *hapd);
#include "drivers/driver.h"
@@ -280,6 +283,47 @@
return hapd->driver->status(hapd->drv_priv, buf, buflen);
}
+static inline int hostapd_drv_br_add_ip_neigh(struct hostapd_data *hapd,
+ int version, const u8 *ipaddr,
+ int prefixlen, const u8 *addr)
+{
+ if (hapd->driver == NULL || hapd->drv_priv == NULL ||
+ hapd->driver->br_add_ip_neigh == NULL)
+ return -1;
+ return hapd->driver->br_add_ip_neigh(hapd->drv_priv, version, ipaddr,
+ prefixlen, addr);
+}
+
+static inline int hostapd_drv_br_delete_ip_neigh(struct hostapd_data *hapd,
+ u8 version, const u8 *ipaddr)
+{
+ if (hapd->driver == NULL || hapd->drv_priv == NULL ||
+ hapd->driver->br_delete_ip_neigh == NULL)
+ return -1;
+ return hapd->driver->br_delete_ip_neigh(hapd->drv_priv, version,
+ ipaddr);
+}
+
+static inline int hostapd_drv_br_port_set_attr(struct hostapd_data *hapd,
+ enum drv_br_port_attr attr,
+ unsigned int val)
+{
+ if (hapd->driver == NULL || hapd->drv_priv == NULL ||
+ hapd->driver->br_port_set_attr == NULL)
+ return -1;
+ return hapd->driver->br_port_set_attr(hapd->drv_priv, attr, val);
+}
+
+static inline int hostapd_drv_br_set_net_param(struct hostapd_data *hapd,
+ enum drv_br_net_param param,
+ unsigned int val)
+{
+ if (hapd->driver == NULL || hapd->drv_priv == NULL ||
+ hapd->driver->br_set_net_param == NULL)
+ return -1;
+ return hapd->driver->br_set_net_param(hapd->drv_priv, param, val);
+}
+
static inline int hostapd_drv_vendor_cmd(struct hostapd_data *hapd,
int vendor_id, int subcmd,
const u8 *data, size_t data_len,
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index 86f1cbe..bd1778e 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -124,6 +124,8 @@
srv.subscr_remediation_url = conf->subscr_remediation_url;
srv.subscr_remediation_method = conf->subscr_remediation_method;
#endif /* CONFIG_HS20 */
+ srv.erp = conf->eap_server_erp;
+ srv.erp_domain = conf->erp_domain;
hapd->radius_srv = radius_server_init(&srv);
if (hapd->radius_srv == NULL) {
@@ -158,6 +160,7 @@
params.private_key = hapd->conf->private_key;
params.private_key_passwd = hapd->conf->private_key_passwd;
params.dh_file = hapd->conf->dh_file;
+ params.openssl_ciphers = hapd->conf->openssl_ciphers;
params.ocsp_stapling_response =
hapd->conf->ocsp_stapling_response;
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 4cae0d9..b0a74e0 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -32,18 +32,47 @@
#ifdef NEED_AP_MLME
+static u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
+ size_t len)
+{
+ if (!hapd->conf->radio_measurements || len < 2 + 4)
+ 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;
+}
+
+
static u8 * hostapd_eid_bss_load(struct hostapd_data *hapd, u8 *eid, size_t len)
{
+ if (len < 2 + 5)
+ return eid;
+
#ifdef CONFIG_TESTING_OPTIONS
if (hapd->conf->bss_load_test_set) {
- if (2 + 5 > len)
- return eid;
*eid++ = WLAN_EID_BSS_LOAD;
*eid++ = 5;
os_memcpy(eid, hapd->conf->bss_load_test, 5);
eid += 5;
+ return eid;
}
#endif /* CONFIG_TESTING_OPTIONS */
+ if (hapd->conf->bss_load_update_period) {
+ *eid++ = WLAN_EID_BSS_LOAD;
+ *eid++ = 5;
+ WPA_PUT_LE16(eid, hapd->num_sta);
+ eid += 2;
+ *eid++ = hapd->iface->channel_utilization;
+ WPA_PUT_LE16(eid, 0); /* no available admission capabity */
+ eid += 2;
+ }
return eid;
}
@@ -350,6 +379,10 @@
#endif /* CONFIG_P2P */
if (hapd->conf->vendor_elements)
buflen += wpabuf_len(hapd->conf->vendor_elements);
+ if (hapd->conf->vendor_vht) {
+ buflen += 5 + 2 + sizeof(struct ieee80211_vht_capabilities) +
+ 2 + sizeof(struct ieee80211_vht_operation);
+ }
resp = os_zalloc(buflen);
if (resp == NULL)
return NULL;
@@ -398,6 +431,8 @@
pos = hostapd_eid_bss_load(hapd, pos, epos - pos);
+ pos = hostapd_eid_rm_enabled_capab(hapd, pos, epos - pos);
+
#ifdef CONFIG_IEEE80211N
pos = hostapd_eid_ht_capabilities(hapd, pos);
pos = hostapd_eid_ht_operation(hapd, pos);
@@ -415,8 +450,12 @@
pos = hostapd_add_csa_elems(hapd, pos, (u8 *)resp,
&hapd->cs_c_off_proberesp);
#ifdef CONFIG_IEEE80211AC
- pos = hostapd_eid_vht_capabilities(hapd, pos);
- pos = hostapd_eid_vht_operation(hapd, pos);
+ if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
+ pos = hostapd_eid_vht_capabilities(hapd, pos);
+ pos = hostapd_eid_vht_operation(hapd, pos);
+ }
+ if (hapd->conf->vendor_vht)
+ pos = hostapd_eid_vendor_vht(hapd, pos);
#endif /* CONFIG_IEEE80211AC */
/* Wi-Fi Alliance WMM */
@@ -745,6 +784,14 @@
#endif /* CONFIG_P2P */
if (hapd->conf->vendor_elements)
tail_len += wpabuf_len(hapd->conf->vendor_elements);
+
+#ifdef CONFIG_IEEE80211AC
+ if (hapd->conf->vendor_vht) {
+ tail_len += 5 + 2 + sizeof(struct ieee80211_vht_capabilities) +
+ 2 + sizeof(struct ieee80211_vht_operation);
+ }
+#endif /* CONFIG_IEEE80211AC */
+
tailpos = tail = os_malloc(tail_len);
if (head == NULL || tail == NULL) {
wpa_printf(MSG_ERROR, "Failed to set beacon data");
@@ -808,6 +855,10 @@
tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE -
tailpos);
+ tailpos = hostapd_eid_rm_enabled_capab(hapd, tailpos,
+ tail + BEACON_TAIL_BUF_SIZE -
+ tailpos);
+
tailpos = hostapd_eid_bss_load(hapd, tailpos,
tail + BEACON_TAIL_BUF_SIZE - tailpos);
@@ -830,8 +881,12 @@
tailpos = hostapd_add_csa_elems(hapd, tailpos, tail,
&hapd->cs_c_off_beacon);
#ifdef CONFIG_IEEE80211AC
- tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
- tailpos = hostapd_eid_vht_operation(hapd, tailpos);
+ if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
+ tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
+ tailpos = hostapd_eid_vht_operation(hapd, tailpos);
+ }
+ if (hapd->conf->vendor_vht)
+ tailpos = hostapd_eid_vendor_vht(hapd, tailpos);
#endif /* CONFIG_IEEE80211AC */
/* Wi-Fi Alliance WMM */
@@ -908,6 +963,7 @@
break;
}
params->isolate = hapd->conf->isolate;
+ params->smps_mode = hapd->iconf->ht_capab & HT_CAP_INFO_SMPS_MASK;
#ifdef NEED_AP_MLME
params->cts_protect = !!(ieee802_11_erp_info(hapd) &
ERP_INFO_USE_PROTECTION);
diff --git a/src/ap/bss_load.c b/src/ap/bss_load.c
new file mode 100644
index 0000000..fb63942
--- /dev/null
+++ b/src/ap/bss_load.c
@@ -0,0 +1,65 @@
+/*
+ * BSS Load Element / Channel Utilization
+ * Copyright (c) 2014, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "hostapd.h"
+#include "bss_load.h"
+#include "ap_drv_ops.h"
+#include "beacon.h"
+
+
+static void update_channel_utilization(void *eloop_data, void *user_data)
+{
+ struct hostapd_data *hapd = eloop_data;
+ unsigned int sec, usec;
+ int err;
+
+ if (!(hapd->beacon_set_done && hapd->started))
+ return;
+
+ err = hostapd_drv_get_survey(hapd, hapd->iface->freq);
+ if (err) {
+ wpa_printf(MSG_ERROR, "BSS Load: Failed to get survey data");
+ return;
+ }
+
+ ieee802_11_set_beacon(hapd);
+
+ sec = ((hapd->bss_load_update_timeout / 1000) * 1024) / 1000;
+ usec = (hapd->bss_load_update_timeout % 1000) * 1024;
+ eloop_register_timeout(sec, usec, update_channel_utilization, hapd,
+ NULL);
+}
+
+
+int bss_load_update_init(struct hostapd_data *hapd)
+{
+ struct hostapd_bss_config *conf = hapd->conf;
+ struct hostapd_config *iconf = hapd->iconf;
+ unsigned int sec, usec;
+
+ if (!conf->bss_load_update_period || !iconf->beacon_int)
+ return -1;
+
+ hapd->bss_load_update_timeout = conf->bss_load_update_period *
+ iconf->beacon_int;
+ sec = ((hapd->bss_load_update_timeout / 1000) * 1024) / 1000;
+ usec = (hapd->bss_load_update_timeout % 1000) * 1024;
+ eloop_register_timeout(sec, usec, update_channel_utilization, hapd,
+ NULL);
+ return 0;
+}
+
+
+void bss_load_update_deinit(struct hostapd_data *hapd)
+{
+ eloop_cancel_timeout(update_channel_utilization, hapd, NULL);
+}
diff --git a/src/ap/bss_load.h b/src/ap/bss_load.h
new file mode 100644
index 0000000..ac3c793
--- /dev/null
+++ b/src/ap/bss_load.h
@@ -0,0 +1,17 @@
+/*
+ * BSS load update
+ * Copyright (c) 2014, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef BSS_LOAD_UPDATE_H
+#define BSS_LOAD_UPDATE_H
+
+
+int bss_load_update_init(struct hostapd_data *hapd);
+void bss_load_update_deinit(struct hostapd_data *hapd);
+
+
+#endif /* BSS_LOAD_UPDATE_H */
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 39edbd7..8c84e3e 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -1,6 +1,6 @@
/*
* Control interface for shared AP commands
- * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,6 +10,7 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
+#include "common/sae.h"
#include "eapol_auth/eapol_auth_sm.h"
#include "hostapd.h"
#include "ieee802_1x.h"
@@ -36,7 +37,7 @@
"rx_bytes=%lu\ntx_bytes=%lu\n",
data.rx_packets, data.tx_packets,
data.rx_bytes, data.tx_bytes);
- if (ret < 0 || (size_t) ret >= buflen)
+ if (os_snprintf_error(buflen, ret))
return 0;
return ret;
}
@@ -55,7 +56,7 @@
ret = os_snprintf(buf, buflen, "connected_time=%u\n",
(unsigned int) age.sec);
- if (ret < 0 || (size_t) ret >= buflen)
+ if (os_snprintf_error(buflen, ret))
return 0;
return ret;
}
@@ -92,7 +93,7 @@
len = 0;
ret = os_snprintf(buf + len, buflen - len, MACSTR "\nflags=",
MAC2STR(sta->addr));
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -104,7 +105,7 @@
ret = os_snprintf(buf + len, buflen - len, "\naid=%d\ncapability=0x%x\n"
"listen_interval=%d\nsupported_rates=",
sta->aid, sta->capability, sta->listen_interval);
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -112,14 +113,14 @@
ret = os_snprintf(buf + len, buflen - len, "%02x%s",
sta->supported_rates[i],
i + 1 < sta->supported_rates_len ? " " : "");
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
}
ret = os_snprintf(buf + len, buflen - len, "\ntimeout_next=%s\n",
timeout_next_str(sta->timeout_next));
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -143,6 +144,15 @@
len += hostapd_get_sta_tx_rx(hapd, sta, buf + len, buflen - len);
len += hostapd_get_sta_conn_time(sta, buf + len, buflen - len);
+#ifdef CONFIG_SAE
+ if (sta->sae && sta->sae->state == SAE_ACCEPTED) {
+ res = os_snprintf(buf + len, buflen - len, "sae_group=%d\n",
+ sta->sae->group);
+ if (!os_snprintf_error(buflen - len, res))
+ len += res;
+ }
+#endif /* CONFIG_SAE */
+
return len;
}
@@ -164,7 +174,7 @@
if (hwaddr_aton(txtaddr, addr)) {
ret = os_snprintf(buf, buflen, "FAIL\n");
- if (ret < 0 || (size_t) ret >= buflen)
+ if (os_snprintf_error(buflen, ret))
return 0;
return ret;
}
@@ -203,7 +213,7 @@
if (hwaddr_aton(txtaddr, addr) ||
(sta = ap_get_sta(hapd, addr)) == NULL) {
ret = os_snprintf(buf, buflen, "FAIL\n");
- if (ret < 0 || (size_t) ret >= buflen)
+ if (os_snprintf_error(buflen, ret))
return 0;
return ret;
}
@@ -422,7 +432,7 @@
iface->num_sta_ht40_intolerant,
iface->olbc_ht,
iface->ht_op_mode);
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -444,7 +454,7 @@
iface->dfs_cac_ms / 1000,
left_time);
}
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -463,7 +473,7 @@
iface->conf->vht_oper_chwidth,
iface->conf->vht_oper_centr_freq_seg0_idx,
iface->conf->vht_oper_centr_freq_seg1_idx);
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -480,7 +490,7 @@
wpa_ssid_txt(bss->conf->ssid.ssid,
bss->conf->ssid.ssid_len),
(int) i, bss->num_sta);
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
}
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index a6ec20b..0db5ef6 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -440,7 +440,8 @@
if (num_available_chandefs == 0)
return NULL;
- os_get_random((u8 *) &_rand, sizeof(_rand));
+ if (os_get_random((u8 *) &_rand, sizeof(_rand)) < 0)
+ _rand = os_random();
chan_idx = _rand % num_available_chandefs;
dfs_find_channel(iface, &chan, chan_idx, skip_radar);
@@ -639,6 +640,16 @@
int res, n_chans, n_chans1, start_chan_idx, start_chan_idx1;
int skip_radar = 0;
+ if (!iface->current_mode) {
+ /*
+ * This can happen with drivers that do not provide mode
+ * information and as such, cannot really use hostapd for DFS.
+ */
+ wpa_printf(MSG_DEBUG,
+ "DFS: No current_mode information - assume no need to perform DFS operations by hostapd");
+ return 1;
+ }
+
iface->cac_started = 0;
do {
diff --git a/src/ap/dhcp_snoop.c b/src/ap/dhcp_snoop.c
new file mode 100644
index 0000000..a706024
--- /dev/null
+++ b/src/ap/dhcp_snoop.c
@@ -0,0 +1,166 @@
+/*
+ * DHCP snooping for Proxy ARP
+ * Copyright (c) 2014, 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 <netinet/ip.h>
+#include <netinet/udp.h>
+
+#include "utils/common.h"
+#include "l2_packet/l2_packet.h"
+#include "hostapd.h"
+#include "sta_info.h"
+#include "ap_drv_ops.h"
+#include "x_snoop.h"
+#include "dhcp_snoop.h"
+
+struct bootp_pkt {
+ struct iphdr iph;
+ struct udphdr udph;
+ u8 op;
+ u8 htype;
+ u8 hlen;
+ u8 hops;
+ be32 xid;
+ be16 secs;
+ be16 flags;
+ be32 client_ip;
+ be32 your_ip;
+ be32 server_ip;
+ be32 relay_ip;
+ u8 hw_addr[16];
+ u8 serv_name[64];
+ u8 boot_file[128];
+ u8 exten[312];
+} STRUCT_PACKED;
+
+#define DHCPACK 5
+static const u8 ic_bootp_cookie[] = { 99, 130, 83, 99 };
+
+
+static void handle_dhcp(void *ctx, const u8 *src_addr, const u8 *buf,
+ size_t len)
+{
+ struct hostapd_data *hapd = ctx;
+ const struct bootp_pkt *b;
+ struct sta_info *sta;
+ int exten_len;
+ const u8 *end, *pos;
+ int res, msgtype = 0, prefixlen = 32;
+ u32 subnet_mask = 0;
+ u16 tot_len;
+
+ exten_len = len - ETH_HLEN - (sizeof(*b) - sizeof(b->exten));
+ if (exten_len < 4)
+ return;
+
+ b = (const struct bootp_pkt *) &buf[ETH_HLEN];
+ tot_len = ntohs(b->iph.tot_len);
+ if (tot_len > (unsigned int) (len - ETH_HLEN))
+ return;
+
+ if (os_memcmp(b->exten, ic_bootp_cookie, ARRAY_SIZE(ic_bootp_cookie)))
+ return;
+
+ /* Parse DHCP options */
+ end = (const u8 *) b + tot_len;
+ pos = &b->exten[4];
+ while (pos < end && *pos != 0xff) {
+ const u8 *opt = pos++;
+
+ if (*opt == 0) /* padding */
+ continue;
+
+ pos += *pos + 1;
+ if (pos >= end)
+ break;
+
+ switch (*opt) {
+ case 1: /* subnet mask */
+ if (opt[1] == 4)
+ subnet_mask = WPA_GET_BE32(&opt[2]);
+ if (subnet_mask == 0)
+ return;
+ while (!(subnet_mask & 0x1)) {
+ subnet_mask >>= 1;
+ prefixlen--;
+ }
+ break;
+ case 53: /* message type */
+ if (opt[1])
+ msgtype = opt[2];
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (msgtype == DHCPACK) {
+ if (b->your_ip == 0)
+ return;
+
+ /* DHCPACK for DHCPREQUEST */
+ sta = ap_get_sta(hapd, b->hw_addr);
+ if (!sta)
+ return;
+
+ wpa_printf(MSG_DEBUG, "dhcp_snoop: Found DHCPACK for " MACSTR
+ " @ IPv4 address %X/%d",
+ MAC2STR(sta->addr), ntohl(b->your_ip), prefixlen);
+
+ if (sta->ipaddr == b->your_ip)
+ return;
+
+ if (sta->ipaddr != 0) {
+ wpa_printf(MSG_DEBUG,
+ "dhcp_snoop: Removing IPv4 address %X from the ip neigh table",
+ sta->ipaddr);
+ hostapd_drv_br_delete_ip_neigh(hapd, 4,
+ (u8 *) &sta->ipaddr);
+ }
+
+ res = hostapd_drv_br_add_ip_neigh(hapd, 4, (u8 *) &b->your_ip,
+ prefixlen, sta->addr);
+ if (res) {
+ wpa_printf(MSG_DEBUG,
+ "dhcp_snoop: Adding ip neigh table failed: %d",
+ res);
+ return;
+ }
+ sta->ipaddr = b->your_ip;
+ }
+
+ if (hapd->conf->disable_dgaf && is_broadcast_ether_addr(buf)) {
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (!(sta->flags & WLAN_STA_AUTHORIZED))
+ continue;
+ x_snoop_mcast_to_ucast_convert_send(hapd, sta,
+ (u8 *) buf, len);
+ }
+ }
+}
+
+
+int dhcp_snoop_init(struct hostapd_data *hapd)
+{
+ hapd->sock_dhcp = x_snoop_get_l2_packet(hapd, handle_dhcp,
+ L2_PACKET_FILTER_DHCP);
+ if (hapd->sock_dhcp == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "dhcp_snoop: Failed to initialize L2 packet processing for DHCP packet: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void dhcp_snoop_deinit(struct hostapd_data *hapd)
+{
+ l2_packet_deinit(hapd->sock_dhcp);
+}
diff --git a/src/ap/dhcp_snoop.h b/src/ap/dhcp_snoop.h
new file mode 100644
index 0000000..93d0050
--- /dev/null
+++ b/src/ap/dhcp_snoop.h
@@ -0,0 +1,30 @@
+/*
+ * DHCP snooping for Proxy ARP
+ * Copyright (c) 2014, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DHCP_SNOOP_H
+#define DHCP_SNOOP_H
+
+#ifdef CONFIG_PROXYARP
+
+int dhcp_snoop_init(struct hostapd_data *hapd);
+void dhcp_snoop_deinit(struct hostapd_data *hapd);
+
+#else /* CONFIG_PROXYARP */
+
+static inline int dhcp_snoop_init(struct hostapd_data *hapd)
+{
+ return 0;
+}
+
+static inline void dhcp_snoop_deinit(struct hostapd_data *hapd)
+{
+}
+
+#endif /* CONFIG_PROXYARP */
+
+#endif /* DHCP_SNOOP_H */
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 3bde720..40a2a9c 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -442,9 +442,10 @@
int channel, chwidth, seg0_idx = 0, seg1_idx = 0;
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_INFO, "driver had channel switch: "
- "freq=%d, ht=%d, offset=%d, width=%d, cf1=%d, cf2=%d",
- freq, ht, offset, width, cf1, cf2);
+ HOSTAPD_LEVEL_INFO,
+ "driver had channel switch: freq=%d, ht=%d, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
+ freq, ht, offset, width, channel_width_to_string(width),
+ cf1, cf2);
hapd->iface->freq = freq;
@@ -489,6 +490,8 @@
hapd->iconf->channel = channel;
hapd->iconf->ieee80211n = ht;
+ if (!ht)
+ hapd->iconf->ieee80211ac = 0;
hapd->iconf->secondary_channel = offset;
hapd->iconf->vht_oper_chwidth = chwidth;
hapd->iconf->vht_oper_centr_freq_seg0_idx = seg0_idx;
@@ -522,6 +525,51 @@
}
+#ifdef CONFIG_ACS
+static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
+ u8 pri_channel, u8 sec_channel)
+{
+ int channel;
+ int ret;
+
+ if (hapd->iconf->channel) {
+ wpa_printf(MSG_INFO, "ACS: Channel was already set to %d",
+ hapd->iconf->channel);
+ return;
+ }
+
+ hapd->iface->freq = hostapd_hw_get_freq(hapd, pri_channel);
+
+ channel = pri_channel;
+ if (!channel) {
+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_WARNING,
+ "driver switched to bad channel");
+ return;
+ }
+
+ hapd->iconf->channel = channel;
+
+ if (sec_channel == 0)
+ hapd->iconf->secondary_channel = 0;
+ else if (sec_channel < pri_channel)
+ hapd->iconf->secondary_channel = -1;
+ else if (sec_channel > pri_channel)
+ hapd->iconf->secondary_channel = 1;
+ else {
+ wpa_printf(MSG_ERROR, "Invalid secondary channel!");
+ return;
+ }
+
+ ret = hostapd_acs_completed(hapd->iface, 0);
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "ACS: Possibly channel configuration is invalid");
+ }
+}
+#endif /* CONFIG_ACS */
+
+
int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
const u8 *bssid, const u8 *ie, size_t ie_len,
int ssi_signal)
@@ -858,6 +906,42 @@
}
+static void hostapd_single_channel_get_survey(struct hostapd_iface *iface,
+ struct survey_results *survey_res)
+{
+ struct hostapd_channel_data *chan;
+ struct freq_survey *survey;
+ u64 divisor, dividend;
+
+ survey = dl_list_first(&survey_res->survey_list, struct freq_survey,
+ list);
+ if (!survey || !survey->freq)
+ return;
+
+ chan = hostapd_get_mode_channel(iface, survey->freq);
+ if (!chan || chan->flag & HOSTAPD_CHAN_DISABLED)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Single Channel Survey: (freq=%d channel_time=%ld channel_time_busy=%ld)",
+ survey->freq,
+ (unsigned long int) survey->channel_time,
+ (unsigned long int) survey->channel_time_busy);
+
+ if (survey->channel_time > iface->last_channel_time &&
+ survey->channel_time > survey->channel_time_busy) {
+ dividend = survey->channel_time_busy -
+ iface->last_channel_time_busy;
+ divisor = survey->channel_time - iface->last_channel_time;
+
+ iface->channel_utilization = dividend * 255 / divisor;
+ wpa_printf(MSG_DEBUG, "Channel Utilization: %d",
+ iface->channel_utilization);
+ }
+ iface->last_channel_time = survey->channel_time;
+ iface->last_channel_time_busy = survey->channel_time_busy;
+}
+
+
static void hostapd_event_get_survey(struct hostapd_data *hapd,
struct survey_results *survey_results)
{
@@ -870,6 +954,11 @@
return;
}
+ if (survey_results->freq_filter) {
+ hostapd_single_channel_get_survey(iface, survey_results);
+ return;
+ }
+
dl_list_for_each_safe(survey, tmp, &survey_results->survey_list,
struct freq_survey, list) {
chan = hostapd_get_mode_channel(iface, survey->freq);
@@ -979,12 +1068,6 @@
if (hapd->iface->scan_cb)
hapd->iface->scan_cb(hapd->iface);
break;
-#ifdef CONFIG_IEEE80211R
- case EVENT_FT_RRB_RX:
- wpa_ft_rrb_rx(hapd->wpa_auth, data->ft_rrb_rx.src,
- data->ft_rrb_rx.data, data->ft_rrb_rx.data_len);
- break;
-#endif /* CONFIG_IEEE80211R */
case EVENT_WPS_BUTTON_PUSHED:
hostapd_wps_button_pushed(hapd, NULL);
break;
@@ -1125,6 +1208,19 @@
hapd->iface, data->channel_list_changed.initiator);
break;
#endif /* NEED_AP_MLME */
+ case EVENT_INTERFACE_ENABLED:
+ wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_ENABLED);
+ break;
+ case EVENT_INTERFACE_DISABLED:
+ wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_DISABLED);
+ break;
+#ifdef CONFIG_ACS
+ case EVENT_ACS_CHANNEL_SELECTED:
+ hostapd_acs_channel_selected(
+ hapd, data->acs_selected_channels.pri_channel,
+ data->acs_selected_channels.sec_channel);
+ break;
+#endif /* CONFIG_ACS */
default:
wpa_printf(MSG_DEBUG, "Unknown event %d", event);
break;
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
index ad07107..9d19f98 100644
--- a/src/ap/gas_serv.c
+++ b/src/ap/gas_serv.c
@@ -58,7 +58,7 @@
}
if (sta->gas_dialog == NULL) {
- sta->gas_dialog = os_zalloc(GAS_DIALOG_MAX *
+ sta->gas_dialog = os_calloc(GAS_DIALOG_MAX,
sizeof(struct gas_dialog_info));
if (sta->gas_dialog == NULL)
return NULL;
@@ -748,6 +748,7 @@
size_t home_realm_query_len;
const u8 *icon_name;
size_t icon_name_len;
+ int p2p_sd;
};
@@ -919,6 +920,21 @@
return;
}
+#ifdef CONFIG_P2P
+ if (*pos == P2P_OUI_TYPE) {
+ /*
+ * This is for P2P SD and will be taken care of by the P2P
+ * implementation. This query needs to be ignored in the generic
+ * GAS server to avoid duplicated response.
+ */
+ wpa_printf(MSG_DEBUG,
+ "ANQP: Ignore WFA vendor type %u (P2P SD) in generic GAS server",
+ *pos);
+ qi->p2p_sd = 1;
+ return;
+ }
+#endif /* CONFIG_P2P */
+
if (*pos != HS20_ANQP_OUI_TYPE) {
wpa_printf(MSG_DEBUG, "ANQP: Unsupported WFA vendor type %u",
*pos);
@@ -969,6 +985,14 @@
buf);
if (!buf)
return;
+#ifdef CONFIG_P2P
+ if (wpabuf_len(buf) == 0 && qi->p2p_sd) {
+ wpa_printf(MSG_DEBUG,
+ "ANQP: Do not send response to P2P SD from generic GAS service (P2P SD implementation will process this)");
+ wpabuf_free(buf);
+ return;
+ }
+#endif /* CONFIG_P2P */
if (wpabuf_len(buf) > hapd->gas_frag_limit ||
hapd->conf->gas_comeback_delay) {
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 3142391..b641503 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -15,6 +15,8 @@
#include "radius/radius_client.h"
#include "radius/radius_das.h"
#include "eap_server/tncs.h"
+#include "eapol_auth/eapol_auth_sm.h"
+#include "eapol_auth/eapol_auth_sm_i.h"
#include "hostapd.h"
#include "authsrv.h"
#include "sta_info.h"
@@ -35,6 +37,10 @@
#include "gas_serv.h"
#include "dfs.h"
#include "ieee802_11.h"
+#include "bss_load.h"
+#include "x_snoop.h"
+#include "dhcp_snoop.h"
+#include "ndisc_snoop.h"
static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
@@ -252,6 +258,16 @@
static void hostapd_free_hapd_data(struct hostapd_data *hapd)
{
+ os_free(hapd->probereq_cb);
+ hapd->probereq_cb = NULL;
+
+#ifdef CONFIG_P2P
+ wpabuf_free(hapd->p2p_beacon_ie);
+ hapd->p2p_beacon_ie = NULL;
+ wpabuf_free(hapd->p2p_probe_resp_ie);
+ hapd->p2p_probe_resp_ie = NULL;
+#endif /* CONFIG_P2P */
+
if (!hapd->started) {
wpa_printf(MSG_ERROR, "%s: Interface %s wasn't started",
__func__, hapd->conf->iface);
@@ -294,28 +310,28 @@
}
}
- os_free(hapd->probereq_cb);
- hapd->probereq_cb = NULL;
-
-#ifdef CONFIG_P2P
- wpabuf_free(hapd->p2p_beacon_ie);
- hapd->p2p_beacon_ie = NULL;
- wpabuf_free(hapd->p2p_probe_resp_ie);
- hapd->p2p_probe_resp_ie = NULL;
-#endif /* CONFIG_P2P */
-
wpabuf_free(hapd->time_adv);
#ifdef CONFIG_INTERWORKING
gas_serv_deinit(hapd);
#endif /* CONFIG_INTERWORKING */
+ bss_load_update_deinit(hapd);
+ ndisc_snoop_deinit(hapd);
+ dhcp_snoop_deinit(hapd);
+ x_snoop_deinit(hapd);
+
#ifdef CONFIG_SQLITE
bin_clear_free(hapd->tmp_eap_user.identity,
hapd->tmp_eap_user.identity_len);
bin_clear_free(hapd->tmp_eap_user.password,
hapd->tmp_eap_user.password_len);
#endif /* CONFIG_SQLITE */
+
+#ifdef CONFIG_MESH
+ wpabuf_free(hapd->mesh_pending_auth);
+ hapd->mesh_pending_auth = NULL;
+#endif /* CONFIG_MESH */
}
@@ -600,51 +616,190 @@
static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,
- struct radius_das_attrs *attr)
+ struct radius_das_attrs *attr,
+ int *multi)
{
- struct sta_info *sta = NULL;
+ struct sta_info *selected, *sta;
char buf[128];
+ int num_attr = 0;
+ int count;
- if (attr->sta_addr)
+ *multi = 0;
+
+ for (sta = hapd->sta_list; sta; sta = sta->next)
+ sta->radius_das_match = 1;
+
+ if (attr->sta_addr) {
+ num_attr++;
sta = ap_get_sta(hapd, attr->sta_addr);
+ if (!sta) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: No Calling-Station-Id match");
+ return NULL;
+ }
- if (sta == NULL && attr->acct_session_id &&
- attr->acct_session_id_len == 17) {
+ selected = sta;
for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (sta != selected)
+ sta->radius_das_match = 0;
+ }
+ wpa_printf(MSG_DEBUG, "RADIUS DAS: Calling-Station-Id match");
+ }
+
+ if (attr->acct_session_id) {
+ num_attr++;
+ if (attr->acct_session_id_len != 17) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: Acct-Session-Id cannot match");
+ return NULL;
+ }
+ count = 0;
+
+ 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)
- break;
+ if (os_memcmp(attr->acct_session_id, buf, 17) != 0)
+ sta->radius_das_match = 0;
+ else
+ count++;
}
+
+ if (count == 0) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: No matches remaining after Acct-Session-Id check");
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG, "RADIUS DAS: Acct-Session-Id match");
}
- if (sta == NULL && attr->cui) {
+ if (attr->acct_multi_session_id) {
+ num_attr++;
+ if (attr->acct_multi_session_id_len != 17) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: Acct-Multi-Session-Id cannot match");
+ return NULL;
+ }
+ count = 0;
+
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (!sta->radius_das_match)
+ continue;
+ if (!sta->eapol_sm ||
+ !sta->eapol_sm->acct_multi_session_id_hi) {
+ 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) !=
+ 0)
+ sta->radius_das_match = 0;
+ else
+ count++;
+ }
+
+ if (count == 0) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: No matches remaining after Acct-Multi-Session-Id check");
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: Acct-Multi-Session-Id match");
+ }
+
+ if (attr->cui) {
+ num_attr++;
+ count = 0;
+
for (sta = hapd->sta_list; sta; sta = sta->next) {
struct wpabuf *cui;
+
+ if (!sta->radius_das_match)
+ continue;
cui = ieee802_1x_get_radius_cui(sta->eapol_sm);
- if (cui && wpabuf_len(cui) == attr->cui_len &&
+ if (!cui || wpabuf_len(cui) != attr->cui_len ||
os_memcmp(wpabuf_head(cui), attr->cui,
- attr->cui_len) == 0)
- break;
+ attr->cui_len) != 0)
+ sta->radius_das_match = 0;
+ else
+ count++;
}
+
+ if (count == 0) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: No matches remaining after Chargeable-User-Identity check");
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: Chargeable-User-Identity match");
}
- if (sta == NULL && attr->user_name) {
+ if (attr->user_name) {
+ num_attr++;
+ count = 0;
+
for (sta = hapd->sta_list; sta; sta = sta->next) {
u8 *identity;
size_t identity_len;
+
+ if (!sta->radius_das_match)
+ continue;
identity = ieee802_1x_get_identity(sta->eapol_sm,
&identity_len);
- if (identity &&
- identity_len == attr->user_name_len &&
+ if (!identity ||
+ identity_len != attr->user_name_len ||
os_memcmp(identity, attr->user_name, identity_len)
- == 0)
- break;
+ != 0)
+ sta->radius_das_match = 0;
+ else
+ count++;
+ }
+
+ if (count == 0) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: No matches remaining after User-Name check");
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: User-Name match");
+ }
+
+ if (num_attr == 0) {
+ /*
+ * In theory, we could match all current associations, but it
+ * seems safer to just reject requests that do not include any
+ * session identification attributes.
+ */
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: No session identification attributes included");
+ return NULL;
+ }
+
+ selected = NULL;
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (sta->radius_das_match) {
+ if (selected) {
+ *multi = 1;
+ return NULL;
+ }
+ selected = sta;
}
}
- return sta;
+ return selected;
+}
+
+
+static int hostapd_das_disconnect_pmksa(struct hostapd_data *hapd,
+ struct radius_das_attrs *attr)
+{
+ if (!hapd->wpa_auth)
+ return -1;
+ return wpa_auth_radius_das_disconnect_pmksa(hapd->wpa_auth, attr);
}
@@ -653,14 +808,29 @@
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta;
+ int multi;
if (hostapd_das_nas_mismatch(hapd, attr))
return RADIUS_DAS_NAS_MISMATCH;
- sta = hostapd_das_find_sta(hapd, attr);
- if (sta == NULL)
+ sta = hostapd_das_find_sta(hapd, attr, &multi);
+ if (sta == NULL) {
+ if (multi) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: Multiple sessions match - not supported");
+ return RADIUS_DAS_MULTI_SESSION_MATCH;
+ }
+ if (hostapd_das_disconnect_pmksa(hapd, attr) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: PMKSA cache entry matched");
+ return RADIUS_DAS_SUCCESS;
+ }
+ wpa_printf(MSG_DEBUG, "RADIUS DAS: No matching session found");
return RADIUS_DAS_SESSION_NOT_FOUND;
+ }
+ wpa_printf(MSG_DEBUG, "RADIUS DAS: Found a matching session " MACSTR
+ " - disconnecting", MAC2STR(sta->addr));
wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
hostapd_drv_sta_deauth(hapd, sta->addr,
@@ -691,6 +861,7 @@
int ssid_len, set_ssid;
char force_ifname[IFNAMSIZ];
u8 if_addr[ETH_ALEN];
+ int flush_old_stations = 1;
wpa_printf(MSG_DEBUG, "%s(hapd=%p (%s), first=%d)",
__func__, hapd, conf->iface, first);
@@ -745,7 +916,14 @@
if (conf->wmm_enabled < 0)
conf->wmm_enabled = hapd->iconf->ieee80211n;
- hostapd_flush_old_stations(hapd, WLAN_REASON_PREV_AUTH_NOT_VALID);
+#ifdef CONFIG_MESH
+ if (hapd->iface->mconf == NULL)
+ flush_old_stations = 0;
+#endif /* CONFIG_MESH */
+
+ if (flush_old_stations)
+ hostapd_flush_old_stations(hapd,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
hostapd_set_privacy(hapd, 0);
hostapd_broadcast_wep_clear(hapd);
@@ -875,6 +1053,31 @@
}
#endif /* CONFIG_INTERWORKING */
+ if (conf->bss_load_update_period && bss_load_update_init(hapd)) {
+ wpa_printf(MSG_ERROR, "BSS Load initialization failed");
+ return -1;
+ }
+
+ if (conf->proxy_arp) {
+ if (x_snoop_init(hapd)) {
+ wpa_printf(MSG_ERROR,
+ "Generic snooping infrastructure initialization failed");
+ return -1;
+ }
+
+ if (dhcp_snoop_init(hapd)) {
+ wpa_printf(MSG_ERROR,
+ "DHCP snooping initialization failed");
+ return -1;
+ }
+
+ if (ndisc_snoop_init(hapd)) {
+ wpa_printf(MSG_ERROR,
+ "Neighbor Discovery snooping initialization failed");
+ return -1;
+ }
+ }
+
if (!hostapd_drv_none(hapd) && vlan_init(hapd)) {
wpa_printf(MSG_ERROR, "VLAN initialization failed.");
return -1;
@@ -899,6 +1102,11 @@
int i;
struct hostapd_tx_queue_params *p;
+#ifdef CONFIG_MESH
+ if (iface->mconf == NULL)
+ return;
+#endif /* CONFIG_MESH */
+
for (i = 0; i < NUM_TX_QUEUES; i++) {
p = &iface->conf->tx_queue[i];
@@ -1164,6 +1372,7 @@
struct hostapd_data *hapd = iface->bss[0];
size_t j;
u8 *prev_addr;
+ int delay_apply_cfg = 0;
if (err)
goto fail;
@@ -1193,7 +1402,17 @@
}
#endif /* NEED_AP_MLME */
- if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
+#ifdef CONFIG_MESH
+ if (iface->mconf != NULL) {
+ wpa_printf(MSG_DEBUG,
+ "%s: Mesh configuration will be applied while joining the mesh network",
+ iface->bss[0]->conf->iface);
+ delay_apply_cfg = 1;
+ }
+#endif /* CONFIG_MESH */
+
+ if (!delay_apply_cfg &&
+ hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
hapd->iconf->channel,
hapd->iconf->ieee80211n,
hapd->iconf->ieee80211ac,
@@ -1809,33 +2028,37 @@
}
-static struct hostapd_iface * hostapd_data_alloc(
- struct hapd_interfaces *interfaces, struct hostapd_config *conf)
+static int hostapd_data_alloc(struct hostapd_iface *hapd_iface,
+ struct hostapd_config *conf)
{
size_t i;
- struct hostapd_iface *hapd_iface =
- interfaces->iface[interfaces->count - 1];
struct hostapd_data *hapd;
- hapd_iface->conf = conf;
- hapd_iface->num_bss = conf->num_bss;
-
- hapd_iface->bss = os_zalloc(conf->num_bss *
+ hapd_iface->bss = os_calloc(conf->num_bss,
sizeof(struct hostapd_data *));
if (hapd_iface->bss == NULL)
- return NULL;
+ return -1;
for (i = 0; i < conf->num_bss; i++) {
hapd = hapd_iface->bss[i] =
hostapd_alloc_bss_data(hapd_iface, conf, conf->bss[i]);
- if (hapd == NULL)
- return NULL;
+ if (hapd == NULL) {
+ while (i > 0) {
+ i--;
+ os_free(hapd_iface->bss[i]);
+ hapd_iface->bss[i] = NULL;
+ }
+ os_free(hapd_iface->bss);
+ hapd_iface->bss = NULL;
+ return -1;
+ }
hapd->msg_ctx = hapd;
}
- hapd_iface->interfaces = interfaces;
+ hapd_iface->conf = conf;
+ hapd_iface->num_bss = conf->num_bss;
- return hapd_iface;
+ return 0;
}
@@ -1882,9 +2105,14 @@
}
if (new_iface) {
- if (interfaces->driver_init(hapd_iface) ||
- hostapd_setup_interface(hapd_iface)) {
- interfaces->count--;
+ if (interfaces->driver_init(hapd_iface))
+ goto fail;
+
+ if (hostapd_setup_interface(hapd_iface)) {
+ hostapd_deinit_driver(
+ hapd_iface->bss[0]->driver,
+ hapd_iface->bss[0]->drv_priv,
+ hapd_iface);
goto fail;
}
} else {
@@ -1904,6 +2132,8 @@
hapd_iface->num_bss--;
wpa_printf(MSG_DEBUG, "%s: free hapd %p %s",
__func__, hapd, hapd->conf->iface);
+ hostapd_config_free_bss(hapd->conf);
+ hapd->conf = NULL;
os_free(hapd);
return -1;
}
@@ -1934,6 +2164,7 @@
"for interface", __func__);
goto fail;
}
+ new_iface = hapd_iface;
if (conf_file && interfaces->config_read_cb) {
conf = interfaces->config_read_cb(conf_file);
@@ -1948,17 +2179,18 @@
goto fail;
}
- hapd_iface = hostapd_data_alloc(interfaces, conf);
- if (hapd_iface == NULL) {
+ if (hostapd_data_alloc(hapd_iface, conf) < 0) {
wpa_printf(MSG_ERROR, "%s: Failed to allocate memory "
"for hostapd", __func__);
goto fail;
}
+ conf = NULL;
if (start_ctrl_iface(hapd_iface) < 0)
goto fail;
- wpa_printf(MSG_INFO, "Add interface '%s'", conf->bss[0]->iface);
+ wpa_printf(MSG_INFO, "Add interface '%s'",
+ hapd_iface->conf->bss[0]->iface);
return 0;
@@ -1978,14 +2210,18 @@
wpa_printf(MSG_DEBUG, "%s: free hapd %p (%s)",
__func__, hapd_iface->bss[i],
hapd->conf->iface);
+ hostapd_cleanup(hapd);
os_free(hapd);
hapd_iface->bss[i] = NULL;
}
os_free(hapd_iface->bss);
+ hapd_iface->bss = NULL;
}
- wpa_printf(MSG_DEBUG, "%s: free iface %p",
- __func__, hapd_iface);
- os_free(hapd_iface);
+ if (new_iface) {
+ interfaces->count--;
+ interfaces->iface[interfaces->count] = NULL;
+ }
+ hostapd_cleanup_iface(hapd_iface);
}
return -1;
}
@@ -2005,6 +2241,7 @@
wpa_printf(MSG_DEBUG, "%s: free hapd %p (%s)",
__func__, hapd, hapd->conf->iface);
hostapd_config_free_bss(hapd->conf);
+ hapd->conf = NULL;
os_free(hapd);
iface->num_bss--;
@@ -2367,6 +2604,12 @@
struct csa_settings *settings)
{
int ret;
+
+ if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA)) {
+ wpa_printf(MSG_INFO, "CSA is not supported");
+ return -1;
+ }
+
ret = hostapd_fill_csa_settings(hapd, settings);
if (ret)
return ret;
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 3c8727b..8e2c70e 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -1,6 +1,6 @@
/*
* hostapd / Initialization and configuration
- * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,6 +10,7 @@
#define HOSTAPD_H
#include "common/defs.h"
+#include "utils/list.h"
#include "ap_config.h"
#include "drivers/driver.h"
@@ -22,6 +23,9 @@
struct full_dynamic_vlan;
enum wps_event;
union wps_event_data;
+#ifdef CONFIG_MESH
+struct mesh_conf;
+#endif /* CONFIG_MESH */
struct hostapd_iface;
@@ -150,6 +154,7 @@
void *ssl_ctx;
void *eap_sim_db_priv;
struct radius_server_data *radius_srv;
+ struct dl_list erp_keys; /* struct eap_server_erp_key */
int parameter_set_count;
@@ -218,6 +223,9 @@
unsigned int cs_c_off_proberesp;
int csa_in_progress;
+ /* BSS Load */
+ unsigned int bss_load_update_timeout;
+
#ifdef CONFIG_P2P
struct p2p_data *p2p;
struct p2p_group *p2p_group;
@@ -235,6 +243,17 @@
#ifdef CONFIG_INTERWORKING
size_t gas_frag_limit;
#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_PROXYARP
+ struct l2_packet_data *sock_dhcp;
+ struct l2_packet_data *sock_ndisc;
+#endif /* CONFIG_PROXYARP */
+#ifdef CONFIG_MESH
+ int num_plinks;
+ int max_plinks;
+ void (*mesh_sta_free_cb)(struct sta_info *sta);
+ struct wpabuf *mesh_pending_auth;
+ struct os_reltime mesh_pending_auth_time;
+#endif /* CONFIG_MESH */
#ifdef CONFIG_SQLITE
struct hostapd_eap_user tmp_eap_user;
@@ -247,7 +266,10 @@
#endif /* CONFIG_SAE */
#ifdef CONFIG_TESTING_OPTIONS
- int ext_mgmt_frame_handling;
+ unsigned int ext_mgmt_frame_handling:1;
+ unsigned int ext_eapol_frame_io:1;
+
+ struct l2_packet_data *l2_test;
#endif /* CONFIG_TESTING_OPTIONS */
};
@@ -272,6 +294,10 @@
HAPD_IFACE_ENABLED
} state;
+#ifdef CONFIG_MESH
+ struct mesh_conf *mconf;
+#endif /* CONFIG_MESH */
+
size_t num_bss;
struct hostapd_data **bss;
@@ -288,7 +314,10 @@
struct ap_info *ap_list; /* AP info list head */
struct ap_info *ap_hash[STA_HASH_SIZE];
- unsigned int drv_flags;
+ u64 drv_flags;
+
+ /* SMPS modes supported by the driver (WPA_DRIVER_SMPS_MODE_*) */
+ unsigned int smps_modes;
/*
* A bitmap of supported protocols for probe response offload. See
@@ -351,6 +380,11 @@
/* lowest observed noise floor in dBm */
s8 lowest_nf;
+ /* channel utilization calculation */
+ u64 last_channel_time;
+ u64 last_channel_time_busy;
+ u8 channel_utilization;
+
unsigned int dfs_cac_ms;
struct os_reltime dfs_cac_start;
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 4e66d1b..05431d3 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -15,6 +15,7 @@
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
+#include "common/hw_features_common.h"
#include "hostapd.h"
#include "ap_config.h"
#include "ap_drv_ops.h"
@@ -74,7 +75,7 @@
int hostapd_get_hw_features(struct hostapd_iface *iface)
{
struct hostapd_data *hapd = iface->bss[0];
- int ret = 0, i, j;
+ int i, j;
u16 num_modes, flags;
struct hostapd_hw_modes *modes;
@@ -107,7 +108,8 @@
/*
* Disable all channels that are marked not to allow
- * IBSS operation or active scanning.
+ * to initiate radiation (a.k.a. passive scan and no
+ * IBSS).
* Use radar channels only if the driver supports DFS.
*/
if ((feature->channels[j].flag &
@@ -118,8 +120,7 @@
!(iface->drv_flags &
WPA_DRIVER_FLAGS_DFS_OFFLOAD)) ||
(feature->channels[j].flag &
- (HOSTAPD_CHAN_NO_IBSS |
- HOSTAPD_CHAN_PASSIVE_SCAN))) {
+ HOSTAPD_CHAN_NO_IR)) {
feature->channels[j].flag |=
HOSTAPD_CHAN_DISABLED;
}
@@ -137,7 +138,7 @@
}
}
- return ret;
+ return 0;
}
@@ -223,66 +224,16 @@
#ifdef CONFIG_IEEE80211N
static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface)
{
- int sec_chan, ok, j, first;
- int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
- 184, 192 };
- size_t k;
+ int pri_chan, sec_chan;
if (!iface->conf->secondary_channel)
return 1; /* HT40 not used */
- sec_chan = iface->conf->channel + iface->conf->secondary_channel * 4;
- wpa_printf(MSG_DEBUG, "HT40: control channel: %d "
- "secondary channel: %d",
- iface->conf->channel, sec_chan);
+ pri_chan = iface->conf->channel;
+ sec_chan = pri_chan + iface->conf->secondary_channel * 4;
- /* Verify that HT40 secondary channel is an allowed 20 MHz
- * channel */
- ok = 0;
- for (j = 0; j < iface->current_mode->num_channels; j++) {
- struct hostapd_channel_data *chan =
- &iface->current_mode->channels[j];
- if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
- chan->chan == sec_chan) {
- ok = 1;
- break;
- }
- }
- if (!ok) {
- wpa_printf(MSG_ERROR, "HT40 secondary channel %d not allowed",
- sec_chan);
- return 0;
- }
-
- /*
- * Verify that HT40 primary,secondary channel pair is allowed per
- * IEEE 802.11n Annex J. This is only needed for 5 GHz band since
- * 2.4 GHz rules allow all cases where the secondary channel fits into
- * the list of allowed channels (already checked above).
- */
- if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
- return 1;
-
- if (iface->conf->secondary_channel > 0)
- first = iface->conf->channel;
- else
- first = sec_chan;
-
- ok = 0;
- for (k = 0; k < ARRAY_SIZE(allowed); k++) {
- if (first == allowed[k]) {
- ok = 1;
- break;
- }
- }
- if (!ok) {
- wpa_printf(MSG_ERROR, "HT40 channel pair (%d, %d) not allowed",
- iface->conf->channel,
- iface->conf->secondary_channel);
- return 0;
- }
-
- return 1;
+ return allowed_ht40_channel_pair(iface->current_mode, pri_chan,
+ sec_chan);
}
@@ -298,214 +249,34 @@
}
-static void ieee80211n_get_pri_sec_chan(struct wpa_scan_res *bss,
- int *pri_chan, int *sec_chan)
-{
- struct ieee80211_ht_operation *oper;
- struct ieee802_11_elems elems;
-
- *pri_chan = *sec_chan = 0;
-
- ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0);
- if (elems.ht_operation &&
- elems.ht_operation_len >= sizeof(*oper)) {
- oper = (struct ieee80211_ht_operation *) elems.ht_operation;
- *pri_chan = oper->primary_chan;
- if (oper->ht_param & HT_INFO_HT_PARAM_STA_CHNL_WIDTH) {
- int sec = oper->ht_param &
- HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK;
- if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
- *sec_chan = *pri_chan + 4;
- else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
- *sec_chan = *pri_chan - 4;
- }
- }
-}
-
-
static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface,
struct wpa_scan_results *scan_res)
{
- int pri_chan, sec_chan, pri_freq, sec_freq, pri_bss, sec_bss;
- int bss_pri_chan, bss_sec_chan;
- size_t i;
- int match;
+ int pri_chan, sec_chan;
+ int res;
pri_chan = iface->conf->channel;
sec_chan = pri_chan + iface->conf->secondary_channel * 4;
- pri_freq = hostapd_hw_get_freq(iface->bss[0], pri_chan);
- if (iface->conf->secondary_channel > 0)
- sec_freq = pri_freq + 20;
- else
- sec_freq = pri_freq - 20;
- /*
- * Switch PRI/SEC channels if Beacons were detected on selected SEC
- * channel, but not on selected PRI channel.
- */
- pri_bss = sec_bss = 0;
- for (i = 0; i < scan_res->num; i++) {
- struct wpa_scan_res *bss = scan_res->res[i];
- if (bss->freq == pri_freq)
- pri_bss++;
- else if (bss->freq == sec_freq)
- sec_bss++;
- }
- if (sec_bss && !pri_bss) {
- wpa_printf(MSG_INFO, "Switch own primary and secondary "
- "channel to get secondary channel with no Beacons "
- "from other BSSes");
+ res = check_40mhz_5g(iface->current_mode, scan_res, pri_chan, sec_chan);
+
+ if (res == 2)
ieee80211n_switch_pri_sec(iface);
- return 1;
- }
- /*
- * Match PRI/SEC channel with any existing HT40 BSS on the same
- * channels that we are about to use (if already mixed order in
- * existing BSSes, use own preference).
- */
- match = 0;
- for (i = 0; i < scan_res->num; i++) {
- struct wpa_scan_res *bss = scan_res->res[i];
- ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan);
- if (pri_chan == bss_pri_chan &&
- sec_chan == bss_sec_chan) {
- match = 1;
- break;
- }
- }
- if (!match) {
- for (i = 0; i < scan_res->num; i++) {
- struct wpa_scan_res *bss = scan_res->res[i];
- ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan,
- &bss_sec_chan);
- if (pri_chan == bss_sec_chan &&
- sec_chan == bss_pri_chan) {
- wpa_printf(MSG_INFO, "Switch own primary and "
- "secondary channel due to BSS "
- "overlap with " MACSTR,
- MAC2STR(bss->bssid));
- ieee80211n_switch_pri_sec(iface);
- break;
- }
- }
- }
-
- return 1;
-}
-
-
-static int ieee80211n_check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq,
- int start, int end)
-{
- struct ieee802_11_elems elems;
- struct ieee80211_ht_operation *oper;
-
- if (bss->freq < start || bss->freq > end || bss->freq == pri_freq)
- return 0;
-
- ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0);
- if (!elems.ht_capabilities) {
- wpa_printf(MSG_DEBUG, "Found overlapping legacy BSS: "
- MACSTR " freq=%d", MAC2STR(bss->bssid), bss->freq);
- return 1;
- }
-
- if (elems.ht_operation &&
- elems.ht_operation_len >= sizeof(*oper)) {
- oper = (struct ieee80211_ht_operation *) elems.ht_operation;
- if (oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)
- return 0;
-
- wpa_printf(MSG_DEBUG, "Found overlapping 20 MHz HT BSS: "
- MACSTR " freq=%d", MAC2STR(bss->bssid), bss->freq);
- return 1;
- }
- return 0;
+ return !!res;
}
static int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface,
struct wpa_scan_results *scan_res)
{
- int pri_freq, sec_freq;
- int affected_start, affected_end;
- size_t i;
+ int pri_chan, sec_chan;
- pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
- if (iface->conf->secondary_channel > 0)
- sec_freq = pri_freq + 20;
- else
- sec_freq = pri_freq - 20;
- affected_start = (pri_freq + sec_freq) / 2 - 25;
- affected_end = (pri_freq + sec_freq) / 2 + 25;
- wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
- affected_start, affected_end);
- for (i = 0; i < scan_res->num; i++) {
- struct wpa_scan_res *bss = scan_res->res[i];
- int pri = bss->freq;
- int sec = pri;
- int sec_chan, pri_chan;
- struct ieee802_11_elems elems;
+ pri_chan = iface->conf->channel;
+ sec_chan = pri_chan + iface->conf->secondary_channel * 4;
- /* Check for overlapping 20 MHz BSS */
- if (ieee80211n_check_20mhz_bss(bss, pri_freq, affected_start,
- affected_end)) {
- wpa_printf(MSG_DEBUG,
- "Overlapping 20 MHz BSS is found");
- return 0;
- }
-
- ieee80211n_get_pri_sec_chan(bss, &pri_chan, &sec_chan);
-
- if (sec_chan) {
- if (sec_chan < pri_chan)
- sec = pri - 20;
- else
- sec = pri + 20;
- }
-
- if ((pri < affected_start || pri > affected_end) &&
- (sec < affected_start || sec > affected_end))
- continue; /* not within affected channel range */
-
- wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR
- " freq=%d pri=%d sec=%d",
- MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan);
-
- if (sec_chan) {
- if (pri_freq != pri || sec_freq != sec) {
- wpa_printf(MSG_DEBUG, "40 MHz pri/sec "
- "mismatch with BSS " MACSTR
- " <%d,%d> (chan=%d%c) vs. <%d,%d>",
- MAC2STR(bss->bssid),
- pri, sec, pri_chan,
- sec > pri ? '+' : '-',
- pri_freq, sec_freq);
- return 0;
- }
- }
-
- ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems,
- 0);
- if (elems.ht_capabilities &&
- elems.ht_capabilities_len >=
- sizeof(struct ieee80211_ht_capabilities)) {
- struct ieee80211_ht_capabilities *ht_cap =
- (struct ieee80211_ht_capabilities *)
- elems.ht_capabilities;
-
- if (le_to_host16(ht_cap->ht_capabilities_info) &
- HT_CAP_INFO_40MHZ_INTOLERANT) {
- wpa_printf(MSG_DEBUG,
- "40 MHz Intolerant is set on channel %d in BSS "
- MACSTR, pri, MAC2STR(bss->bssid));
- return 0;
- }
- }
- }
-
- return 1;
+ return check_40mhz_2g4(iface->current_mode, scan_res, pri_chan,
+ sec_chan);
}
@@ -746,11 +517,24 @@
return 0;
}
- if ((conf & HT_CAP_INFO_SMPS_MASK) != (hw & HT_CAP_INFO_SMPS_MASK) &&
- (conf & HT_CAP_INFO_SMPS_MASK) != HT_CAP_INFO_SMPS_DISABLED) {
- wpa_printf(MSG_ERROR, "Driver does not support configured "
- "HT capability [SMPS-*]");
- return 0;
+ switch (conf & HT_CAP_INFO_SMPS_MASK) {
+ case HT_CAP_INFO_SMPS_STATIC:
+ if (!(iface->smps_modes & WPA_DRIVER_SMPS_MODE_STATIC)) {
+ wpa_printf(MSG_ERROR,
+ "Driver does not support configured HT capability [SMPS-STATIC]");
+ return 0;
+ }
+ break;
+ case HT_CAP_INFO_SMPS_DYNAMIC:
+ if (!(iface->smps_modes & WPA_DRIVER_SMPS_MODE_DYNAMIC)) {
+ wpa_printf(MSG_ERROR,
+ "Driver does not support configured HT capability [SMPS-DYNAMIC]");
+ return 0;
+ }
+ break;
+ case HT_CAP_INFO_SMPS_DISABLED:
+ default:
+ break;
}
if ((conf & HT_CAP_INFO_GREEN_FIELD) &&
@@ -839,16 +623,16 @@
}
-static int ieee80211ac_cap_check_max(u32 hw, u32 conf, u32 cap,
+static int ieee80211ac_cap_check_max(u32 hw, u32 conf, u32 mask,
+ unsigned int shift,
const char *name)
{
- u32 hw_max = hw & cap;
- u32 conf_val = conf & cap;
+ u32 hw_max = hw & mask;
+ u32 conf_val = conf & mask;
if (conf_val > hw_max) {
- int offset = find_first_bit(cap);
wpa_printf(MSG_ERROR, "Configured VHT capability [%s] exceeds max value supported by the driver (%d > %d)",
- name, conf_val >> offset, hw_max >> offset);
+ name, conf_val >> shift, hw_max >> shift);
return 0;
}
return 1;
@@ -857,12 +641,31 @@
static int ieee80211ac_supported_vht_capab(struct hostapd_iface *iface)
{
- u32 hw = iface->current_mode->vht_capab;
+ struct hostapd_hw_modes *mode = iface->current_mode;
+ u32 hw = mode->vht_capab;
u32 conf = iface->conf->vht_capab;
wpa_printf(MSG_DEBUG, "hw vht capab: 0x%x, conf vht capab: 0x%x",
hw, conf);
+ if (mode->mode == HOSTAPD_MODE_IEEE80211G &&
+ iface->conf->bss[0]->vendor_vht &&
+ mode->vht_capab == 0 && iface->hw_features) {
+ int i;
+
+ for (i = 0; i < iface->num_hw_features; i++) {
+ if (iface->hw_features[i].mode ==
+ HOSTAPD_MODE_IEEE80211A) {
+ mode = &iface->hw_features[i];
+ hw = mode->vht_capab;
+ wpa_printf(MSG_DEBUG,
+ "update hw vht capab based on 5 GHz band: 0x%x",
+ hw);
+ break;
+ }
+ }
+ }
+
#define VHT_CAP_CHECK(cap) \
do { \
if (!ieee80211ac_cap_check(hw, conf, cap, #cap)) \
@@ -871,7 +674,8 @@
#define VHT_CAP_CHECK_MAX(cap) \
do { \
- if (!ieee80211ac_cap_check_max(hw, conf, cap, #cap)) \
+ if (!ieee80211ac_cap_check_max(hw, conf, cap, cap ## _SHIFT, \
+ #cap)) \
return 0; \
} while (0)
@@ -945,12 +749,10 @@
return 1;
wpa_printf(MSG_DEBUG,
- "%schannel [%i] (%i) is disabled for use in AP mode, flags: 0x%x%s%s%s",
+ "%schannel [%i] (%i) is disabled for use in AP mode, flags: 0x%x%s%s",
primary ? "" : "Configured HT40 secondary ",
i, chan->chan, chan->flag,
- chan->flag & HOSTAPD_CHAN_NO_IBSS ? " NO-IBSS" : "",
- chan->flag & HOSTAPD_CHAN_PASSIVE_SCAN ?
- " PASSIVE-SCAN" : "",
+ chan->flag & HOSTAPD_CHAN_NO_IR ? " NO-IR" : "",
chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : "");
}
@@ -1131,35 +933,11 @@
int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan)
{
- int i;
-
- if (!hapd->iface->current_mode)
- return 0;
-
- for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
- struct hostapd_channel_data *ch =
- &hapd->iface->current_mode->channels[i];
- if (ch->chan == chan)
- return ch->freq;
- }
-
- return 0;
+ return hw_get_freq(hapd->iface->current_mode, chan);
}
int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
{
- int i;
-
- if (!hapd->iface->current_mode)
- return 0;
-
- for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
- struct hostapd_channel_data *ch =
- &hapd->iface->current_mode->channels[i];
- if (ch->freq == freq)
- return ch->chan;
- }
-
- return 0;
+ return hw_get_chan(hapd->iface->current_mode, freq);
}
diff --git a/src/ap/iapp.c b/src/ap/iapp.c
index 9b2900f..99aa04d 100644
--- a/src/ap/iapp.c
+++ b/src/ap/iapp.c
@@ -361,7 +361,7 @@
switch (hdr->command) {
case IAPP_CMD_ADD_notify:
- iapp_process_add_notify(iapp, &from, hdr, hlen - sizeof(*hdr));
+ iapp_process_add_notify(iapp, &from, hdr, len - sizeof(*hdr));
break;
case IAPP_CMD_MOVE_notify:
/* TODO: MOVE is using TCP; so move this to TCP handler once it
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index de1ee5e..89911b1 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -1,6 +1,6 @@
/*
* hostapd / IEEE 802.11 Management
- * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -29,6 +29,7 @@
#include "sta_info.h"
#include "ieee802_1x.h"
#include "wpa_auth.h"
+#include "pmksa_cache_auth.h"
#include "wmm.h"
#include "ap_list.h"
#include "accounting.h"
@@ -198,6 +199,9 @@
(hapd->iconf->spectrum_mgmt_required || dfs))
capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
+ if (hapd->conf->radio_measurements)
+ capab |= IEEE80211_CAP_RRM;
+
return capab;
}
@@ -324,8 +328,12 @@
#ifdef CONFIG_SAE
-static struct wpabuf * auth_process_sae_commit(struct hostapd_data *hapd,
- struct sta_info *sta)
+#define dot11RSNASAERetransPeriod 40 /* msec */
+#define dot11RSNASAESync 5 /* attempts */
+
+
+static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
+ struct sta_info *sta, int update)
{
struct wpabuf *buf;
@@ -334,7 +342,8 @@
return NULL;
}
- if (sae_prepare_commit(hapd->own_addr, sta->addr,
+ if (update &&
+ sae_prepare_commit(hapd->own_addr, sta->addr,
(u8 *) hapd->conf->ssid.wpa_passphrase,
os_strlen(hapd->conf->ssid.wpa_passphrase),
sta->sae) < 0) {
@@ -342,15 +351,11 @@
return NULL;
}
- if (sae_process_commit(sta->sae) < 0) {
- wpa_printf(MSG_DEBUG, "SAE: Failed to process peer commit");
- return NULL;
- }
-
buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN);
if (buf == NULL)
return NULL;
- sae_write_commit(sta->sae, buf, NULL);
+ sae_write_commit(sta->sae, buf, sta->sae->tmp ?
+ sta->sae->tmp->anti_clogging_token : NULL);
return buf;
}
@@ -371,6 +376,46 @@
}
+static int auth_sae_send_commit(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const u8 *bssid, int update)
+{
+ struct wpabuf *data;
+
+ data = auth_build_sae_commit(hapd, sta, update);
+ if (data == NULL)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+ send_auth_reply(hapd, sta->addr, bssid,
+ WLAN_AUTH_SAE, 1, WLAN_STATUS_SUCCESS,
+ wpabuf_head(data), wpabuf_len(data));
+
+ wpabuf_free(data);
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+static int auth_sae_send_confirm(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const u8 *bssid)
+{
+ struct wpabuf *data;
+
+ data = auth_build_sae_confirm(hapd, sta);
+ if (data == NULL)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+ send_auth_reply(hapd, sta->addr, bssid,
+ WLAN_AUTH_SAE, 2, WLAN_STATUS_SUCCESS,
+ wpabuf_head(data), wpabuf_len(data));
+
+ wpabuf_free(data);
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+
static int use_sae_anti_clogging(struct hostapd_data *hapd)
{
struct sta_info *sta;
@@ -411,7 +456,7 @@
static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
- const u8 *addr)
+ int group, const u8 *addr)
{
struct wpabuf *buf;
u8 *token;
@@ -428,10 +473,12 @@
hapd->last_sae_token_key_update = now;
}
- buf = wpabuf_alloc(SHA256_MAC_LEN);
+ buf = wpabuf_alloc(sizeof(le16) + SHA256_MAC_LEN);
if (buf == NULL)
return NULL;
+ wpabuf_put_le16(buf, group); /* Finite Cyclic Group */
+
token = wpabuf_put(buf, SHA256_MAC_LEN);
hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
addr, ETH_ALEN, token);
@@ -440,28 +487,299 @@
}
+static int sae_check_big_sync(struct sta_info *sta)
+{
+ if (sta->sae->sync > dot11RSNASAESync) {
+ sta->sae->state = SAE_NOTHING;
+ sta->sae->sync = 0;
+ return -1;
+ }
+ return 0;
+}
+
+
+static void auth_sae_retransmit_timer(void *eloop_ctx, void *eloop_data)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct sta_info *sta = eloop_data;
+ int ret;
+
+ if (sae_check_big_sync(sta))
+ return;
+ sta->sae->sync++;
+
+ switch (sta->sae->state) {
+ case SAE_COMMITTED:
+ ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0);
+ eloop_register_timeout(0, dot11RSNASAERetransPeriod * 1000,
+ auth_sae_retransmit_timer, hapd, sta);
+ break;
+ case SAE_CONFIRMED:
+ ret = auth_sae_send_confirm(hapd, sta, hapd->own_addr);
+ eloop_register_timeout(0, dot11RSNASAERetransPeriod * 1000,
+ auth_sae_retransmit_timer, hapd, sta);
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+
+ if (ret != WLAN_STATUS_SUCCESS)
+ wpa_printf(MSG_INFO, "SAE: Failed to retransmit: ret=%d", ret);
+}
+
+
+void sae_clear_retransmit_timer(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta);
+}
+
+
+static void sae_set_retransmit_timer(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ if (!(hapd->conf->mesh & MESH_ENABLED))
+ return;
+
+ eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta);
+ eloop_register_timeout(0, dot11RSNASAERetransPeriod * 1000,
+ auth_sae_retransmit_timer, hapd, sta);
+}
+
+
+static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *bssid, u8 auth_transaction)
+{
+ int ret;
+
+ if (auth_transaction != 1 && auth_transaction != 2)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+ switch (sta->sae->state) {
+ case SAE_NOTHING:
+ if (auth_transaction == 1) {
+ ret = auth_sae_send_commit(hapd, sta, bssid, 1);
+ if (ret)
+ return ret;
+ sta->sae->state = SAE_COMMITTED;
+
+ if (sae_process_commit(sta->sae) < 0)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+ /*
+ * In mesh case, both Commit and Confirm can be sent
+ * immediately. In infrastructure BSS, only a single
+ * Authentication frame (Commit) is expected from the AP
+ * here and the second one (Confirm) will be sent once
+ * the STA has sent its second Authentication frame
+ * (Confirm).
+ */
+ if (hapd->conf->mesh & MESH_ENABLED) {
+ /*
+ * Send both Commit and Confirm immediately
+ * based on SAE finite state machine
+ * Nothing -> Confirm transition.
+ */
+ ret = auth_sae_send_confirm(hapd, sta, bssid);
+ if (ret)
+ return ret;
+ sta->sae->state = SAE_CONFIRMED;
+ } else {
+ /*
+ * For infrastructure BSS, send only the Commit
+ * message now to get alternating sequence of
+ * Authentication frames between the AP and STA.
+ * Confirm will be sent in
+ * Commited -> Confirmed/Accepted transition
+ * when receiving Confirm from STA.
+ */
+ }
+ sta->sae->sync = 0;
+ sae_set_retransmit_timer(hapd, sta);
+ } else {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "SAE confirm before commit");
+ }
+ break;
+ case SAE_COMMITTED:
+ sae_clear_retransmit_timer(hapd, sta);
+ if (auth_transaction == 1) {
+ if (sae_process_commit(sta->sae) < 0)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+ ret = auth_sae_send_confirm(hapd, sta, bssid);
+ if (ret)
+ return ret;
+ sta->sae->state = SAE_CONFIRMED;
+ sta->sae->sync = 0;
+ sae_set_retransmit_timer(hapd, sta);
+ } else if (hapd->conf->mesh & MESH_ENABLED) {
+ /*
+ * In mesh case, follow SAE finite state machine and
+ * send Commit now, if sync count allows.
+ */
+ if (sae_check_big_sync(sta))
+ return WLAN_STATUS_SUCCESS;
+ sta->sae->sync++;
+
+ ret = auth_sae_send_commit(hapd, sta, bssid, 1);
+ if (ret)
+ return ret;
+
+ sae_set_retransmit_timer(hapd, sta);
+ } else {
+ /*
+ * For instructure BSS, send the postponed Confirm from
+ * Nothing -> Confirmed transition that was reduced to
+ * Nothing -> Committed above.
+ */
+ ret = auth_sae_send_confirm(hapd, sta, bssid);
+ if (ret)
+ return ret;
+
+ sta->sae->state = SAE_CONFIRMED;
+
+ /*
+ * Since this was triggered on Confirm RX, run another
+ * step to get to Accepted without waiting for
+ * additional events.
+ */
+ return sae_sm_step(hapd, sta, bssid, auth_transaction);
+ }
+ break;
+ case SAE_CONFIRMED:
+ sae_clear_retransmit_timer(hapd, sta);
+ if (auth_transaction == 1) {
+ if (sae_check_big_sync(sta))
+ return WLAN_STATUS_SUCCESS;
+ sta->sae->sync++;
+
+ ret = auth_sae_send_commit(hapd, sta, bssid, 1);
+ if (ret)
+ return ret;
+
+ if (sae_process_commit(sta->sae) < 0)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+ ret = auth_sae_send_confirm(hapd, sta, bssid);
+ if (ret)
+ return ret;
+
+ sae_set_retransmit_timer(hapd, sta);
+ } else {
+ sta->flags |= WLAN_STA_AUTH;
+ sta->auth_alg = WLAN_AUTH_SAE;
+ mlme_authenticate_indication(hapd, sta);
+ wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
+ sta->sae->state = SAE_ACCEPTED;
+ wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
+ sta->sae->pmk);
+ }
+ break;
+ case SAE_ACCEPTED:
+ if (auth_transaction == 1) {
+ wpa_printf(MSG_DEBUG, "SAE: remove the STA (" MACSTR
+ ") doing reauthentication",
+ MAC2STR(sta->addr));
+ ap_free_sta(hapd, sta);
+ } else {
+ if (sae_check_big_sync(sta))
+ return WLAN_STATUS_SUCCESS;
+ sta->sae->sync++;
+
+ ret = auth_sae_send_confirm(hapd, sta, bssid);
+ sae_clear_temp_data(sta->sae);
+ if (ret)
+ return ret;
+ }
+ break;
+ default:
+ wpa_printf(MSG_ERROR, "SAE: invalid state %d",
+ sta->sae->state);
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+ return WLAN_STATUS_SUCCESS;
+}
+
+
static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
const struct ieee80211_mgmt *mgmt, size_t len,
- u8 auth_transaction)
+ u16 auth_transaction, u16 status_code)
{
u16 resp = WLAN_STATUS_SUCCESS;
struct wpabuf *data = NULL;
if (!sta->sae) {
- if (auth_transaction != 1)
+ if (auth_transaction != 1 || status_code != WLAN_STATUS_SUCCESS)
return;
sta->sae = os_zalloc(sizeof(*sta->sae));
if (sta->sae == NULL)
return;
sta->sae->state = SAE_NOTHING;
+ sta->sae->sync = 0;
}
if (auth_transaction == 1) {
- const u8 *token = NULL;
+ const u8 *token = NULL, *pos, *end;
size_t token_len = 0;
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
- "start SAE authentication (RX commit)");
+ "start SAE authentication (RX commit, status=%u)",
+ status_code);
+
+ if ((hapd->conf->mesh & MESH_ENABLED) &&
+ status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ &&
+ sta->sae->tmp) {
+ pos = mgmt->u.auth.variable;
+ end = ((const u8 *) mgmt) + len;
+ if (pos + sizeof(le16) > end) {
+ wpa_printf(MSG_ERROR,
+ "SAE: Too short anti-clogging token request");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto reply;
+ }
+ resp = sae_group_allowed(sta->sae,
+ hapd->conf->sae_groups,
+ WPA_GET_LE16(pos));
+ if (resp != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_ERROR,
+ "SAE: Invalid group in anti-clogging token request");
+ goto reply;
+ }
+ pos += sizeof(le16);
+
+ wpabuf_free(sta->sae->tmp->anti_clogging_token);
+ sta->sae->tmp->anti_clogging_token =
+ wpabuf_alloc_copy(pos, end - pos);
+ if (sta->sae->tmp->anti_clogging_token == NULL) {
+ wpa_printf(MSG_ERROR,
+ "SAE: Failed to alloc for anti-clogging token");
+ return;
+ }
+
+ /*
+ * IEEE Std 802.11-2012, 11.3.8.6.4: If the Status code
+ * is 76, a new Commit Message shall be constructed
+ * with the Anti-Clogging Token from the received
+ * Authentication frame, and the commit-scalar and
+ * COMMIT-ELEMENT previously sent.
+ */
+ if (auth_sae_send_commit(hapd, sta, mgmt->bssid, 0)) {
+ wpa_printf(MSG_ERROR,
+ "SAE: Failed to send commit message");
+ return;
+ }
+ sta->sae->state = SAE_COMMITTED;
+ sta->sae->sync = 0;
+ sae_set_retransmit_timer(hapd, sta);
+ return;
+ }
+
+ if (status_code != WLAN_STATUS_SUCCESS)
+ return;
+
resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable,
((const u8 *) mgmt) + len -
mgmt->u.auth.variable, &token,
@@ -474,69 +792,91 @@
return;
}
- if (resp == WLAN_STATUS_SUCCESS) {
- if (!token && use_sae_anti_clogging(hapd)) {
- wpa_printf(MSG_DEBUG, "SAE: Request anti-"
- "clogging token from " MACSTR,
- MAC2STR(sta->addr));
- data = auth_build_token_req(hapd, sta->addr);
- resp = WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ;
- } else {
- data = auth_process_sae_commit(hapd, sta);
- if (data == NULL)
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- else
- sta->sae->state = SAE_COMMITTED;
- }
+ if (resp != WLAN_STATUS_SUCCESS)
+ goto reply;
+
+ if (!token && use_sae_anti_clogging(hapd)) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Request anti-clogging token from "
+ MACSTR, MAC2STR(sta->addr));
+ data = auth_build_token_req(hapd, sta->sae->group,
+ sta->addr);
+ resp = WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ;
+ if (hapd->conf->mesh & MESH_ENABLED)
+ sta->sae->state = SAE_NOTHING;
+ goto reply;
}
+
+ resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction);
} else if (auth_transaction == 2) {
- if (sta->sae->state != SAE_COMMITTED) {
- hostapd_logger(hapd, sta->addr,
- HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_DEBUG,
- "SAE confirm before commit");
- resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
- goto failed;
- }
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
- "SAE authentication (RX confirm)");
- if (sae_check_confirm(sta->sae, mgmt->u.auth.variable,
- ((u8 *) mgmt) + len -
- mgmt->u.auth.variable) < 0) {
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- } else {
- resp = WLAN_STATUS_SUCCESS;
- sta->flags |= WLAN_STA_AUTH;
- wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
- sta->auth_alg = WLAN_AUTH_SAE;
- mlme_authenticate_indication(hapd, sta);
-
- data = auth_build_sae_confirm(hapd, sta);
- if (data == NULL)
+ "SAE authentication (RX confirm, status=%u)",
+ status_code);
+ if (status_code != WLAN_STATUS_SUCCESS)
+ return;
+ if (sta->sae->state >= SAE_CONFIRMED ||
+ !(hapd->conf->mesh & MESH_ENABLED)) {
+ if (sae_check_confirm(sta->sae, mgmt->u.auth.variable,
+ ((u8 *) mgmt) + len -
+ mgmt->u.auth.variable) < 0) {
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- else {
- sta->sae->state = SAE_ACCEPTED;
- sae_clear_temp_data(sta->sae);
+ goto reply;
}
}
+ resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction);
} else {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
- "unexpected SAE authentication transaction %u",
- auth_transaction);
+ "unexpected SAE authentication transaction %u (status=%u)",
+ auth_transaction, status_code);
+ if (status_code != WLAN_STATUS_SUCCESS)
+ return;
resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
}
-failed:
- sta->auth_alg = WLAN_AUTH_SAE;
-
- send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
- auth_transaction, resp,
- data ? wpabuf_head(data) : (u8 *) "",
- data ? wpabuf_len(data) : 0);
+reply:
+ if (resp != WLAN_STATUS_SUCCESS) {
+ send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
+ auth_transaction, resp,
+ data ? wpabuf_head(data) : (u8 *) "",
+ data ? wpabuf_len(data) : 0);
+ }
wpabuf_free(data);
}
+
+
+/**
+ * auth_sae_init_committed - Send COMMIT and start SAE in committed state
+ * @hapd: BSS data for the device initiating the authentication
+ * @sta: the peer to which commit authentication frame is sent
+ *
+ * This function implements Init event handling (IEEE Std 802.11-2012,
+ * 11.3.8.6.3) in which initial COMMIT message is sent. Prior to calling, the
+ * sta->sae structure should be initialized appropriately via a call to
+ * sae_prepare_commit().
+ */
+int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ int ret;
+
+ if (!sta->sae || !sta->sae->tmp)
+ return -1;
+
+ if (sta->sae->state != SAE_NOTHING)
+ return -1;
+
+ ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0);
+ if (ret)
+ return -1;
+
+ sta->sae->state = SAE_COMMITTED;
+ sta->sae->sync = 0;
+ sae_set_retransmit_timer(hapd, sta);
+
+ return 0;
+}
+
#endif /* CONFIG_SAE */
@@ -556,6 +896,7 @@
size_t resp_ies_len = 0;
char *identity = NULL;
char *radius_cui = NULL;
+ u16 seq_ctrl;
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
@@ -577,6 +918,7 @@
auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
status_code = le_to_host16(mgmt->u.auth.status_code);
fc = le_to_host16(mgmt->frame_control);
+ seq_ctrl = le_to_host16(mgmt->seq_ctrl);
if (len >= IEEE80211_HDRLEN + sizeof(mgmt->u.auth) +
2 + WLAN_AUTH_CHALLENGE_LEN &&
@@ -585,10 +927,12 @@
challenge = &mgmt->u.auth.variable[2];
wpa_printf(MSG_DEBUG, "authentication: STA=" MACSTR " auth_alg=%d "
- "auth_transaction=%d status_code=%d wep=%d%s",
+ "auth_transaction=%d status_code=%d wep=%d%s "
+ "seq_ctrl=0x%x%s",
MAC2STR(mgmt->sa), auth_alg, auth_transaction,
status_code, !!(fc & WLAN_FC_ISWEP),
- challenge ? " challenge" : "");
+ challenge ? " challenge" : "",
+ seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
if (hapd->tkip_countermeasures) {
resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
@@ -649,11 +993,46 @@
return;
}
- sta = ap_sta_add(hapd, mgmt->sa);
- if (!sta) {
- resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
- goto fail;
+ sta = ap_get_sta(hapd, mgmt->sa);
+ if (sta) {
+ if ((fc & WLAN_FC_RETRY) &&
+ sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
+ sta->last_seq_ctrl == seq_ctrl &&
+ sta->last_subtype == WLAN_FC_STYPE_AUTH) {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "Drop repeated authentication frame seq_ctrl=0x%x",
+ seq_ctrl);
+ return;
+ }
+ } else {
+#ifdef CONFIG_MESH
+ if (hapd->conf->mesh & MESH_ENABLED) {
+ /* if the mesh peer is not available, we don't do auth.
+ */
+ wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR
+ " not yet known - drop Authentiation frame",
+ MAC2STR(mgmt->sa));
+ /*
+ * Save a copy of the frame so that it can be processed
+ * if a new peer entry is added shortly after this.
+ */
+ wpabuf_free(hapd->mesh_pending_auth);
+ hapd->mesh_pending_auth = wpabuf_alloc_copy(mgmt, len);
+ os_get_reltime(&hapd->mesh_pending_auth_time);
+ return;
+ }
+#endif /* CONFIG_MESH */
+
+ sta = ap_sta_add(hapd, mgmt->sa);
+ if (!sta) {
+ resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+ goto fail;
+ }
}
+ sta->last_seq_ctrl = seq_ctrl;
+ sta->last_subtype = WLAN_FC_STYPE_AUTH;
if (vlan_id > 0) {
if (!hostapd_vlan_id_valid(hapd->conf->vlan, vlan_id)) {
@@ -737,7 +1116,23 @@
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_SAE
case WLAN_AUTH_SAE:
- handle_auth_sae(hapd, sta, mgmt, len, auth_transaction);
+#ifdef CONFIG_MESH
+ if (status_code == WLAN_STATUS_SUCCESS &&
+ hapd->conf->mesh & MESH_ENABLED) {
+ if (sta->wpa_sm == NULL)
+ sta->wpa_sm =
+ wpa_auth_sta_init(hapd->wpa_auth,
+ sta->addr, NULL);
+ if (sta->wpa_sm == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Failed to initialize WPA state machine");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ }
+#endif /* CONFIG_MESH */
+ handle_auth_sae(hapd, sta, mgmt, len, auth_transaction,
+ status_code);
return;
#endif /* CONFIG_SAE */
}
@@ -932,6 +1327,13 @@
"mandatory VHT PHY - reject association");
return WLAN_STATUS_ASSOC_DENIED_NO_VHT;
}
+
+ if (hapd->conf->vendor_vht && !elems.vht_capabilities) {
+ resp = copy_sta_vendor_vht(hapd, sta, elems.vendor_vht,
+ elems.vendor_vht_len);
+ if (resp != WLAN_STATUS_SUCCESS)
+ return resp;
+ }
#endif /* CONFIG_IEEE80211AC */
#ifdef CONFIG_P2P
@@ -1072,9 +1474,21 @@
#ifdef CONFIG_SAE
if (wpa_auth_uses_sae(sta->wpa_sm) &&
- sta->auth_alg != WLAN_AUTH_SAE &&
- !(sta->auth_alg == WLAN_AUTH_FT &&
- wpa_auth_uses_ft_sae(sta->wpa_sm))) {
+ sta->auth_alg == WLAN_AUTH_OPEN) {
+ struct rsn_pmksa_cache_entry *sa;
+ sa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
+ if (!sa || sa->akmp != WPA_KEY_MGMT_SAE) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: No PMKSA cache entry found for "
+ MACSTR, MAC2STR(sta->addr));
+ return WLAN_STATUS_INVALID_PMKID;
+ }
+ wpa_printf(MSG_DEBUG, "SAE: " MACSTR
+ " using PMKSA caching", MAC2STR(sta->addr));
+ } else if (wpa_auth_uses_sae(sta->wpa_sm) &&
+ sta->auth_alg != WLAN_AUTH_SAE &&
+ !(sta->auth_alg == WLAN_AUTH_FT &&
+ wpa_auth_uses_ft_sae(sta->wpa_sm))) {
wpa_printf(MSG_DEBUG, "SAE: " MACSTR " tried to use "
"SAE AKM after non-SAE auth_alg %u",
MAC2STR(sta->addr), sta->auth_alg);
@@ -1209,8 +1623,10 @@
#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
- p = hostapd_eid_vht_capabilities(hapd, p);
- p = hostapd_eid_vht_operation(hapd, p);
+ if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
+ p = hostapd_eid_vht_capabilities(hapd, p);
+ p = hostapd_eid_vht_operation(hapd, p);
+ }
#endif /* CONFIG_IEEE80211AC */
p = hostapd_eid_ext_capab(hapd, p);
@@ -1218,6 +1634,11 @@
if (sta->qos_map_enabled)
p = hostapd_eid_qos_map_set(hapd, p);
+#ifdef CONFIG_IEEE80211AC
+ if (hapd->conf->vendor_vht && (sta->flags & WLAN_STA_VENDOR_VHT))
+ p = hostapd_eid_vendor_vht(hapd, p);
+#endif /* CONFIG_IEEE80211AC */
+
if (sta->flags & WLAN_STA_WMM)
p = hostapd_eid_wmm(hapd, p);
@@ -1275,7 +1696,7 @@
const struct ieee80211_mgmt *mgmt, size_t len,
int reassoc)
{
- u16 capab_info, listen_interval;
+ u16 capab_info, listen_interval, seq_ctrl, fc;
u16 resp = WLAN_STATUS_SUCCESS;
const u8 *pos;
int left, i;
@@ -1308,15 +1729,19 @@
}
#endif /* CONFIG_TESTING_OPTIONS */
+ fc = le_to_host16(mgmt->frame_control);
+ seq_ctrl = le_to_host16(mgmt->seq_ctrl);
+
if (reassoc) {
capab_info = le_to_host16(mgmt->u.reassoc_req.capab_info);
listen_interval = le_to_host16(
mgmt->u.reassoc_req.listen_interval);
wpa_printf(MSG_DEBUG, "reassociation request: STA=" MACSTR
" capab_info=0x%02x listen_interval=%d current_ap="
- MACSTR,
+ MACSTR " seq_ctrl=0x%x%s",
MAC2STR(mgmt->sa), capab_info, listen_interval,
- MAC2STR(mgmt->u.reassoc_req.current_ap));
+ MAC2STR(mgmt->u.reassoc_req.current_ap),
+ seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req));
pos = mgmt->u.reassoc_req.variable;
} else {
@@ -1324,8 +1749,10 @@
listen_interval = le_to_host16(
mgmt->u.assoc_req.listen_interval);
wpa_printf(MSG_DEBUG, "association request: STA=" MACSTR
- " capab_info=0x%02x listen_interval=%d",
- MAC2STR(mgmt->sa), capab_info, listen_interval);
+ " capab_info=0x%02x listen_interval=%d "
+ "seq_ctrl=0x%x%s",
+ MAC2STR(mgmt->sa), capab_info, listen_interval,
+ seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req));
pos = mgmt->u.assoc_req.variable;
}
@@ -1351,6 +1778,21 @@
return;
}
+ if ((fc & WLAN_FC_RETRY) &&
+ sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
+ sta->last_seq_ctrl == seq_ctrl &&
+ sta->last_subtype == reassoc ? WLAN_FC_STYPE_REASSOC_REQ :
+ WLAN_FC_STYPE_ASSOC_REQ) {
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "Drop repeated association frame seq_ctrl=0x%x",
+ seq_ctrl);
+ return;
+ }
+ sta->last_seq_ctrl = seq_ctrl;
+ sta->last_subtype = reassoc ? WLAN_FC_STYPE_REASSOC_REQ :
+ WLAN_FC_STYPE_ASSOC_REQ;
+
if (hapd->tkip_countermeasures) {
resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
goto fail;
@@ -1476,6 +1918,7 @@
}
ap_sta_set_authorized(hapd, sta, 0);
+ sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
@@ -1486,6 +1929,9 @@
* authenticated. */
accounting_sta_stop(hapd, sta);
ieee802_1x_free_station(sta);
+ if (sta->ipaddr)
+ hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
+ ap_sta_ip6addr_del(hapd, sta);
hostapd_drv_sta_remove(hapd, sta->addr);
if (sta->timeout_next == STA_NULLFUNC ||
@@ -1525,6 +1971,7 @@
}
ap_sta_set_authorized(hapd, sta, 0);
+ sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
WLAN_STA_ASSOC_REQ_OK);
wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
@@ -1624,6 +2071,26 @@
}
#endif /* CONFIG_IEEE80211W */
+ if (sta) {
+ u16 fc = le_to_host16(mgmt->frame_control);
+ u16 seq_ctrl = le_to_host16(mgmt->seq_ctrl);
+
+ if ((fc & WLAN_FC_RETRY) &&
+ sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
+ sta->last_seq_ctrl == seq_ctrl &&
+ sta->last_subtype == WLAN_FC_STYPE_ACTION) {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "Drop repeated action frame seq_ctrl=0x%x",
+ seq_ctrl);
+ return 1;
+ }
+
+ sta->last_seq_ctrl = seq_ctrl;
+ sta->last_subtype = WLAN_FC_STYPE_ACTION;
+ }
+
switch (mgmt->u.action.category) {
#ifdef CONFIG_IEEE80211R
case WLAN_ACTION_FT:
@@ -1758,6 +2225,9 @@
!((hapd->conf->p2p & P2P_GROUP_OWNER) &&
stype == WLAN_FC_STYPE_ACTION) &&
#endif /* CONFIG_P2P */
+#ifdef CONFIG_MESH
+ !(hapd->conf->mesh & MESH_ENABLED) &&
+#endif /* CONFIG_MESH */
os_memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0) {
wpa_printf(MSG_INFO, "MGMT: BSSID=" MACSTR " not our address",
MAC2STR(mgmt->bssid));
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index cf0d3f2..41c27d9 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -51,6 +51,7 @@
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_vht_operation(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_vendor_vht(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);
@@ -62,6 +63,9 @@
struct ieee80211_vht_capabilities *neg_vht_cap);
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ht_capab, size_t ht_capab_len);
+u16 copy_sta_vendor_vht(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *ie, size_t len);
+
void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta);
void ht40_intolerant_add(struct hostapd_iface *iface, struct sta_info *sta);
void ht40_intolerant_remove(struct hostapd_iface *iface, struct sta_info *sta);
@@ -89,4 +93,15 @@
void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr);
u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid);
+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);
+#else /* CONFIG_SAE */
+static inline void sae_clear_retransmit_timer(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+}
+#endif /* CONFIG_SAE */
+
#endif /* IEEE802_11_H */
diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c
index fe87883..3f299f3 100644
--- a/src/ap/ieee802_11_ht.c
+++ b/src/ap/ieee802_11_ht.c
@@ -211,7 +211,8 @@
struct ieee80211_2040_intol_chan_report *ic_report;
int is_ht_allowed = 1;
int i;
- const u8 *data = ((const u8 *) mgmt) + 1;
+ const u8 *start = (const u8 *) mgmt;
+ const u8 *data = start + IEEE80211_HDRLEN + 2;
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "hostapd_public_action - action=%d",
@@ -220,14 +221,22 @@
if (!(iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
return;
- if (len < IEEE80211_HDRLEN + 1)
+ if (len < IEEE80211_HDRLEN + 2 + sizeof(*bc_ie))
return;
- data++;
- bc_ie = (struct ieee80211_2040_bss_coex_ie *) &data[0];
- ic_report = (struct ieee80211_2040_intol_chan_report *)
- (&data[0] + sizeof(*bc_ie));
+ bc_ie = (struct ieee80211_2040_bss_coex_ie *) data;
+ if (bc_ie->element_id != WLAN_EID_20_40_BSS_COEXISTENCE ||
+ bc_ie->length < 1) {
+ wpa_printf(MSG_DEBUG, "Unexpected IE (%u,%u) in coex report",
+ bc_ie->element_id, bc_ie->length);
+ return;
+ }
+ if (len < IEEE80211_HDRLEN + 2 + 2 + bc_ie->length)
+ return;
+ data += 2 + bc_ie->length;
+ wpa_printf(MSG_DEBUG, "20/40 BSS Coexistence Information field: 0x%x",
+ bc_ie->coex_param);
if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ) {
hostapd_logger(hapd, mgmt->sa,
HOSTAPD_MODULE_IEEE80211,
@@ -244,22 +253,34 @@
is_ht_allowed = 0;
}
- if (ic_report &&
- (ic_report->element_id == WLAN_EID_20_40_BSS_INTOLERANT)) {
+ if (start + len - data >= 3 &&
+ data[0] == WLAN_EID_20_40_BSS_INTOLERANT && data[1] >= 1) {
+ u8 ielen = data[1];
+
+ if (ielen > start + len - data - 2)
+ return;
+ ic_report = (struct ieee80211_2040_intol_chan_report *) data;
+ wpa_printf(MSG_DEBUG,
+ "20/40 BSS Intolerant Channel Report: Operating Class %u",
+ ic_report->op_class);
+
/* Go through the channel report to find any BSS there in the
* affected channel range */
- for (i = 0; i < ic_report->length - 1; i++) {
- if (is_40_allowed(iface, ic_report->variable[i]))
+ for (i = 0; i < ielen - 1; i++) {
+ u8 chan = ic_report->variable[i];
+
+ if (is_40_allowed(iface, chan))
continue;
hostapd_logger(hapd, mgmt->sa,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"20_40_INTOLERANT channel %d reported",
- ic_report->variable[i]);
+ chan);
is_ht_allowed = 0;
- break;
}
}
+ wpa_printf(MSG_DEBUG, "is_ht_allowed=%d num_sta_ht40_intolerant=%d",
+ is_ht_allowed, iface->num_sta_ht40_intolerant);
if (!is_ht_allowed &&
(iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX)) {
@@ -279,6 +300,9 @@
NULL);
eloop_register_timeout(delay_time, 0, ap_ht2040_timeout,
hapd->iface, NULL);
+ wpa_printf(MSG_DEBUG,
+ "Reschedule HT 20/40 timeout to occur in %u seconds",
+ delay_time);
}
}
}
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index 12403f9..d462ac8 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -174,6 +174,8 @@
*pos |= 0x01; /* Bit 0 - Coexistence management */
break;
case 1: /* Bits 8-15 */
+ if (hapd->conf->proxy_arp)
+ *pos |= 0x10; /* Bit 12 - Proxy ARP */
break;
case 2: /* Bits 16-23 */
if (hapd->conf->wnm_sleep_mode)
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index 437cf50..159693f 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -22,12 +22,25 @@
u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid)
{
struct ieee80211_vht_capabilities *cap;
+ struct hostapd_hw_modes *mode = hapd->iface->current_mode;
u8 *pos = eid;
- if (!hapd->iconf->ieee80211ac || !hapd->iface->current_mode ||
- hapd->conf->disable_11ac)
+ if (!mode)
return eid;
+ if (mode->mode == HOSTAPD_MODE_IEEE80211G && hapd->conf->vendor_vht &&
+ mode->vht_capab == 0 && hapd->iface->hw_features) {
+ int i;
+
+ for (i = 0; i < hapd->iface->num_hw_features; i++) {
+ if (hapd->iface->hw_features[i].mode ==
+ HOSTAPD_MODE_IEEE80211A) {
+ mode = &hapd->iface->hw_features[i];
+ break;
+ }
+ }
+ }
+
*pos++ = WLAN_EID_VHT_CAP;
*pos++ = sizeof(*cap);
@@ -37,8 +50,7 @@
hapd->iface->conf->vht_capab);
/* Supported MCS set comes from hw */
- os_memcpy(&cap->vht_supported_mcs_set,
- hapd->iface->current_mode->vht_mcs_set, 8);
+ os_memcpy(&cap->vht_supported_mcs_set, mode->vht_mcs_set, 8);
pos += sizeof(*cap);
@@ -51,9 +63,6 @@
struct ieee80211_vht_operation *oper;
u8 *pos = eid;
- if (!hapd->iconf->ieee80211ac || hapd->conf->disable_11ac)
- return eid;
-
*pos++ = WLAN_EID_VHT_OPERATION;
*pos++ = sizeof(*oper);
@@ -109,6 +118,66 @@
}
+u16 copy_sta_vendor_vht(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *ie, size_t len)
+{
+ const u8 *vht_capab;
+ unsigned int vht_capab_len;
+
+ if (!ie || len < 5 + 2 + sizeof(struct ieee80211_vht_capabilities) ||
+ hapd->conf->disable_11ac)
+ goto no_capab;
+
+ /* The VHT Capabilities element embedded in vendor VHT */
+ vht_capab = ie + 5;
+ if (vht_capab[0] != WLAN_EID_VHT_CAP)
+ goto no_capab;
+ vht_capab_len = vht_capab[1];
+ if (vht_capab_len < sizeof(struct ieee80211_vht_capabilities) ||
+ (int) vht_capab_len > ie + len - vht_capab - 2)
+ goto no_capab;
+ vht_capab += 2;
+
+ if (sta->vht_capabilities == NULL) {
+ sta->vht_capabilities =
+ os_zalloc(sizeof(struct ieee80211_vht_capabilities));
+ if (sta->vht_capabilities == NULL)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ sta->flags |= WLAN_STA_VHT | WLAN_STA_VENDOR_VHT;
+ os_memcpy(sta->vht_capabilities, vht_capab,
+ sizeof(struct ieee80211_vht_capabilities));
+ return WLAN_STATUS_SUCCESS;
+
+no_capab:
+ sta->flags &= ~WLAN_STA_VENDOR_VHT;
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 *pos = eid;
+
+ if (!hapd->iface->current_mode)
+ return eid;
+
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = (5 + /* The Vendor OUI, type and subtype */
+ 2 + sizeof(struct ieee80211_vht_capabilities) +
+ 2 + sizeof(struct ieee80211_vht_operation));
+
+ 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_operation(hapd, pos);
+
+ return pos;
+}
+
+
u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *vht_oper_notif)
{
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 2d09b67..79dc0f9 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -66,6 +66,20 @@
if (wpa_auth_pairwise_set(sta->wpa_sm))
encrypt = 1;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->ext_eapol_frame_io) {
+ size_t hex_len = 2 * len + 1;
+ char *hex = os_malloc(hex_len);
+
+ if (hex) {
+ wpa_snprintf_hex(hex, hex_len, buf, len);
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ "EAPOL-TX " MACSTR " %s",
+ MAC2STR(sta->addr), hex);
+ os_free(hex);
+ }
+ } else
+#endif /* CONFIG_TESTING_OPTIONS */
if (sta->flags & WLAN_STA_PREAUTH) {
rsn_preauth_send(hapd, sta, buf, len);
} else {
@@ -282,9 +296,15 @@
{
const u8 *identity;
size_t identity_len;
+ const struct eap_hdr *hdr = (const struct eap_hdr *) eap;
if (len <= sizeof(struct eap_hdr) ||
- eap[sizeof(struct eap_hdr)] != EAP_TYPE_IDENTITY)
+ (hdr->code == EAP_CODE_RESPONSE &&
+ eap[sizeof(struct eap_hdr)] != EAP_TYPE_IDENTITY) ||
+ (hdr->code == EAP_CODE_INITIATE &&
+ eap[sizeof(struct eap_hdr)] != EAP_ERP_TYPE_REAUTH) ||
+ (hdr->code != EAP_CODE_RESPONSE &&
+ hdr->code != EAP_CODE_INITIATE))
return;
identity = eap_get_identity(sm->eap, &identity_len);
@@ -697,6 +717,39 @@
}
+static void handle_eap_initiate(struct hostapd_data *hapd,
+ struct sta_info *sta, struct eap_hdr *eap,
+ size_t len)
+{
+#ifdef CONFIG_ERP
+ u8 type, *data;
+ struct eapol_state_machine *sm = sta->eapol_sm;
+
+ if (sm == NULL)
+ return;
+
+ if (len < sizeof(*eap) + 1) {
+ wpa_printf(MSG_INFO,
+ "handle_eap_initiate: too short response data");
+ return;
+ }
+
+ data = (u8 *) (eap + 1);
+ type = data[0];
+
+ hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X,
+ HOSTAPD_LEVEL_DEBUG, "received EAP packet (code=%d "
+ "id=%d len=%d) from STA: EAP Initiate type %u",
+ eap->code, eap->identifier, be_to_host16(eap->length),
+ type);
+
+ wpabuf_free(sm->eap_if->eapRespData);
+ sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len);
+ sm->eapolEap = TRUE;
+#endif /* CONFIG_ERP */
+}
+
+
/* Process incoming EAP packet from Supplicant */
static void handle_eap(struct hostapd_data *hapd, struct sta_info *sta,
u8 *buf, size_t len)
@@ -740,6 +793,13 @@
case EAP_CODE_FAILURE:
wpa_printf(MSG_DEBUG, " (failure)");
return;
+ case EAP_CODE_INITIATE:
+ wpa_printf(MSG_DEBUG, " (initiate)");
+ handle_eap_initiate(hapd, sta, eap, eap_len);
+ break;
+ case EAP_CODE_FINISH:
+ wpa_printf(MSG_DEBUG, " (finish)");
+ break;
default:
wpa_printf(MSG_DEBUG, " (unknown code)");
return;
@@ -961,8 +1021,9 @@
int key_mgmt;
#ifdef CONFIG_WPS
- if (hapd->conf->wps_state && hapd->conf->wpa &&
- (sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) {
+ if (hapd->conf->wps_state &&
+ ((hapd->conf->wpa && (sta->flags & WLAN_STA_MAYBE_WPS)) ||
+ (sta->flags & WLAN_STA_WPS))) {
/*
* Need to enable IEEE 802.1X/EAPOL state machines for possible
* WPS handshake even if IEEE 802.1X/EAPOL is not used for
@@ -1150,15 +1211,11 @@
if (eap_type >= 0)
sm->eap_type_authsrv = eap_type;
os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)",
- eap_type >= 0 ? eap_server_get_name(0, eap_type) :
- "??",
- eap_type);
+ eap_server_get_name(0, eap_type), eap_type);
break;
case EAP_CODE_RESPONSE:
os_snprintf(buf, sizeof(buf), "EAP Response-%s (%d)",
- eap_type >= 0 ? eap_server_get_name(0, eap_type) :
- "??",
- eap_type);
+ eap_server_get_name(0, eap_type), eap_type);
break;
case EAP_CODE_SUCCESS:
os_strlcpy(buf, "EAP Success", sizeof(buf));
@@ -1214,6 +1271,11 @@
sm->eap_if->aaaEapKeyDataLen = len;
sm->eap_if->aaaEapKeyAvailable = TRUE;
}
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "MS-MPPE: 1x_get_keys, could not get keys: %p send: %p recv: %p",
+ keys, keys ? keys->send : NULL,
+ keys ? keys->recv : NULL);
}
if (keys) {
@@ -1972,12 +2034,43 @@
}
+#ifdef CONFIG_ERP
+
+static struct eap_server_erp_key *
+ieee802_1x_erp_get_key(void *ctx, const char *keyname)
+{
+ struct hostapd_data *hapd = ctx;
+ struct eap_server_erp_key *erp;
+
+ dl_list_for_each(erp, &hapd->erp_keys, struct eap_server_erp_key,
+ list) {
+ if (os_strcmp(erp->keyname_nai, keyname) == 0)
+ return erp;
+ }
+
+ return NULL;
+}
+
+
+static int ieee802_1x_erp_add_key(void *ctx, struct eap_server_erp_key *erp)
+{
+ struct hostapd_data *hapd = ctx;
+
+ dl_list_add(&hapd->erp_keys, &erp->list);
+ return 0;
+}
+
+#endif /* CONFIG_ERP */
+
+
int ieee802_1x_init(struct hostapd_data *hapd)
{
int i;
struct eapol_auth_config conf;
struct eapol_auth_cb cb;
+ dl_list_init(&hapd->erp_keys);
+
os_memset(&conf, 0, sizeof(conf));
conf.ctx = hapd;
conf.eap_reauth_period = hapd->conf->eap_reauth_period;
@@ -1989,6 +2082,9 @@
conf.eap_sim_db_priv = hapd->eap_sim_db_priv;
conf.eap_req_id_text = hapd->conf->eap_req_id_text;
conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len;
+ conf.erp_send_reauth_start = hapd->conf->erp_send_reauth_start;
+ conf.erp_domain = hapd->conf->erp_domain;
+ conf.erp = hapd->conf->eap_server_erp;
conf.pac_opaque_encr_key = hapd->conf->pac_opaque_encr_key;
conf.eap_fast_a_id = hapd->conf->eap_fast_a_id;
conf.eap_fast_a_id_len = hapd->conf->eap_fast_a_id_len;
@@ -2021,6 +2117,10 @@
cb.abort_auth = _ieee802_1x_abort_auth;
cb.tx_key = _ieee802_1x_tx_key;
cb.eapol_event = ieee802_1x_eapol_event;
+#ifdef CONFIG_ERP
+ cb.erp_get_key = ieee802_1x_erp_get_key;
+ cb.erp_add_key = ieee802_1x_erp_add_key;
+#endif /* CONFIG_ERP */
hapd->eapol_auth = eapol_auth_init(&conf, &cb);
if (hapd->eapol_auth == NULL)
@@ -2052,6 +2152,18 @@
}
+void ieee802_1x_erp_flush(struct hostapd_data *hapd)
+{
+ struct eap_server_erp_key *erp;
+
+ while ((erp = dl_list_first(&hapd->erp_keys, struct eap_server_erp_key,
+ list)) != NULL) {
+ dl_list_del(&erp->list);
+ bin_clear_free(erp, sizeof(*erp));
+ }
+}
+
+
void ieee802_1x_deinit(struct hostapd_data *hapd)
{
eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL);
@@ -2062,6 +2174,8 @@
eapol_auth_deinit(hapd->eapol_auth);
hapd->eapol_auth = NULL;
+
+ ieee802_1x_erp_flush(hapd);
}
@@ -2252,7 +2366,7 @@
sta->aid,
EAPOL_VERSION,
sm->initialize);
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -2280,7 +2394,7 @@
sm->reAuthPeriod,
bool_txt(sm->reAuthEnabled),
bool_txt(sm->keyTxEnabled));
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -2310,7 +2424,7 @@
sm->dot1xAuthEapLengthErrorFramesRx,
sm->dot1xAuthLastEapolFrameVersion,
MAC2STR(sm->addr));
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -2348,7 +2462,7 @@
sm->backendOtherRequestsToSupplicant,
sm->backendAuthSuccesses,
sm->backendAuthFails);
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -2370,20 +2484,28 @@
1 : 2,
(unsigned int) diff.sec,
sm->identity);
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
+ if (sm->acct_multi_session_id_hi) {
+ ret = os_snprintf(buf + len, buflen - len,
+ "authMultiSessionId=%08X+%08X\n",
+ sm->acct_multi_session_id_hi,
+ sm->acct_multi_session_id_lo);
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ }
+
name1 = eap_server_get_name(0, sm->eap_type_authsrv);
name2 = eap_server_get_name(0, sm->eap_type_supp);
ret = os_snprintf(buf + len, buflen - len,
"last_eap_type_as=%d (%s)\n"
"last_eap_type_sta=%d (%s)\n",
- sm->eap_type_authsrv,
- name1 ? name1 : "",
- sm->eap_type_supp,
- name2 ? name2 : "");
- if (ret < 0 || (size_t) ret >= buflen - len)
+ sm->eap_type_authsrv, name1,
+ sm->eap_type_supp, name2);
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
diff --git a/src/ap/ieee802_1x.h b/src/ap/ieee802_1x.h
index e1df940..de6e0e7 100644
--- a/src/ap/ieee802_1x.h
+++ b/src/ap/ieee802_1x.h
@@ -29,6 +29,7 @@
struct sta_info *sta, int authorized);
void ieee802_1x_dump_state(FILE *f, const char *prefix, struct sta_info *sta);
int ieee802_1x_init(struct hostapd_data *hapd);
+void ieee802_1x_erp_flush(struct hostapd_data *hapd);
void ieee802_1x_deinit(struct hostapd_data *hapd);
int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *buf, size_t len, int ack);
diff --git a/src/ap/ndisc_snoop.c b/src/ap/ndisc_snoop.c
new file mode 100644
index 0000000..b0d42dc
--- /dev/null
+++ b/src/ap/ndisc_snoop.c
@@ -0,0 +1,171 @@
+/*
+ * Neighbor Discovery snooping for Proxy ARP
+ * Copyright (c) 2014, 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 <netinet/ip6.h>
+#include <netinet/icmp6.h>
+
+#include "utils/common.h"
+#include "l2_packet/l2_packet.h"
+#include "hostapd.h"
+#include "sta_info.h"
+#include "ap_drv_ops.h"
+#include "list.h"
+#include "x_snoop.h"
+
+struct ip6addr {
+ struct in6_addr addr;
+ struct dl_list list;
+};
+
+struct icmpv6_ndmsg {
+ struct ip6_hdr ipv6h;
+ struct icmp6_hdr icmp6h;
+ struct in6_addr target_addr;
+ u8 opt_type;
+ u8 len;
+ u8 opt_lladdr[0];
+} STRUCT_PACKED;
+
+#define ROUTER_ADVERTISEMENT 134
+#define NEIGHBOR_SOLICITATION 135
+#define NEIGHBOR_ADVERTISEMENT 136
+#define SOURCE_LL_ADDR 1
+
+static int sta_ip6addr_add(struct sta_info *sta, struct in6_addr *addr)
+{
+ struct ip6addr *ip6addr;
+
+ ip6addr = os_zalloc(sizeof(*ip6addr));
+ if (!ip6addr)
+ return -1;
+
+ os_memcpy(&ip6addr->addr, addr, sizeof(*addr));
+
+ dl_list_add_tail(&sta->ip6addr, &ip6addr->list);
+
+ return 0;
+}
+
+
+void sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ struct ip6addr *ip6addr, *prev;
+
+ dl_list_for_each_safe(ip6addr, prev, &sta->ip6addr, struct ip6addr,
+ list) {
+ hostapd_drv_br_delete_ip_neigh(hapd, 6, (u8 *) &ip6addr->addr);
+ os_free(ip6addr);
+ }
+}
+
+
+static int sta_has_ip6addr(struct sta_info *sta, struct in6_addr *addr)
+{
+ struct ip6addr *ip6addr;
+
+ dl_list_for_each(ip6addr, &sta->ip6addr, struct ip6addr, list) {
+ if (ip6addr->addr.s6_addr32[0] == addr->s6_addr32[0] &&
+ ip6addr->addr.s6_addr32[1] == addr->s6_addr32[1] &&
+ ip6addr->addr.s6_addr32[2] == addr->s6_addr32[2] &&
+ ip6addr->addr.s6_addr32[3] == addr->s6_addr32[3])
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static void handle_ndisc(void *ctx, const u8 *src_addr, const u8 *buf,
+ size_t len)
+{
+ struct hostapd_data *hapd = ctx;
+ struct icmpv6_ndmsg *msg;
+ struct in6_addr *saddr;
+ struct sta_info *sta;
+ int res;
+ char addrtxt[INET6_ADDRSTRLEN + 1];
+
+ if (len < ETH_HLEN + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr))
+ return;
+ msg = (struct icmpv6_ndmsg *) &buf[ETH_HLEN];
+ switch (msg->icmp6h.icmp6_type) {
+ case NEIGHBOR_SOLICITATION:
+ if (len < ETH_HLEN + sizeof(*msg))
+ return;
+ if (msg->opt_type != SOURCE_LL_ADDR)
+ return;
+
+ saddr = &msg->ipv6h.ip6_src;
+ if (!(saddr->s6_addr32[0] == 0 && saddr->s6_addr32[1] == 0 &&
+ saddr->s6_addr32[2] == 0 && saddr->s6_addr32[3] == 0)) {
+ if (len < ETH_HLEN + sizeof(*msg) + ETH_ALEN)
+ return;
+ sta = ap_get_sta(hapd, msg->opt_lladdr);
+ if (!sta)
+ return;
+
+ if (sta_has_ip6addr(sta, saddr))
+ return;
+
+ if (inet_ntop(AF_INET6, saddr, addrtxt, sizeof(addrtxt))
+ == NULL)
+ addrtxt[0] = '\0';
+ wpa_printf(MSG_DEBUG, "ndisc_snoop: Learned new IPv6 address %s for "
+ MACSTR, addrtxt, MAC2STR(sta->addr));
+ hostapd_drv_br_delete_ip_neigh(hapd, 6, (u8 *) saddr);
+ res = hostapd_drv_br_add_ip_neigh(hapd, 6, (u8 *) saddr,
+ 128, sta->addr);
+ if (res) {
+ wpa_printf(MSG_ERROR,
+ "ndisc_snoop: Adding ip neigh failed: %d",
+ res);
+ return;
+ }
+
+ if (sta_ip6addr_add(sta, saddr))
+ return;
+ }
+ break;
+ case ROUTER_ADVERTISEMENT:
+ if (!hapd->conf->disable_dgaf)
+ return;
+ /* fall through */
+ case NEIGHBOR_ADVERTISEMENT:
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (!(sta->flags & WLAN_STA_AUTHORIZED))
+ continue;
+ x_snoop_mcast_to_ucast_convert_send(hapd, sta,
+ (u8 *) buf, len);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+
+int ndisc_snoop_init(struct hostapd_data *hapd)
+{
+ hapd->sock_ndisc = x_snoop_get_l2_packet(hapd, handle_ndisc,
+ L2_PACKET_FILTER_NDISC);
+ if (hapd->sock_ndisc == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "ndisc_snoop: Failed to initialize L2 packet processing for NDISC packets: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void ndisc_snoop_deinit(struct hostapd_data *hapd)
+{
+ l2_packet_deinit(hapd->sock_ndisc);
+}
diff --git a/src/ap/ndisc_snoop.h b/src/ap/ndisc_snoop.h
new file mode 100644
index 0000000..3cc9a55
--- /dev/null
+++ b/src/ap/ndisc_snoop.h
@@ -0,0 +1,36 @@
+/*
+ * Neighbor Discovery snooping for Proxy ARP
+ * Copyright (c) 2014, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef NDISC_SNOOP_H
+#define NDISC_SNOOP_H
+
+#if defined(CONFIG_PROXYARP) && defined(CONFIG_IPV6)
+
+int ndisc_snoop_init(struct hostapd_data *hapd);
+void ndisc_snoop_deinit(struct hostapd_data *hapd);
+void sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta);
+
+#else /* CONFIG_PROXYARP && CONFIG_IPV6 */
+
+static inline int ndisc_snoop_init(struct hostapd_data *hapd)
+{
+ return 0;
+}
+
+static inline void ndisc_snoop_deinit(struct hostapd_data *hapd)
+{
+}
+
+static inline void sta_ip6addr_del(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+}
+
+#endif /* CONFIG_PROXYARP && CONFIG_IPV6 */
+
+#endif /* NDISC_SNOOP_H */
diff --git a/src/ap/peerkey_auth.c b/src/ap/peerkey_auth.c
index 612babc..efc1d7e 100644
--- a/src/ap/peerkey_auth.c
+++ b/src/ap/peerkey_auth.c
@@ -79,15 +79,15 @@
void wpa_smk_m1(struct wpa_authenticator *wpa_auth,
- struct wpa_state_machine *sm, struct wpa_eapol_key *key)
+ struct wpa_state_machine *sm, struct wpa_eapol_key *key,
+ const u8 *key_data, size_t key_data_len)
{
struct wpa_eapol_ie_parse kde;
struct wpa_stsl_search search;
u8 *buf, *pos;
size_t buf_len;
- if (wpa_parse_kde_ies((const u8 *) (key + 1),
- WPA_GET_BE16(key->key_data_length), &kde) < 0) {
+ if (wpa_parse_kde_ies(key_data, key_data_len, &kde) < 0) {
wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M1");
return;
}
@@ -253,14 +253,14 @@
void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
- struct wpa_state_machine *sm, struct wpa_eapol_key *key)
+ struct wpa_state_machine *sm, struct wpa_eapol_key *key,
+ const u8 *key_data, size_t key_data_len)
{
struct wpa_eapol_ie_parse kde;
struct wpa_stsl_search search;
u8 smk[32], buf[ETH_ALEN + 8 + 2 * WPA_NONCE_LEN], *pos;
- if (wpa_parse_kde_ies((const u8 *) (key + 1),
- WPA_GET_BE16(key->key_data_length), &kde) < 0) {
+ if (wpa_parse_kde_ies(key_data, key_data_len, &kde) < 0) {
wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M3");
return;
}
@@ -324,15 +324,15 @@
void wpa_smk_error(struct wpa_authenticator *wpa_auth,
- struct wpa_state_machine *sm, struct wpa_eapol_key *key)
+ struct wpa_state_machine *sm,
+ const u8 *key_data, size_t key_data_len)
{
struct wpa_eapol_ie_parse kde;
struct wpa_stsl_search search;
struct rsn_error_kde error;
u16 mui, error_type;
- if (wpa_parse_kde_ies((const u8 *) (key + 1),
- WPA_GET_BE16(key->key_data_length), &kde) < 0) {
+ if (wpa_parse_kde_ies(key_data, key_data_len, &kde) < 0) {
wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error");
return;
}
diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c
index 9de4cff..877affe 100644
--- a/src/ap/pmksa_cache_auth.c
+++ b/src/ap/pmksa_cache_auth.c
@@ -1,6 +1,6 @@
/*
* hostapd - PMKSA cache for IEEE 802.11i RSN
- * Copyright (c) 2004-2008, 2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2008, 2012-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -12,6 +12,7 @@
#include "utils/eloop.h"
#include "eapol_auth/eapol_auth_sm.h"
#include "eapol_auth/eapol_auth_sm_i.h"
+#include "radius/radius_das.h"
#include "sta_info.h"
#include "ap_config.h"
#include "pmksa_cache_auth.h"
@@ -146,6 +147,9 @@
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;
}
@@ -183,6 +187,9 @@
eapol->eap_type_authsrv = entry->eap_type_authsrv;
((struct sta_info *) eapol->sta)->vlan_id = entry->vlan_id;
+
+ eapol->acct_multi_session_id_hi = entry->acct_multi_session_id_hi;
+ eapol->acct_multi_session_id_lo = entry->acct_multi_session_id_lo;
}
@@ -227,6 +234,8 @@
* @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)
+ * @kck: Key confirmation key or %NULL if not yet derived
+ * @kck_len: KCK length in bytes
* @aa: Authenticator address
* @spa: Supplicant address
* @session_timeout: Session timeout
@@ -242,8 +251,9 @@
struct rsn_pmksa_cache_entry *
pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
const u8 *pmk, size_t pmk_len,
- const u8 *aa, const u8 *spa, int session_timeout,
- struct eapol_state_machine *eapol, int akmp)
+ const u8 *kck, size_t kck_len,
+ const u8 *aa, const u8 *spa, int session_timeout,
+ struct eapol_state_machine *eapol, int akmp)
{
struct rsn_pmksa_cache_entry *entry, *pos;
struct os_reltime now;
@@ -251,13 +261,21 @@
if (pmk_len > PMK_LEN)
return NULL;
+ if (wpa_key_mgmt_suite_b(akmp) && !kck)
+ return NULL;
+
entry = os_zalloc(sizeof(*entry));
if (entry == NULL)
return NULL;
os_memcpy(entry->pmk, pmk, pmk_len);
entry->pmk_len = pmk_len;
- rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
- wpa_key_mgmt_sha256(akmp));
+ 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);
+ else
+ rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
+ wpa_key_mgmt_sha256(akmp));
os_get_reltime(&now);
entry->expiration = now.sec;
if (session_timeout > 0)
@@ -437,3 +455,74 @@
return pmksa;
}
+
+
+static int das_attr_match(struct rsn_pmksa_cache_entry *entry,
+ struct radius_das_attrs *attr)
+{
+ int match = 0;
+
+ if (attr->sta_addr) {
+ if (os_memcmp(attr->sta_addr, entry->spa, ETH_ALEN) != 0)
+ return 0;
+ match++;
+ }
+
+ if (attr->acct_multi_session_id) {
+ char buf[20];
+
+ if (attr->acct_multi_session_id_len != 17)
+ 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)
+ return 0;
+ match++;
+ }
+
+ if (attr->cui) {
+ if (!entry->cui ||
+ attr->cui_len != wpabuf_len(entry->cui) ||
+ os_memcmp(attr->cui, wpabuf_head(entry->cui),
+ attr->cui_len) != 0)
+ return 0;
+ match++;
+ }
+
+ if (attr->user_name) {
+ if (!entry->identity ||
+ attr->user_name_len != entry->identity_len ||
+ os_memcmp(attr->user_name, entry->identity,
+ attr->user_name_len) != 0)
+ return 0;
+ match++;
+ }
+
+ return match;
+}
+
+
+int pmksa_cache_auth_radius_das_disconnect(struct rsn_pmksa_cache *pmksa,
+ struct radius_das_attrs *attr)
+{
+ int found = 0;
+ struct rsn_pmksa_cache_entry *entry, *prev;
+
+ if (attr->acct_session_id)
+ return -1;
+
+ entry = pmksa->pmksa;
+ while (entry) {
+ if (das_attr_match(entry, attr)) {
+ found++;
+ prev = entry;
+ entry = entry->next;
+ pmksa_cache_free_entry(pmksa, prev);
+ continue;
+ }
+ entry = entry->next;
+ }
+
+ return found ? 0 : -1;
+}
diff --git a/src/ap/pmksa_cache_auth.h b/src/ap/pmksa_cache_auth.h
index aa90024..8b7be12 100644
--- a/src/ap/pmksa_cache_auth.h
+++ b/src/ap/pmksa_cache_auth.h
@@ -30,6 +30,9 @@
u8 eap_type_authsrv;
int vlan_id;
int opportunistic;
+
+ u32 acct_multi_session_id_hi;
+ u32 acct_multi_session_id_lo;
};
struct rsn_pmksa_cache;
@@ -47,6 +50,7 @@
struct rsn_pmksa_cache_entry *
pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
const u8 *pmk, size_t pmk_len,
+ const u8 *kck, size_t kck_len,
const u8 *aa, const u8 *spa, int session_timeout,
struct eapol_state_machine *eapol, int akmp);
struct rsn_pmksa_cache_entry *
@@ -57,5 +61,7 @@
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);
#endif /* PMKSA_CACHE_H */
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index efd2a72..bb43218 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -31,6 +31,7 @@
#include "ap_drv_ops.h"
#include "gas_serv.h"
#include "wnm_ap.h"
+#include "ndisc_snoop.h"
#include "sta_info.h"
static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
@@ -144,6 +145,12 @@
}
+void ap_sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ sta_ip6addr_del(hapd, sta);
+}
+
+
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
{
int set_beacon = 0;
@@ -156,6 +163,10 @@
if (sta->flags & WLAN_STA_WDS)
hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0);
+ if (sta->ipaddr)
+ hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
+ ap_sta_ip6addr_del(hapd, sta);
+
if (!hapd->iface->driver_ap_teardown &&
!(sta->flags & WLAN_STA_PREAUTH))
hostapd_drv_sta_remove(hapd, sta->addr);
@@ -224,6 +235,11 @@
set_beacon++;
#endif /* NEED_AP_MLME && CONFIG_IEEE80211N */
+#ifdef CONFIG_MESH
+ if (hapd->mesh_sta_free_cb)
+ hapd->mesh_sta_free_cb(sta);
+#endif /* CONFIG_MESH */
+
if (set_beacon)
ieee802_11_set_beacons(hapd->iface);
@@ -234,6 +250,7 @@
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);
+ sae_clear_retransmit_timer(hapd, sta);
ieee802_1x_free_station(sta);
wpa_auth_sta_deinit(sta->wpa_sm);
@@ -353,8 +370,14 @@
* but do not disconnect the station now.
*/
next_time = hapd->conf->ap_max_inactivity + fuzz;
- } else if (inactive_sec < hapd->conf->ap_max_inactivity &&
- sta->flags & WLAN_STA_ASSOC) {
+ } else if (inactive_sec == -ENOENT) {
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+ "Station " MACSTR " has lost its driver entry",
+ MAC2STR(sta->addr));
+
+ if (hapd->conf->skip_inactivity_poll)
+ sta->timeout_next = STA_DISASSOC;
+ } else if (inactive_sec < hapd->conf->ap_max_inactivity) {
/* station activity detected; reset timeout state */
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
"Station " MACSTR " has been active %is ago",
@@ -596,6 +619,8 @@
ap_sta_hash_add(hapd, sta);
sta->ssid = &hapd->conf->ssid;
ap_sta_remove_in_other_bss(hapd, sta);
+ sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
+ dl_list_init(&sta->ip6addr);
return sta;
}
@@ -605,6 +630,10 @@
{
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
+ if (sta->ipaddr)
+ 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));
if (hostapd_drv_sta_remove(hapd, sta->addr) &&
@@ -657,6 +686,7 @@
{
wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR,
hapd->conf->iface, MAC2STR(sta->addr));
+ sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
ap_sta_set_authorized(hapd, sta, 0);
sta->timeout_next = STA_DEAUTH;
@@ -695,7 +725,8 @@
{
wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR,
hapd->conf->iface, MAC2STR(sta->addr));
- sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+ sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
+ sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
ap_sta_set_authorized(hapd, sta, 0);
sta->timeout_next = STA_REMOVE;
wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
@@ -904,7 +935,15 @@
sta->sa_query_trans_id = nbuf;
sta->sa_query_count++;
- os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+ if (os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0) {
+ /*
+ * We don't really care which ID is used here, so simply
+ * hardcode this if the mostly theoretical os_get_random()
+ * failure happens.
+ */
+ trans_id[0] = 0x12;
+ trans_id[1] = 0x34;
+ }
timeout = hapd->conf->assoc_sa_query_retry_timeout;
sec = ((timeout / 1000) * 1024) / 1000;
@@ -949,6 +988,11 @@
if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED))
return;
+ if (authorized)
+ sta->flags |= WLAN_STA_AUTHORIZED;
+ else
+ sta->flags &= ~WLAN_STA_AUTHORIZED;
+
#ifdef CONFIG_P2P
if (hapd->p2p_group == NULL) {
if (sta->p2p_ie != NULL &&
@@ -964,6 +1008,10 @@
#endif /* CONFIG_P2P */
os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(sta->addr));
+ if (hapd->sta_authorized_cb)
+ hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx,
+ sta->addr, authorized, dev_addr);
+
if (authorized) {
char ip_addr[100];
ip_addr[0] = '\0';
@@ -984,8 +1032,6 @@
wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO,
AP_STA_CONNECTED "%s%s",
buf, ip_addr);
-
- sta->flags |= WLAN_STA_AUTHORIZED;
} else {
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED "%s", buf);
@@ -993,13 +1039,7 @@
hapd->msg_ctx_parent != hapd->msg_ctx)
wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO,
AP_STA_DISCONNECTED "%s", buf);
-
- sta->flags &= ~WLAN_STA_AUTHORIZED;
}
-
- if (hapd->sta_authorized_cb)
- hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx,
- sta->addr, authorized, dev_addr);
}
@@ -1067,7 +1107,7 @@
int res;
buf[0] = '\0';
- res = os_snprintf(buf, buflen, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ res = os_snprintf(buf, buflen, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
(flags & WLAN_STA_AUTH ? "[AUTH]" : ""),
(flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
(flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : ""),
@@ -1085,8 +1125,11 @@
(flags & WLAN_STA_WPS2 ? "[WPS2]" : ""),
(flags & WLAN_STA_GAS ? "[GAS]" : ""),
(flags & WLAN_STA_VHT ? "[VHT]" : ""),
+ (flags & WLAN_STA_VENDOR_VHT ? "[VENDOR_VHT]" : ""),
(flags & WLAN_STA_WNM_SLEEP_MODE ?
"[WNM_SLEEP_MODE]" : ""));
+ if (os_snprintf_error(buflen, res))
+ res = -1;
return res;
}
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index faf32d8..57551ab 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -9,6 +9,13 @@
#ifndef STA_INFO_H
#define STA_INFO_H
+#ifdef CONFIG_MESH
+/* needed for mesh_plink_state enum */
+#include "common/defs.h"
+#endif /* CONFIG_MESH */
+
+#include "list.h"
+
/* STA flags */
#define WLAN_STA_AUTH BIT(0)
#define WLAN_STA_ASSOC BIT(1)
@@ -28,6 +35,7 @@
#define WLAN_STA_VHT BIT(18)
#define WLAN_STA_WNM_SLEEP_MODE BIT(19)
#define WLAN_STA_VHT_OPMODE_ENABLED BIT(20)
+#define WLAN_STA_VENDOR_VHT BIT(21)
#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
#define WLAN_STA_NONERP BIT(31)
@@ -41,6 +49,8 @@
struct sta_info *next; /* next entry in sta list */
struct sta_info *hnext; /* next entry in hash table list */
u8 addr[6];
+ be32 ipaddr;
+ struct dl_list ip6addr; /* list head for struct ip6addr */
u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */
u32 flags; /* Bitfield of WLAN_STA_* */
u16 capability;
@@ -49,6 +59,20 @@
int supported_rates_len;
u8 qosinfo; /* Valid when WLAN_STA_WMM is set */
+#ifdef CONFIG_MESH
+ enum mesh_plink_state plink_state;
+ u16 peer_lid;
+ u16 my_lid;
+ u16 mpm_close_reason;
+ int mpm_retries;
+ u8 my_nonce[32];
+ u8 peer_nonce[32];
+ u8 aek[32]; /* SHA256 digest length */
+ u8 mtk[16];
+ u8 mgtk[16];
+ u8 sae_auth_retry;
+#endif /* CONFIG_MESH */
+
unsigned int nonerp_set:1;
unsigned int no_short_slot_time_set:1;
unsigned int no_short_preamble_set:1;
@@ -61,6 +85,7 @@
unsigned int remediation:1;
unsigned int hs20_deauth_requested:1;
unsigned int session_timeout_set:1;
+ unsigned int radius_das_match:1;
u16 auth_alg;
@@ -138,6 +163,12 @@
#endif /* CONFIG_SAE */
u32 session_timeout; /* valid only if session_timeout_set == 1 */
+
+ /* Last Authentication/(Re)Association Request/Action frame sequence
+ * control */
+ u16 last_seq_ctrl;
+ /* Last Authentication/(Re)Association Request/Action frame subtype */
+ u8 last_subtype;
};
@@ -167,6 +198,7 @@
struct sta_info * ap_get_sta_p2p(struct hostapd_data *hapd, const u8 *addr);
void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta);
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta);
+void ap_sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta);
void hostapd_free_stas(struct hostapd_data *hapd);
void ap_handle_timer(void *eloop_ctx, void *timeout_ctx);
void ap_sta_replenish_timeout(struct hostapd_data *hapd, struct sta_info *sta,
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
index cf25dbb..4c8bc10 100644
--- a/src/ap/wnm_ap.c
+++ b/src/ap/wnm_ap.c
@@ -1,6 +1,6 @@
/*
* hostapd - WNM
- * Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
+ * Copyright (c) 2011-2014, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -11,6 +11,7 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
#include "ap/hostapd.h"
#include "ap/sta_info.h"
#include "ap/ap_config.h"
@@ -358,7 +359,16 @@
}
wpa_printf(MSG_DEBUG, "WNM: Target BSSID: " MACSTR,
MAC2STR(pos));
+ wpa_msg(hapd->msg_ctx, MSG_INFO, BSS_TM_RESP MACSTR
+ " status_code=%u bss_termination_delay=%u target_bssid="
+ MACSTR,
+ MAC2STR(addr), status_code, bss_termination_delay,
+ MAC2STR(pos));
pos += ETH_ALEN;
+ } else {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, BSS_TM_RESP MACSTR
+ " status_code=%u bss_termination_delay=%u",
+ MAC2STR(addr), status_code, bss_termination_delay);
}
wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries",
@@ -436,6 +446,34 @@
}
+static void set_disassoc_timer(struct hostapd_data *hapd, struct sta_info *sta,
+ int disassoc_timer)
+{
+ int timeout, beacon_int;
+
+ /*
+ * Prevent STA from reconnecting using cached PMKSA to force
+ * full authentication with the authentication server (which may
+ * decide to reject the connection),
+ */
+ wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
+
+ beacon_int = hapd->iconf->beacon_int;
+ if (beacon_int < 1)
+ beacon_int = 100; /* best guess */
+ /* Calculate timeout in ms based on beacon_int in TU */
+ timeout = disassoc_timer * beacon_int * 128 / 125;
+ wpa_printf(MSG_DEBUG, "Disassociation timer for " MACSTR
+ " set to %d ms", MAC2STR(sta->addr), timeout);
+
+ sta->timeout_next = STA_DISASSOC_FROM_CLI;
+ eloop_cancel_timeout(ap_handle_timer, hapd, sta);
+ eloop_register_timeout(timeout / 1000,
+ timeout % 1000 * 1000,
+ ap_handle_timer, hapd, sta);
+}
+
+
int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
struct sta_info *sta, const char *url,
int disassoc_timer)
@@ -477,30 +515,81 @@
return -1;
}
- /* send disassociation frame after time-out */
if (disassoc_timer) {
- int timeout, beacon_int;
+ /* send disassociation frame after time-out */
+ set_disassoc_timer(hapd, sta, disassoc_timer);
+ }
- /*
- * Prevent STA from reconnecting using cached PMKSA to force
- * full authentication with the authentication server (which may
- * decide to reject the connection),
- */
- wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
+ return 0;
+}
- beacon_int = hapd->iconf->beacon_int;
- if (beacon_int < 1)
- beacon_int = 100; /* best guess */
- /* Calculate timeout in ms based on beacon_int in TU */
- timeout = disassoc_timer * beacon_int * 128 / 125;
- wpa_printf(MSG_DEBUG, "Disassociation timer for " MACSTR
- " set to %d ms", MAC2STR(sta->addr), timeout);
- sta->timeout_next = STA_DISASSOC_FROM_CLI;
- eloop_cancel_timeout(ap_handle_timer, hapd, sta);
- eloop_register_timeout(timeout / 1000,
- timeout % 1000 * 1000,
- ap_handle_timer, hapd, sta);
+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)
+{
+ u8 *buf, *pos;
+ struct ieee80211_mgmt *mgmt;
+ size_t url_len;
+
+ 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);
+ if (buf == NULL)
+ return -1;
+ mgmt = (struct ieee80211_mgmt *) buf;
+ mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_ACTION);
+ os_memcpy(mgmt->da, sta->addr, ETH_ALEN);
+ os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
+ mgmt->u.action.category = WLAN_ACTION_WNM;
+ mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
+ mgmt->u.action.u.bss_tm_req.dialog_token = 1;
+ mgmt->u.action.u.bss_tm_req.req_mode = req_mode;
+ mgmt->u.action.u.bss_tm_req.disassoc_timer =
+ host_to_le16(disassoc_timer);
+ mgmt->u.action.u.bss_tm_req.validity_interval = valid_int;
+
+ pos = mgmt->u.action.u.bss_tm_req.variable;
+
+ if ((req_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) &&
+ bss_term_dur) {
+ os_memcpy(pos, bss_term_dur, 12);
+ pos += 12;
+ }
+
+ if (url) {
+ /* Session Information URL */
+ url_len = os_strlen(url);
+ if (url_len > 255) {
+ os_free(buf);
+ return -1;
+ }
+
+ *pos++ = url_len;
+ os_memcpy(pos, url, url_len);
+ pos += url_len;
+ }
+
+ if (nei_rep) {
+ os_memcpy(pos, nei_rep, nei_rep_len);
+ pos += nei_rep_len;
+ }
+
+ if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "Failed to send BSS Transition Management Request frame");
+ os_free(buf);
+ return -1;
+ }
+ os_free(buf);
+
+ if (disassoc_timer) {
+ /* send disassociation frame after time-out */
+ set_disassoc_timer(hapd, sta, disassoc_timer);
}
return 0;
diff --git a/src/ap/wnm_ap.h b/src/ap/wnm_ap.h
index eeaf5ec..7789307 100644
--- a/src/ap/wnm_ap.h
+++ b/src/ap/wnm_ap.h
@@ -1,6 +1,6 @@
/*
* IEEE 802.11v WNM related functions and structures
- * Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
+ * Copyright (c) 2011-2014, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -18,5 +18,9 @@
int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
struct sta_info *sta, const char *url,
int disassoc_timer);
+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);
#endif /* WNM_AP_H */
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 1a16b5c..1905dc9 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -1,6 +1,6 @@
/*
* IEEE 802.11 RSN / WPA Authenticator
- * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -33,7 +33,8 @@
static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx);
static int wpa_sm_step(struct wpa_state_machine *sm);
-static int wpa_verify_key_mic(struct wpa_ptk *PTK, u8 *data, size_t data_len);
+static int wpa_verify_key_mic(int akmp, struct wpa_ptk *PTK, u8 *data,
+ size_t data_len);
static void wpa_sm_call_step(void *eloop_ctx, void *timeout_ctx);
static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
@@ -42,6 +43,8 @@
struct wpa_group *group);
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);
static const u32 dot11RSNAConfigGroupUpdateCount = 4;
static const u32 dot11RSNAConfigPairwiseUpdateCount = 4;
@@ -135,6 +138,17 @@
}
+#ifdef CONFIG_MESH
+static inline int wpa_auth_start_ampe(struct wpa_authenticator *wpa_auth,
+ const u8 *addr)
+{
+ if (wpa_auth->cb.start_ampe == NULL)
+ return -1;
+ return wpa_auth->cb.start_ampe(wpa_auth->cb.ctx, addr);
+}
+#endif /* CONFIG_MESH */
+
+
int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth,
int (*cb)(struct wpa_state_machine *sm, void *ctx),
void *cb_ctx)
@@ -401,6 +415,7 @@
wpa_auth);
if (wpa_auth->pmksa == NULL) {
wpa_printf(MSG_ERROR, "PMKSA cache initialization failed.");
+ os_free(wpa_auth->group);
os_free(wpa_auth->wpa_ie);
os_free(wpa_auth);
return NULL;
@@ -410,6 +425,7 @@
wpa_auth->ft_pmk_cache = wpa_ft_pmk_cache_init();
if (wpa_auth->ft_pmk_cache == NULL) {
wpa_printf(MSG_ERROR, "FT PMK cache initialization failed.");
+ os_free(wpa_auth->group);
os_free(wpa_auth->wpa_ie);
pmksa_cache_auth_deinit(wpa_auth->pmksa);
os_free(wpa_auth);
@@ -782,40 +798,96 @@
}
+static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
+ size_t data_len)
+{
+ struct wpa_ptk PTK;
+ int ok = 0;
+ const u8 *pmk = NULL;
+
+ for (;;) {
+ if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
+ pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
+ sm->p2p_dev_addr, pmk);
+ if (pmk == NULL)
+ break;
+ } else
+ pmk = sm->PMK;
+
+ wpa_derive_ptk(sm, sm->alt_SNonce, pmk, &PTK);
+
+ if (wpa_verify_key_mic(sm->wpa_key_mgmt, &PTK, data, data_len)
+ == 0) {
+ ok = 1;
+ break;
+ }
+
+ if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt))
+ break;
+ }
+
+ if (!ok) {
+ wpa_printf(MSG_DEBUG,
+ "WPA: Earlier SNonce did not result in matching MIC");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "WPA: Earlier SNonce resulted in matching MIC");
+ sm->alt_snonce_valid = 0;
+ os_memcpy(sm->SNonce, sm->alt_SNonce, WPA_NONCE_LEN);
+ os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
+ sm->PTK_valid = TRUE;
+
+ return 0;
+}
+
+
void wpa_receive(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm,
u8 *data, size_t data_len)
{
struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
+ struct wpa_eapol_key_192 *key192;
u16 key_info, key_data_length;
enum { PAIRWISE_2, PAIRWISE_4, GROUP_2, REQUEST,
SMK_M1, SMK_M3, SMK_ERROR } msg;
char *msgtxt;
struct wpa_eapol_ie_parse kde;
int ft;
- const u8 *eapol_key_ie;
- size_t eapol_key_ie_len;
+ const u8 *eapol_key_ie, *key_data;
+ size_t eapol_key_ie_len, keyhdrlen, mic_len;
if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL)
return;
- if (data_len < sizeof(*hdr) + sizeof(*key))
+ mic_len = wpa_mic_len(sm->wpa_key_mgmt);
+ keyhdrlen = mic_len == 24 ? sizeof(*key192) : sizeof(*key);
+
+ if (data_len < sizeof(*hdr) + keyhdrlen)
return;
hdr = (struct ieee802_1x_hdr *) data;
key = (struct wpa_eapol_key *) (hdr + 1);
+ key192 = (struct wpa_eapol_key_192 *) (hdr + 1);
key_info = WPA_GET_BE16(key->key_info);
- key_data_length = WPA_GET_BE16(key->key_data_length);
+ if (mic_len == 24) {
+ key_data = (const u8 *) (key192 + 1);
+ key_data_length = WPA_GET_BE16(key192->key_data_length);
+ } else {
+ key_data = (const u8 *) (key + 1);
+ key_data_length = WPA_GET_BE16(key->key_data_length);
+ }
wpa_printf(MSG_DEBUG, "WPA: Received EAPOL-Key from " MACSTR
" key_info=0x%x type=%u key_data_length=%u",
MAC2STR(sm->addr), key_info, key->type, key_data_length);
- if (key_data_length > data_len - sizeof(*hdr) - sizeof(*key)) {
+ if (key_data_length > data_len - sizeof(*hdr) - keyhdrlen) {
wpa_printf(MSG_INFO, "WPA: Invalid EAPOL-Key frame - "
"key_data overflow (%d > %lu)",
key_data_length,
(unsigned long) (data_len - sizeof(*hdr) -
- sizeof(*key)));
+ keyhdrlen));
return;
}
@@ -884,6 +956,7 @@
sm->pairwise == WPA_CIPHER_GCMP) {
if (wpa_use_aes_cmac(sm) &&
sm->wpa_key_mgmt != WPA_KEY_MGMT_OSEN &&
+ !wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) &&
ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
wpa_auth_logger(wpa_auth, sm->addr,
LOGGER_WARNING,
@@ -902,6 +975,13 @@
return;
}
}
+
+ if (wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) &&
+ ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING,
+ "did not use EAPOL-Key descriptor version 0 as required for AKM-defined cases");
+ return;
+ }
}
if (key_info & WPA_KEY_INFO_REQUEST) {
@@ -937,8 +1017,25 @@
"based on retransmitted EAPOL-Key "
"1/4");
sm->update_snonce = 1;
- wpa_replay_counter_mark_invalid(sm->prev_key_replay,
- key->replay_counter);
+ os_memcpy(sm->alt_SNonce, sm->SNonce, WPA_NONCE_LEN);
+ sm->alt_snonce_valid = TRUE;
+ os_memcpy(sm->alt_replay_counter,
+ sm->key_replay[0].counter,
+ WPA_REPLAY_COUNTER_LEN);
+ goto continue_processing;
+ }
+
+ if (msg == PAIRWISE_4 && sm->alt_snonce_valid &&
+ sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING &&
+ os_memcmp(key->replay_counter, sm->alt_replay_counter,
+ WPA_REPLAY_COUNTER_LEN) == 0) {
+ /*
+ * Supplicant may still be using the old SNonce since
+ * there was two EAPOL-Key 2/4 messages and they had
+ * different SNonce values.
+ */
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "Try to process received EAPOL-Key 4/4 based on old Replay Counter and SNonce from an earlier EAPOL-Key 1/4");
goto continue_processing;
}
@@ -997,8 +1094,7 @@
wpa_sta_disconnect(wpa_auth, sm->addr);
return;
}
- if (wpa_parse_kde_ies((u8 *) (key + 1), key_data_length,
- &kde) < 0) {
+ if (wpa_parse_kde_ies(key_data, key_data_length, &kde) < 0) {
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
"received EAPOL-Key msg 2/4 with "
"invalid Key Data contents");
@@ -1123,7 +1219,10 @@
sm->MICVerified = FALSE;
if (sm->PTK_valid && !sm->update_snonce) {
- if (wpa_verify_key_mic(&sm->PTK, data, data_len)) {
+ if (wpa_verify_key_mic(sm->wpa_key_mgmt, &sm->PTK, data,
+ data_len) &&
+ (msg != PAIRWISE_4 || !sm->alt_snonce_valid ||
+ wpa_try_alt_snonce(sm, data, data_len))) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
"received EAPOL-Key with invalid MIC");
return;
@@ -1152,7 +1251,7 @@
*/
if (msg == SMK_ERROR) {
#ifdef CONFIG_PEERKEY
- wpa_smk_error(wpa_auth, sm, key);
+ wpa_smk_error(wpa_auth, sm, key_data, key_data_length);
#endif /* CONFIG_PEERKEY */
return;
} else if (key_info & WPA_KEY_INFO_ERROR) {
@@ -1167,11 +1266,12 @@
wpa_request_new_ptk(sm);
#ifdef CONFIG_PEERKEY
} else if (msg == SMK_M1) {
- wpa_smk_m1(wpa_auth, sm, key);
+ wpa_smk_m1(wpa_auth, sm, key, key_data,
+ key_data_length);
#endif /* CONFIG_PEERKEY */
} else if (key_data_length > 0 &&
- wpa_parse_kde_ies((const u8 *) (key + 1),
- key_data_length, &kde) == 0 &&
+ wpa_parse_kde_ies(key_data, key_data_length,
+ &kde) == 0 &&
kde.mac_addr) {
} else {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
@@ -1209,7 +1309,7 @@
#ifdef CONFIG_PEERKEY
if (msg == SMK_M3) {
- wpa_smk_m3(wpa_auth, sm, key);
+ wpa_smk_m3(wpa_auth, sm, key, key_data, key_data_length);
return;
}
#endif /* CONFIG_PEERKEY */
@@ -1284,18 +1384,24 @@
{
struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
- size_t len;
+ struct wpa_eapol_key_192 *key192;
+ size_t len, mic_len, keyhdrlen;
int alg;
int key_data_len, pad_len = 0;
u8 *buf, *pos;
int version, pairwise;
int i;
+ u8 *key_data;
- len = sizeof(struct ieee802_1x_hdr) + sizeof(struct wpa_eapol_key);
+ mic_len = wpa_mic_len(sm->wpa_key_mgmt);
+ keyhdrlen = mic_len == 24 ? sizeof(*key192) : sizeof(*key);
+
+ len = sizeof(struct ieee802_1x_hdr) + keyhdrlen;
if (force_version)
version = force_version;
- else if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN)
+ else if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN ||
+ wpa_key_mgmt_suite_b(sm->wpa_key_mgmt))
version = WPA_KEY_INFO_TYPE_AKM_DEFINED;
else if (wpa_use_aes_cmac(sm))
version = WPA_KEY_INFO_TYPE_AES_128_CMAC;
@@ -1320,6 +1426,7 @@
if ((version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN ||
+ wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) ||
version == WPA_KEY_INFO_TYPE_AES_128_CMAC) && encr) {
pad_len = key_data_len % 8;
if (pad_len)
@@ -1336,6 +1443,8 @@
hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
hdr->length = host_to_be16(len - sizeof(*hdr));
key = (struct wpa_eapol_key *) (hdr + 1);
+ key192 = (struct wpa_eapol_key_192 *) (hdr + 1);
+ key_data = ((u8 *) (hdr + 1)) + keyhdrlen;
key->type = sm->wpa == WPA_VERSION_WPA2 ?
EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
@@ -1361,6 +1470,8 @@
inc_byte_array(sm->key_replay[0].counter, WPA_REPLAY_COUNTER_LEN);
os_memcpy(key->replay_counter, sm->key_replay[0].counter,
WPA_REPLAY_COUNTER_LEN);
+ wpa_hexdump(MSG_DEBUG, "WPA: Replay Counter",
+ key->replay_counter, WPA_REPLAY_COUNTER_LEN);
sm->key_replay[0].valid = TRUE;
if (nonce)
@@ -1370,8 +1481,11 @@
os_memcpy(key->key_rsc, key_rsc, WPA_KEY_RSC_LEN);
if (kde && !encr) {
- os_memcpy(key + 1, kde, kde_len);
- WPA_PUT_BE16(key->key_data_length, kde_len);
+ os_memcpy(key_data, kde, kde_len);
+ if (mic_len == 24)
+ WPA_PUT_BE16(key192->key_data_length, kde_len);
+ else
+ WPA_PUT_BE16(key->key_data_length, kde_len);
} else if (encr && kde) {
buf = os_zalloc(key_data_len);
if (buf == NULL) {
@@ -1389,30 +1503,46 @@
buf, key_data_len);
if (version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN ||
+ wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) ||
version == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
- if (aes_wrap(sm->PTK.kek, 16,
- (key_data_len - 8) / 8, buf,
- (u8 *) (key + 1))) {
+ if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len,
+ (key_data_len - 8) / 8, buf, key_data)) {
os_free(hdr);
os_free(buf);
return;
}
- WPA_PUT_BE16(key->key_data_length, key_data_len);
- } else {
+ if (mic_len == 24)
+ WPA_PUT_BE16(key192->key_data_length,
+ key_data_len);
+ else
+ WPA_PUT_BE16(key->key_data_length,
+ key_data_len);
+ } else if (sm->PTK.kek_len == 16) {
u8 ek[32];
os_memcpy(key->key_iv,
sm->group->Counter + WPA_NONCE_LEN - 16, 16);
inc_byte_array(sm->group->Counter, WPA_NONCE_LEN);
os_memcpy(ek, key->key_iv, 16);
- os_memcpy(ek + 16, sm->PTK.kek, 16);
- os_memcpy(key + 1, buf, key_data_len);
- rc4_skip(ek, 32, 256, (u8 *) (key + 1), key_data_len);
- WPA_PUT_BE16(key->key_data_length, key_data_len);
+ os_memcpy(ek + 16, sm->PTK.kek, sm->PTK.kek_len);
+ os_memcpy(key_data, buf, key_data_len);
+ rc4_skip(ek, 32, 256, key_data, key_data_len);
+ if (mic_len == 24)
+ WPA_PUT_BE16(key192->key_data_length,
+ key_data_len);
+ else
+ WPA_PUT_BE16(key->key_data_length,
+ key_data_len);
+ } else {
+ os_free(hdr);
+ os_free(buf);
+ return;
}
os_free(buf);
}
if (key_info & WPA_KEY_INFO_MIC) {
+ u8 *key_mic;
+
if (!sm->PTK_valid) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
"PTK not valid when sending EAPOL-Key "
@@ -1420,8 +1550,11 @@
os_free(hdr);
return;
}
- wpa_eapol_key_mic(sm->PTK.kck, version, (u8 *) hdr, len,
- key->key_mic);
+
+ key_mic = key192->key_mic; /* same offset for key and key192 */
+ wpa_eapol_key_mic(sm->PTK.kck, sm->PTK.kck_len,
+ sm->wpa_key_mgmt, version,
+ (u8 *) hdr, len, key_mic);
#ifdef CONFIG_TESTING_OPTIONS
if (!pairwise &&
wpa_auth->conf.corrupt_gtk_rekey_mic_probability > 0.0 &&
@@ -1429,7 +1562,7 @@
wpa_auth->conf.corrupt_gtk_rekey_mic_probability) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
"Corrupting group EAPOL-Key Key MIC");
- key->key_mic[0]++;
+ key_mic[0]++;
}
#endif /* CONFIG_TESTING_OPTIONS */
}
@@ -1473,27 +1606,32 @@
}
-static int wpa_verify_key_mic(struct wpa_ptk *PTK, u8 *data, size_t data_len)
+static int wpa_verify_key_mic(int akmp, struct wpa_ptk *PTK, u8 *data,
+ size_t data_len)
{
struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
+ struct wpa_eapol_key_192 *key192;
u16 key_info;
int ret = 0;
- u8 mic[16];
+ u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
+ size_t mic_len = wpa_mic_len(akmp);
if (data_len < sizeof(*hdr) + sizeof(*key))
return -1;
hdr = (struct ieee802_1x_hdr *) data;
key = (struct wpa_eapol_key *) (hdr + 1);
+ key192 = (struct wpa_eapol_key_192 *) (hdr + 1);
key_info = WPA_GET_BE16(key->key_info);
- os_memcpy(mic, key->key_mic, 16);
- os_memset(key->key_mic, 0, 16);
- if (wpa_eapol_key_mic(PTK->kck, key_info & WPA_KEY_INFO_TYPE_MASK,
- data, data_len, key->key_mic) ||
- os_memcmp_const(mic, key->key_mic, 16) != 0)
+ os_memcpy(mic, key192->key_mic, mic_len);
+ os_memset(key192->key_mic, 0, mic_len);
+ if (wpa_eapol_key_mic(PTK->kck, PTK->kck_len, akmp,
+ key_info & WPA_KEY_INFO_TYPE_MASK,
+ data, data_len, key192->key_mic) ||
+ os_memcmp_const(mic, key192->key_mic, mic_len) != 0)
ret = -1;
- os_memcpy(key->key_mic, mic, 16);
+ os_memcpy(key192->key_mic, mic, mic_len);
return ret;
}
@@ -1520,6 +1658,14 @@
switch (event) {
case WPA_AUTH:
+#ifdef CONFIG_MESH
+ /* PTKs are derived through AMPE */
+ if (wpa_auth_start_ampe(sm->wpa_auth, sm->addr)) {
+ /* not mesh */
+ break;
+ }
+ return 0;
+#endif /* CONFIG_MESH */
case WPA_ASSOC:
break;
case WPA_DEAUTH:
@@ -1733,7 +1879,8 @@
}
#endif /* CONFIG_IEEE80211R */
} else {
- wpa_printf(MSG_DEBUG, "WPA: Could not get PMK");
+ wpa_printf(MSG_DEBUG, "WPA: Could not get PMK, get_msk: %p",
+ sm->wpa_auth->cb.get_msk);
}
sm->req_replay_counter_used = 0;
@@ -1773,6 +1920,7 @@
SM_ENTRY_MA(WPA_PTK, PTKSTART, wpa_ptk);
sm->PTKRequest = FALSE;
sm->TimeoutEvt = FALSE;
+ sm->alt_snonce_valid = FALSE;
sm->TimeoutCtr++;
if (sm->TimeoutCtr > (int) dot11RSNAConfigPairwiseUpdateCount) {
@@ -1795,10 +1943,13 @@
pmkid[0] = WLAN_EID_VENDOR_SPECIFIC;
pmkid[1] = RSN_SELECTOR_LEN + PMKID_LEN;
RSN_SELECTOR_PUT(&pmkid[2], RSN_KEY_DATA_PMKID);
- if (sm->pmksa)
+ if (sm->pmksa) {
os_memcpy(&pmkid[2 + RSN_SELECTOR_LEN],
sm->pmksa->pmkid, PMKID_LEN);
- else {
+ } else if (wpa_key_mgmt_suite_b(sm->wpa_key_mgmt)) {
+ /* No KCK available to derive PMKID */
+ pmkid = NULL;
+ } else {
/*
* Calculate PMKID since no PMKSA cache entry was
* available with pre-calculated PMKID.
@@ -1814,21 +1965,17 @@
}
-static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *pmk,
- struct wpa_ptk *ptk)
+static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
+ const u8 *pmk, struct wpa_ptk *ptk)
{
- size_t ptk_len = wpa_cipher_key_len(sm->pairwise) + 32;
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
- return wpa_auth_derive_ptk_ft(sm, pmk, ptk, ptk_len);
+ return wpa_auth_derive_ptk_ft(sm, pmk, ptk);
#endif /* CONFIG_IEEE80211R */
- wpa_pmk_to_ptk(pmk, PMK_LEN, "Pairwise key expansion",
- sm->wpa_auth->addr, sm->addr, sm->ANonce, sm->SNonce,
- (u8 *) ptk, ptk_len,
- wpa_key_mgmt_sha256(sm->wpa_key_mgmt));
-
- return 0;
+ 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);
}
@@ -1854,9 +2001,10 @@
} else
pmk = sm->PMK;
- wpa_derive_ptk(sm, pmk, &PTK);
+ wpa_derive_ptk(sm, sm->SNonce, pmk, &PTK);
- if (wpa_verify_key_mic(&PTK, sm->last_rx_eapol_key,
+ if (wpa_verify_key_mic(sm->wpa_key_mgmt, &PTK,
+ sm->last_rx_eapol_key,
sm->last_rx_eapol_key_len) == 0) {
ok = 1;
break;
@@ -2009,8 +2157,10 @@
if (sm->wpa == WPA_VERSION_WPA &&
(sm->wpa_auth->conf.wpa & WPA_PROTO_RSN) &&
wpa_ie_len > wpa_ie[1] + 2 && wpa_ie[0] == WLAN_EID_RSN) {
- /* WPA-only STA, remove RSN IE */
+ /* WPA-only STA, remove RSN IE and possible MDIE */
wpa_ie = wpa_ie + wpa_ie[1] + 2;
+ if (wpa_ie[0] == WLAN_EID_MOBILITY_DOMAIN)
+ wpa_ie = wpa_ie + wpa_ie[1] + 2;
wpa_ie_len = wpa_ie[1] + 2;
}
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
@@ -2157,7 +2307,7 @@
enum wpa_alg alg = wpa_cipher_to_alg(sm->pairwise);
int klen = wpa_cipher_key_len(sm->pairwise);
if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
- sm->PTK.tk1, klen)) {
+ sm->PTK.tk, klen)) {
wpa_sta_disconnect(sm->wpa_auth, sm->addr);
return;
}
@@ -2331,7 +2481,8 @@
{
u8 rsc[WPA_KEY_RSC_LEN];
struct wpa_group *gsm = sm->group;
- u8 *kde, *pos, hdr[2];
+ const u8 *kde;
+ u8 *kde_buf = NULL, *pos, hdr[2];
size_t kde_len;
u8 *gtk, dummy_gtk[32];
@@ -2367,28 +2518,29 @@
if (sm->wpa == WPA_VERSION_WPA2) {
kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
ieee80211w_kde_len(sm);
- kde = os_malloc(kde_len);
- if (kde == NULL)
+ kde_buf = os_malloc(kde_len);
+ if (kde_buf == NULL)
return;
- pos = kde;
+ kde = pos = kde_buf;
hdr[0] = gsm->GN & 0x03;
hdr[1] = 0;
pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
gtk, gsm->GTK_len);
pos = ieee80211w_kde_add(sm, pos);
+ kde_len = pos - kde;
} else {
kde = gtk;
- pos = kde + gsm->GTK_len;
+ kde_len = gsm->GTK_len;
}
wpa_send_eapol(sm->wpa_auth, sm,
WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
WPA_KEY_INFO_ACK |
(!sm->Pair ? WPA_KEY_INFO_INSTALL : 0),
- rsc, gsm->GNonce, kde, pos - kde, gsm->GN, 1);
- if (sm->wpa == WPA_VERSION_WPA2)
- os_free(kde);
+ rsc, gsm->GNonce, kde, kde_len, gsm->GN, 1);
+
+ os_free(kde_buf);
}
@@ -2859,7 +3011,7 @@
wpa_bool_txt(preauth),
wpa_bool_txt(wpa_auth->conf.wpa & WPA_PROTO_RSN),
wpa_bool_txt(wpa_auth->conf.rsn_preauth));
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -2909,7 +3061,7 @@
RSN_SUITE_ARG(wpa_auth->dot11RSNAGroupCipherRequested),
wpa_auth->dot11RSNATKIPCounterMeasuresInvoked,
wpa_auth->dot11RSNA4WayHandshakeFailures);
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -2919,7 +3071,7 @@
/* Private MIB */
ret = os_snprintf(buf + len, buflen - len, "hostapdWPAGroupState=%d\n",
wpa_auth->group->wpa_group_state);
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -2961,7 +3113,7 @@
RSN_SUITE_ARG(pairwise),
sm->dot11RSNAStatsTKIPLocalMICFailures,
sm->dot11RSNAStatsTKIPRemoteMICFailures);
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -2971,7 +3123,7 @@
"hostapdWPAPTKGroupState=%d\n",
sm->wpa_ptk_state,
sm->wpa_ptk_group_state);
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -3055,6 +3207,7 @@
return -1;
if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, PMK_LEN,
+ sm->PTK.kck, sm->PTK.kck_len,
sm->wpa_auth->addr, sm->addr, session_timeout,
eapol, sm->wpa_key_mgmt))
return 0;
@@ -3071,7 +3224,9 @@
if (wpa_auth == NULL)
return -1;
- if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, len, wpa_auth->addr,
+ if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, len,
+ NULL, 0,
+ wpa_auth->addr,
sta_addr, session_timeout, eapol,
WPA_KEY_MGMT_IEEE8021X))
return 0;
@@ -3080,6 +3235,22 @@
}
+int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr,
+ const u8 *pmk)
+{
+ if (wpa_auth->conf.disable_pmksa_caching)
+ return -1;
+
+ if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, PMK_LEN,
+ NULL, 0,
+ wpa_auth->addr, addr, 0, NULL,
+ WPA_KEY_MGMT_SAE))
+ return 0;
+
+ return -1;
+}
+
+
void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
const u8 *sta_addr)
{
@@ -3206,3 +3377,10 @@
return 0;
}
#endif /* CONFIG_P2P */
+
+
+int wpa_auth_radius_das_disconnect_pmksa(struct wpa_authenticator *wpa_auth,
+ struct radius_das_attrs *attr)
+{
+ return pmksa_cache_auth_radius_das_disconnect(wpa_auth->pmksa, attr);
+}
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 929a253..b34b84d 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -213,6 +213,9 @@
int (*add_tspec)(void *ctx, const u8 *sta_addr, u8 *tspec_ie,
size_t tspec_ielen);
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_MESH
+ int (*start_ampe)(void *ctx, const u8 *sta_addr);
+#endif /* CONFIG_MESH */
};
struct wpa_authenticator * wpa_init(const u8 *addr,
@@ -276,6 +279,8 @@
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);
void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
const u8 *sta_addr);
int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id);
@@ -310,4 +315,8 @@
int wpa_auth_get_ip_addr(struct wpa_state_machine *sm, u8 *addr);
+struct radius_das_attrs;
+int wpa_auth_radius_das_disconnect_pmksa(struct wpa_authenticator *wpa_auth,
+ struct radius_das_attrs *attr);
+
#endif /* WPA_AUTH_H */
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index 781f15f..ef3249a 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -1,6 +1,6 @@
/*
* hostapd - IEEE 802.11r - Fast BSS Transition
- * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,6 +10,7 @@
#include "utils/common.h"
#include "utils/eloop.h"
+#include "utils/list.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "crypto/aes_wrap.h"
@@ -361,7 +362,7 @@
int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
- struct wpa_ptk *ptk, size_t ptk_len)
+ struct wpa_ptk *ptk)
{
u8 pmk_r0[PMK_LEN], pmk_r0_name[WPA_PMK_NAME_LEN];
u8 pmk_r1[PMK_LEN];
@@ -373,7 +374,6 @@
const u8 *ssid = sm->wpa_auth->conf.ssid;
size_t ssid_len = sm->wpa_auth->conf.ssid_len;
-
if (sm->xxkey_len == 0) {
wpa_printf(MSG_DEBUG, "FT: XXKey not available for key "
"derivation");
@@ -395,13 +395,9 @@
wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, sm->pmk_r1_name,
sm->pairwise);
- wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
- sm->wpa_auth->addr, sm->pmk_r1_name,
- (u8 *) ptk, ptk_len, ptk_name);
- wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, ptk_len);
- wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
-
- return 0;
+ return wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
+ sm->wpa_auth->addr, sm->pmk_r1_name,
+ ptk, ptk_name, sm->wpa_key_mgmt, sm->pairwise);
}
@@ -460,7 +456,8 @@
WPA_PUT_LE16(&subelem[2], gsm->GN & 0x03);
subelem[4] = gsm->GTK_len;
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, subelem + 5);
- if (aes_wrap(sm->PTK.kek, 16, key_len / 8, key, subelem + 13)) {
+ if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len, key_len / 8, key,
+ subelem + 13)) {
os_free(subelem);
return NULL;
}
@@ -492,7 +489,7 @@
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos);
pos += 6;
*pos++ = WPA_IGTK_LEN;
- if (aes_wrap(sm->PTK.kek, 16, WPA_IGTK_LEN / 8,
+ if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len, WPA_IGTK_LEN / 8,
gsm->IGTK[gsm->GN_igtk - 4], pos)) {
os_free(subelem);
return NULL;
@@ -744,7 +741,8 @@
ric_start = NULL;
if (auth_alg == WLAN_AUTH_FT &&
- wpa_ft_mic(sm->PTK.kck, sm->addr, sm->wpa_auth->addr, 6,
+ wpa_ft_mic(sm->PTK.kck, sm->PTK.kck_len, sm->addr,
+ sm->wpa_auth->addr, 6,
mdie, mdie_len, ftie, ftie_len,
rsnie, rsnie_len,
ric_start, ric_start ? pos - ric_start : 0,
@@ -788,7 +786,7 @@
* optimized by adding the STA entry earlier.
*/
if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
- sm->PTK.tk1, klen))
+ sm->PTK.tk, klen))
return;
/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
@@ -806,7 +804,7 @@
u8 ptk_name[WPA_PMK_NAME_LEN];
struct wpa_auth_config *conf;
struct wpa_ft_ies parse;
- size_t buflen, ptk_len;
+ size_t buflen;
int ret;
u8 *pos, *end;
int pairwise;
@@ -891,13 +889,11 @@
wpa_hexdump(MSG_DEBUG, "FT: Generated ANonce",
sm->ANonce, WPA_NONCE_LEN);
- ptk_len = pairwise == WPA_CIPHER_TKIP ? 64 : 48;
- wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
- sm->wpa_auth->addr, pmk_r1_name,
- (u8 *) &sm->PTK, ptk_len, ptk_name);
- wpa_hexdump_key(MSG_DEBUG, "FT: PTK",
- (u8 *) &sm->PTK, ptk_len);
- wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
+ if (wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
+ sm->wpa_auth->addr, pmk_r1_name,
+ &sm->PTK, ptk_name, sm->wpa_key_mgmt,
+ pairwise) < 0)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
sm->pairwise = pairwise;
sm->PTK_valid = TRUE;
@@ -992,7 +988,8 @@
struct wpa_ft_ies parse;
struct rsn_mdie *mdie;
struct rsn_ftie *ftie;
- u8 mic[16];
+ u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
+ size_t mic_len = 16;
unsigned int count;
if (sm == NULL)
@@ -1107,7 +1104,8 @@
return -1;
}
- if (wpa_ft_mic(sm->PTK.kck, sm->addr, sm->wpa_auth->addr, 5,
+ if (wpa_ft_mic(sm->PTK.kck, sm->PTK.kck_len, sm->addr,
+ sm->wpa_auth->addr, 5,
parse.mdie - 2, parse.mdie_len + 2,
parse.ftie - 2, parse.ftie_len + 2,
parse.rsn - 2, parse.rsn_len + 2,
@@ -1117,12 +1115,13 @@
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
- if (os_memcmp_const(mic, ftie->mic, 16) != 0) {
+ if (os_memcmp_const(mic, ftie->mic, mic_len) != 0) {
wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE");
wpa_printf(MSG_DEBUG, "FT: addr=" MACSTR " auth_addr=" MACSTR,
MAC2STR(sm->addr), MAC2STR(sm->wpa_auth->addr));
- wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", ftie->mic, 16);
- wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16);
+ wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC",
+ ftie->mic, mic_len);
+ wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, mic_len);
wpa_hexdump(MSG_MSGDUMP, "FT: MDIE",
parse.mdie - 2, parse.mdie_len + 2);
wpa_hexdump(MSG_MSGDUMP, "FT: FTIE",
@@ -1310,7 +1309,9 @@
const u8 *src_addr,
const u8 *data, size_t data_len)
{
- struct ft_r0kh_r1kh_pull_frame *frame, f;
+ struct ft_r0kh_r1kh_pull_frame f;
+ const u8 *crypt;
+ u8 *plain;
struct ft_remote_r1kh *r1kh;
struct ft_r0kh_r1kh_resp_frame resp, r;
u8 pmk_r0[PMK_LEN];
@@ -1318,7 +1319,7 @@
wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull");
- if (data_len < sizeof(*frame))
+ if (data_len < sizeof(f))
return -1;
r1kh = wpa_auth->conf.r1kh_list;
@@ -1334,12 +1335,14 @@
return -1;
}
- frame = (struct ft_r0kh_r1kh_pull_frame *) data;
+ crypt = data + offsetof(struct ft_r0kh_r1kh_pull_frame, nonce);
+ os_memset(&f, 0, sizeof(f));
+ plain = ((u8 *) &f) + offsetof(struct ft_r0kh_r1kh_pull_frame, nonce);
/* aes_unwrap() does not support inplace decryption, so use a temporary
* buffer for the data. */
if (aes_unwrap(r1kh->key, sizeof(r1kh->key),
(FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8,
- frame->nonce, f.nonce) < 0) {
+ crypt, plain) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 pull "
"request from " MACSTR, MAC2STR(src_addr));
return -1;
@@ -1442,13 +1445,15 @@
const u8 *src_addr,
const u8 *data, size_t data_len)
{
- struct ft_r0kh_r1kh_resp_frame *frame, f;
+ struct ft_r0kh_r1kh_resp_frame f;
+ const u8 *crypt;
+ u8 *plain;
struct ft_remote_r0kh *r0kh;
int pairwise, res;
wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull response");
- if (data_len < sizeof(*frame))
+ if (data_len < sizeof(f))
return -1;
r0kh = wpa_auth->conf.r0kh_list;
@@ -1464,12 +1469,14 @@
return -1;
}
- frame = (struct ft_r0kh_r1kh_resp_frame *) data;
+ crypt = data + offsetof(struct ft_r0kh_r1kh_resp_frame, nonce);
+ os_memset(&f, 0, sizeof(f));
+ plain = ((u8 *) &f) + offsetof(struct ft_r0kh_r1kh_resp_frame, nonce);
/* aes_unwrap() does not support inplace decryption, so use a temporary
* buffer for the data. */
if (aes_unwrap(r0kh->key, sizeof(r0kh->key),
(FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8,
- frame->nonce, f.nonce) < 0) {
+ crypt, plain) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 pull "
"response from " MACSTR, MAC2STR(src_addr));
return -1;
@@ -1507,7 +1514,9 @@
const u8 *src_addr,
const u8 *data, size_t data_len)
{
- struct ft_r0kh_r1kh_push_frame *frame, f;
+ struct ft_r0kh_r1kh_push_frame f;
+ const u8 *crypt;
+ u8 *plain;
struct ft_remote_r0kh *r0kh;
struct os_time now;
os_time_t tsend;
@@ -1515,7 +1524,7 @@
wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 push");
- if (data_len < sizeof(*frame))
+ if (data_len < sizeof(f))
return -1;
r0kh = wpa_auth->conf.r0kh_list;
@@ -1531,12 +1540,15 @@
return -1;
}
- frame = (struct ft_r0kh_r1kh_push_frame *) data;
+ crypt = data + offsetof(struct ft_r0kh_r1kh_push_frame, timestamp);
+ os_memset(&f, 0, sizeof(f));
+ plain = ((u8 *) &f) + offsetof(struct ft_r0kh_r1kh_push_frame,
+ timestamp);
/* aes_unwrap() does not support inplace decryption, so use a temporary
* buffer for the data. */
if (aes_unwrap(r0kh->key, sizeof(r0kh->key),
(FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
- frame->timestamp, f.timestamp) < 0) {
+ crypt, plain) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 push from "
MACSTR, MAC2STR(src_addr));
return -1;
@@ -1710,6 +1722,8 @@
{
struct ft_r0kh_r1kh_push_frame frame, f;
struct os_time now;
+ const u8 *plain;
+ u8 *crypt;
os_memset(&frame, 0, sizeof(frame));
frame.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
@@ -1732,9 +1746,13 @@
WPA_PUT_LE32(f.timestamp, now.sec);
f.pairwise = host_to_le16(pairwise);
os_memset(f.pad, 0, sizeof(f.pad));
+ plain = ((const u8 *) &f) + offsetof(struct ft_r0kh_r1kh_push_frame,
+ timestamp);
+ crypt = ((u8 *) &frame) + offsetof(struct ft_r0kh_r1kh_push_frame,
+ timestamp);
if (aes_wrap(r1kh->key, sizeof(r1kh->key),
(FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
- f.timestamp, frame.timestamp) < 0)
+ plain, crypt) < 0)
return;
wpa_ft_rrb_send(wpa_auth, r1kh->addr, (u8 *) &frame, sizeof(frame));
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 6ee9a4f..7f83207 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -249,12 +249,17 @@
struct sta_info *sta;
sta = ap_get_sta(hapd, addr);
- if (sta == NULL)
+ if (sta == NULL) {
+ wpa_printf(MSG_DEBUG, "AUTH_GET_MSK: Cannot find STA");
return -1;
+ }
key = ieee802_1x_get_key(sta->eapol_sm, &keylen);
- if (key == NULL)
+ if (key == NULL) {
+ wpa_printf(MSG_DEBUG, "AUTH_GET_MSK: Key is null, eapol_sm: %p",
+ sta->eapol_sm);
return -1;
+ }
if (keylen > *len)
keylen = *len;
@@ -299,6 +304,21 @@
struct sta_info *sta;
u32 flags = 0;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->ext_eapol_frame_io) {
+ size_t hex_len = 2 * data_len + 1;
+ char *hex = os_malloc(hex_len);
+
+ if (hex == NULL)
+ return -1;
+ wpa_snprintf_hex(hex, hex_len, data, data_len);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, "EAPOL-TX " MACSTR " %s",
+ MAC2STR(addr), hex);
+ os_free(hex);
+ return 0;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
sta = ap_get_sta(hapd, addr);
if (sta)
flags = hostapd_sta_flags_to_drv(sta->flags);
@@ -404,6 +424,21 @@
struct l2_ethhdr *buf;
int ret;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->ext_eapol_frame_io && proto == ETH_P_EAPOL) {
+ size_t hex_len = 2 * data_len + 1;
+ char *hex = os_malloc(hex_len);
+
+ if (hex == NULL)
+ return -1;
+ wpa_snprintf_hex(hex, hex_len, data, data_len);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, "EAPOL-TX " MACSTR " %s",
+ MAC2STR(dst), hex);
+ os_free(hex);
+ return 0;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
#ifdef CONFIG_IEEE80211R
if (proto == ETH_P_RRB && hapd->iface->interfaces &&
hapd->iface->interfaces->for_each_interface) {
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index 6960ff3..7b2cd3e 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -1,6 +1,6 @@
/*
* hostapd - IEEE 802.11i-2004 / WPA Authenticator: Internal definitions
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -58,6 +58,8 @@
Boolean GUpdateStationKeys;
u8 ANonce[WPA_NONCE_LEN];
u8 SNonce[WPA_NONCE_LEN];
+ u8 alt_SNonce[WPA_NONCE_LEN];
+ u8 alt_replay_counter[WPA_REPLAY_COUNTER_LEN];
u8 PMK[PMK_LEN];
struct wpa_ptk PTK;
Boolean PTK_valid;
@@ -84,6 +86,7 @@
unsigned int mgmt_frame_prot:1;
unsigned int rx_eapol_key_secure:1;
unsigned int update_snonce:1;
+ unsigned int alt_snonce_valid:1;
#ifdef CONFIG_IEEE80211R
unsigned int ft_completed:1;
unsigned int pmk_r1_name_valid:1;
@@ -227,11 +230,14 @@
int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
struct wpa_stsl_negotiation *neg);
void wpa_smk_error(struct wpa_authenticator *wpa_auth,
- struct wpa_state_machine *sm, struct wpa_eapol_key *key);
+ struct wpa_state_machine *sm,
+ const u8 *key_data, size_t key_data_len);
void wpa_smk_m1(struct wpa_authenticator *wpa_auth,
- struct wpa_state_machine *sm, struct wpa_eapol_key *key);
+ struct wpa_state_machine *sm, struct wpa_eapol_key *key,
+ const u8 *key_data, size_t key_data_len);
void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
- struct wpa_state_machine *sm, struct wpa_eapol_key *key);
+ struct wpa_state_machine *sm, struct wpa_eapol_key *key,
+ const u8 *key_data, size_t key_data_len);
#endif /* CONFIG_PEERKEY */
#ifdef CONFIG_IEEE80211R
@@ -242,7 +248,7 @@
u8 *buf, size_t len, const u8 *subelem,
size_t subelem_len);
int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
- struct wpa_ptk *ptk, size_t ptk_len);
+ struct wpa_ptk *ptk);
struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void);
void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache);
void wpa_ft_install_ptk(struct wpa_state_machine *sm);
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 1e4defc..f287297 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -1,6 +1,6 @@
/*
* hostapd - WPA/RSN IE and KDE definitions
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -200,6 +200,16 @@
num_suites++;
}
#endif /* CONFIG_SAE */
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
#ifdef CONFIG_RSN_TESTING
if (rsn_testing) {
@@ -477,6 +487,10 @@
selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
if (0) {
}
+ else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ selector = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192;
+ else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
+ selector = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
#ifdef CONFIG_IEEE80211R
else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
selector = RSN_AUTH_KEY_MGMT_FT_802_1X;
@@ -555,6 +569,10 @@
}
if (0) {
}
+ else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
+ else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B;
#ifdef CONFIG_IEEE80211R
else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index 6f16f50..9ba7aba 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -185,7 +185,7 @@
dev->model_number, dev->serial_number,
wps_dev_type_bin2str(dev->pri_dev_type, devtype,
sizeof(devtype)));
- if (len > 0 && len < (int) sizeof(txt))
+ if (!os_snprintf_error(sizeof(txt), len))
wpa_msg(hapd->msg_ctx, MSG_INFO, "%s", txt);
if (hapd->conf->wps_pin_requests) {
@@ -1049,7 +1049,7 @@
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X)
wps->auth_types |= WPS_AUTH_WPA2;
- if (conf->rsn_pairwise & WPA_CIPHER_CCMP)
+ 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 |= WPS_ENCR_TKIP;
@@ -1583,7 +1583,7 @@
int ret;
ret = os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%s", pin);
- if (ret < 0 || ret >= (int) sizeof(data.pin_txt))
+ if (os_snprintf_error(sizeof(data.pin_txt), ret))
return -1;
data.timeout = timeout;
return hostapd_wps_for_each(hapd, wps_ap_pin_set, &data);
diff --git a/src/ap/x_snoop.c b/src/ap/x_snoop.c
new file mode 100644
index 0000000..8f77015
--- /dev/null
+++ b/src/ap/x_snoop.c
@@ -0,0 +1,123 @@
+/*
+ * Generic Snooping for Proxy ARP
+ * Copyright (c) 2014, 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 "hostapd.h"
+#include "sta_info.h"
+#include "ap_drv_ops.h"
+#include "x_snoop.h"
+
+
+int x_snoop_init(struct hostapd_data *hapd)
+{
+ struct hostapd_bss_config *conf = hapd->conf;
+
+ if (!conf->isolate) {
+ wpa_printf(MSG_DEBUG,
+ "x_snoop: ap_isolate must be enabled for x_snoop");
+ return -1;
+ }
+
+ if (conf->bridge[0] == '\0') {
+ wpa_printf(MSG_DEBUG,
+ "x_snoop: Bridge must be configured for x_snoop");
+ return -1;
+ }
+
+ if (hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE,
+ 1)) {
+ wpa_printf(MSG_DEBUG,
+ "x_snoop: Failed to enable hairpin_mode on the bridge port");
+ return -1;
+ }
+
+ if (hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_PROXYARP, 1)) {
+ wpa_printf(MSG_DEBUG,
+ "x_snoop: Failed to enable proxyarp on the bridge port");
+ return -1;
+ }
+
+ if (hostapd_drv_br_set_net_param(hapd, DRV_BR_NET_PARAM_GARP_ACCEPT,
+ 1)) {
+ wpa_printf(MSG_DEBUG,
+ "x_snoop: Failed to enable accepting gratuitous ARP on the bridge");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+struct l2_packet_data *
+x_snoop_get_l2_packet(struct hostapd_data *hapd,
+ void (*handler)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len),
+ enum l2_packet_filter_type type)
+{
+ struct hostapd_bss_config *conf = hapd->conf;
+ struct l2_packet_data *l2;
+
+ l2 = l2_packet_init(conf->bridge, NULL, ETH_P_ALL, handler, hapd, 1);
+ if (l2 == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "x_snoop: Failed to initialize L2 packet processing %s",
+ strerror(errno));
+ return NULL;
+ }
+
+ if (l2_packet_set_packet_filter(l2, type)) {
+ wpa_printf(MSG_DEBUG,
+ "x_snoop: Failed to set L2 packet filter for type: %d",
+ type);
+ l2_packet_deinit(l2);
+ return NULL;
+ }
+
+ return l2;
+}
+
+
+void x_snoop_mcast_to_ucast_convert_send(struct hostapd_data *hapd,
+ struct sta_info *sta, u8 *buf,
+ size_t len)
+{
+ int res;
+ u8 addr[ETH_ALEN];
+ u8 *dst_addr = buf;
+
+ if (!(dst_addr[0] & 0x01))
+ return;
+
+ wpa_printf(MSG_EXCESSIVE, "x_snoop: Multicast-to-unicast conversion "
+ MACSTR " -> " MACSTR " (len %u)",
+ MAC2STR(dst_addr), MAC2STR(sta->addr), (unsigned int) len);
+
+ /* save the multicast destination address for restoring it later */
+ os_memcpy(addr, buf, ETH_ALEN);
+
+ os_memcpy(buf, sta->addr, ETH_ALEN);
+ res = l2_packet_send(hapd->sock_dhcp, NULL, 0, buf, len);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG,
+ "x_snoop: Failed to send mcast to ucast converted packet to "
+ MACSTR, MAC2STR(sta->addr));
+ }
+
+ /* restore the multicast destination address */
+ os_memcpy(buf, addr, ETH_ALEN);
+}
+
+
+void x_snoop_deinit(struct hostapd_data *hapd)
+{
+ hostapd_drv_br_set_net_param(hapd, DRV_BR_NET_PARAM_GARP_ACCEPT, 0);
+ hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_PROXYARP, 0);
+ hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE, 0);
+}
diff --git a/src/ap/x_snoop.h b/src/ap/x_snoop.h
new file mode 100644
index 0000000..e43a78d
--- /dev/null
+++ b/src/ap/x_snoop.h
@@ -0,0 +1,56 @@
+/*
+ * Generic Snooping for Proxy ARP
+ * Copyright (c) 2014, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef X_SNOOP_H
+#define X_SNOOP_H
+
+#include "l2_packet/l2_packet.h"
+
+#ifdef CONFIG_PROXYARP
+
+int x_snoop_init(struct hostapd_data *hapd);
+struct l2_packet_data *
+x_snoop_get_l2_packet(struct hostapd_data *hapd,
+ void (*handler)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len),
+ enum l2_packet_filter_type type);
+void x_snoop_mcast_to_ucast_convert_send(struct hostapd_data *hapd,
+ struct sta_info *sta, u8 *buf,
+ size_t len);
+void x_snoop_deinit(struct hostapd_data *hapd);
+
+#else /* CONFIG_PROXYARP */
+
+static inline int x_snoop_init(struct hostapd_data *hapd)
+{
+ return 0;
+}
+
+static inline struct l2_packet_data *
+x_snoop_get_l2_packet(struct hostapd_data *hapd,
+ void (*handler)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len),
+ enum l2_packet_filter_type type)
+{
+ return NULL;
+}
+
+static inline void
+x_snoop_mcast_to_ucast_convert_send(struct hostapd_data *hapd,
+ struct sta_info *sta, void *buf,
+ size_t len)
+{
+}
+
+static inline void x_snoop_deinit(struct hostapd_data *hapd)
+{
+}
+
+#endif /* CONFIG_PROXYARP */
+
+#endif /* X_SNOOP_H */
diff --git a/src/common/defs.h b/src/common/defs.h
index d4091e3..b5f4f80 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - Common definitions
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -49,6 +49,8 @@
#define WPA_KEY_MGMT_WAPI_CERT BIT(13)
#define WPA_KEY_MGMT_CCKM BIT(14)
#define WPA_KEY_MGMT_OSEN BIT(15)
+#define WPA_KEY_MGMT_IEEE8021X_SUITE_B BIT(16)
+#define WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 BIT(17)
static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
{
@@ -56,7 +58,9 @@
WPA_KEY_MGMT_FT_IEEE8021X |
WPA_KEY_MGMT_CCKM |
WPA_KEY_MGMT_OSEN |
- WPA_KEY_MGMT_IEEE8021X_SHA256));
+ WPA_KEY_MGMT_IEEE8021X_SHA256 |
+ WPA_KEY_MGMT_IEEE8021X_SUITE_B |
+ WPA_KEY_MGMT_IEEE8021X_SUITE_B_192));
}
static inline int wpa_key_mgmt_wpa_psk(int akm)
@@ -85,7 +89,19 @@
{
return !!(akm & (WPA_KEY_MGMT_PSK_SHA256 |
WPA_KEY_MGMT_IEEE8021X_SHA256 |
- WPA_KEY_MGMT_OSEN));
+ WPA_KEY_MGMT_OSEN |
+ WPA_KEY_MGMT_IEEE8021X_SUITE_B));
+}
+
+static inline int wpa_key_mgmt_sha384(int akm)
+{
+ return !!(akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192);
+}
+
+static inline int wpa_key_mgmt_suite_b(int akm)
+{
+ return !!(akm & (WPA_KEY_MGMT_IEEE8021X_SUITE_B |
+ WPA_KEY_MGMT_IEEE8021X_SUITE_B_192));
}
static inline int wpa_key_mgmt_wpa(int akm)
@@ -300,4 +316,14 @@
/* Maximum number of EAP methods to store for EAP server user information */
#define EAP_MAX_METHODS 8
+enum mesh_plink_state {
+ PLINK_LISTEN = 1,
+ PLINK_OPEN_SENT,
+ PLINK_OPEN_RCVD,
+ PLINK_CNF_RCVD,
+ PLINK_ESTAB,
+ PLINK_HOLDING,
+ PLINK_BLOCKED,
+};
+
#endif /* DEFS_H */
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
new file mode 100644
index 0000000..942380b
--- /dev/null
+++ b/src/common/hw_features_common.c
@@ -0,0 +1,356 @@
+/*
+ * Common hostapd/wpa_supplicant HW features
+ * 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 "includes.h"
+
+#include "common.h"
+#include "defs.h"
+#include "ieee802_11_defs.h"
+#include "ieee802_11_common.h"
+#include "hw_features_common.h"
+
+
+struct hostapd_channel_data * hw_get_channel_chan(struct hostapd_hw_modes *mode,
+ int chan, int *freq)
+{
+ int i;
+
+ if (freq)
+ *freq = 0;
+
+ if (!mode)
+ return NULL;
+
+ for (i = 0; i < mode->num_channels; i++) {
+ struct hostapd_channel_data *ch = &mode->channels[i];
+ if (ch->chan == chan) {
+ if (freq)
+ *freq = ch->freq;
+ return ch;
+ }
+ }
+
+ return NULL;
+}
+
+
+struct hostapd_channel_data * hw_get_channel_freq(struct hostapd_hw_modes *mode,
+ int freq, int *chan)
+{
+ int i;
+
+ if (chan)
+ *chan = 0;
+
+ if (!mode)
+ return NULL;
+
+ for (i = 0; i < mode->num_channels; i++) {
+ struct hostapd_channel_data *ch = &mode->channels[i];
+ if (ch->freq == freq) {
+ if (chan)
+ *chan = ch->chan;
+ return ch;
+ }
+ }
+
+ return NULL;
+}
+
+
+int hw_get_freq(struct hostapd_hw_modes *mode, int chan)
+{
+ int freq;
+
+ hw_get_channel_chan(mode, chan, &freq);
+
+ return freq;
+}
+
+
+int hw_get_chan(struct hostapd_hw_modes *mode, int freq)
+{
+ int chan;
+
+ hw_get_channel_freq(mode, freq, &chan);
+
+ return chan;
+}
+
+
+int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan,
+ int sec_chan)
+{
+ int ok, j, first;
+ int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
+ 184, 192 };
+ size_t k;
+
+ if (pri_chan == sec_chan || !sec_chan)
+ return 1; /* HT40 not used */
+
+ wpa_printf(MSG_DEBUG,
+ "HT40: control channel: %d secondary channel: %d",
+ pri_chan, sec_chan);
+
+ /* Verify that HT40 secondary channel is an allowed 20 MHz
+ * channel */
+ ok = 0;
+ for (j = 0; j < mode->num_channels; j++) {
+ struct hostapd_channel_data *chan = &mode->channels[j];
+ if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
+ chan->chan == sec_chan) {
+ ok = 1;
+ break;
+ }
+ }
+ if (!ok) {
+ wpa_printf(MSG_ERROR, "HT40 secondary channel %d not allowed",
+ sec_chan);
+ return 0;
+ }
+
+ /*
+ * Verify that HT40 primary,secondary channel pair is allowed per
+ * IEEE 802.11n Annex J. This is only needed for 5 GHz band since
+ * 2.4 GHz rules allow all cases where the secondary channel fits into
+ * the list of allowed channels (already checked above).
+ */
+ if (mode->mode != HOSTAPD_MODE_IEEE80211A)
+ return 1;
+
+ first = pri_chan < sec_chan ? pri_chan : sec_chan;
+
+ ok = 0;
+ for (k = 0; k < ARRAY_SIZE(allowed); k++) {
+ if (first == allowed[k]) {
+ ok = 1;
+ break;
+ }
+ }
+ if (!ok) {
+ wpa_printf(MSG_ERROR, "HT40 channel pair (%d, %d) not allowed",
+ pri_chan, sec_chan);
+ return 0;
+ }
+
+ return 1;
+}
+
+
+void get_pri_sec_chan(struct wpa_scan_res *bss, int *pri_chan, int *sec_chan)
+{
+ struct ieee80211_ht_operation *oper;
+ struct ieee802_11_elems elems;
+
+ *pri_chan = *sec_chan = 0;
+
+ ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0);
+ if (elems.ht_operation &&
+ elems.ht_operation_len >= sizeof(*oper)) {
+ oper = (struct ieee80211_ht_operation *) elems.ht_operation;
+ *pri_chan = oper->primary_chan;
+ if (oper->ht_param & HT_INFO_HT_PARAM_STA_CHNL_WIDTH) {
+ int sec = oper->ht_param &
+ HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK;
+ if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
+ *sec_chan = *pri_chan + 4;
+ else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
+ *sec_chan = *pri_chan - 4;
+ }
+ }
+}
+
+
+int check_40mhz_5g(struct hostapd_hw_modes *mode,
+ struct wpa_scan_results *scan_res, int pri_chan,
+ int sec_chan)
+{
+ int pri_freq, sec_freq, pri_bss, sec_bss;
+ int bss_pri_chan, bss_sec_chan;
+ size_t i;
+ int match;
+
+ if (!mode || !scan_res || !pri_chan || !sec_chan)
+ return 0;
+
+ if (pri_chan == sec_chan)
+ return 0;
+
+ pri_freq = hw_get_freq(mode, pri_chan);
+ sec_freq = hw_get_freq(mode, sec_chan);
+
+ /*
+ * Switch PRI/SEC channels if Beacons were detected on selected SEC
+ * channel, but not on selected PRI channel.
+ */
+ pri_bss = sec_bss = 0;
+ for (i = 0; i < scan_res->num; i++) {
+ struct wpa_scan_res *bss = scan_res->res[i];
+ if (bss->freq == pri_freq)
+ pri_bss++;
+ else if (bss->freq == sec_freq)
+ sec_bss++;
+ }
+ if (sec_bss && !pri_bss) {
+ wpa_printf(MSG_INFO,
+ "Switch own primary and secondary channel to get secondary channel with no Beacons from other BSSes");
+ return 2;
+ }
+
+ /*
+ * Match PRI/SEC channel with any existing HT40 BSS on the same
+ * channels that we are about to use (if already mixed order in
+ * existing BSSes, use own preference).
+ */
+ match = 0;
+ for (i = 0; i < scan_res->num; i++) {
+ struct wpa_scan_res *bss = scan_res->res[i];
+ get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan);
+ if (pri_chan == bss_pri_chan &&
+ sec_chan == bss_sec_chan) {
+ match = 1;
+ break;
+ }
+ }
+ if (!match) {
+ for (i = 0; i < scan_res->num; i++) {
+ struct wpa_scan_res *bss = scan_res->res[i];
+ get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan);
+ if (pri_chan == bss_sec_chan &&
+ sec_chan == bss_pri_chan) {
+ wpa_printf(MSG_INFO, "Switch own primary and "
+ "secondary channel due to BSS "
+ "overlap with " MACSTR,
+ MAC2STR(bss->bssid));
+ return 2;
+ }
+ }
+ }
+
+ return 1;
+}
+
+
+int check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq, int start, int end)
+{
+ struct ieee802_11_elems elems;
+ struct ieee80211_ht_operation *oper;
+
+ if (bss->freq < start || bss->freq > end || bss->freq == pri_freq)
+ return 0;
+
+ ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0);
+ if (!elems.ht_capabilities) {
+ wpa_printf(MSG_DEBUG, "Found overlapping legacy BSS: "
+ MACSTR " freq=%d", MAC2STR(bss->bssid), bss->freq);
+ return 1;
+ }
+
+ if (elems.ht_operation &&
+ elems.ht_operation_len >= sizeof(*oper)) {
+ oper = (struct ieee80211_ht_operation *) elems.ht_operation;
+ if (oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "Found overlapping 20 MHz HT BSS: "
+ MACSTR " freq=%d", MAC2STR(bss->bssid), bss->freq);
+ return 1;
+ }
+ return 0;
+}
+
+
+int check_40mhz_2g4(struct hostapd_hw_modes *mode,
+ struct wpa_scan_results *scan_res, int pri_chan,
+ int sec_chan)
+{
+ int pri_freq, sec_freq;
+ int affected_start, affected_end;
+ size_t i;
+
+ if (!mode || !scan_res || !pri_chan || !sec_chan)
+ return 0;
+
+ if (pri_chan == sec_chan)
+ return 0;
+
+ pri_freq = hw_get_freq(mode, pri_chan);
+ sec_freq = hw_get_freq(mode, sec_chan);
+
+ affected_start = (pri_freq + sec_freq) / 2 - 25;
+ affected_end = (pri_freq + sec_freq) / 2 + 25;
+ wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
+ affected_start, affected_end);
+ for (i = 0; i < scan_res->num; i++) {
+ struct wpa_scan_res *bss = scan_res->res[i];
+ int pri = bss->freq;
+ int sec = pri;
+ struct ieee802_11_elems elems;
+
+ /* Check for overlapping 20 MHz BSS */
+ if (check_20mhz_bss(bss, pri_freq, affected_start,
+ affected_end)) {
+ wpa_printf(MSG_DEBUG,
+ "Overlapping 20 MHz BSS is found");
+ return 0;
+ }
+
+ get_pri_sec_chan(bss, &pri_chan, &sec_chan);
+
+ if (sec_chan) {
+ if (sec_chan < pri_chan)
+ sec = pri - 20;
+ else
+ sec = pri + 20;
+ }
+
+ if ((pri < affected_start || pri > affected_end) &&
+ (sec < affected_start || sec > affected_end))
+ continue; /* not within affected channel range */
+
+ wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR
+ " freq=%d pri=%d sec=%d",
+ MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan);
+
+ if (sec_chan) {
+ if (pri_freq != pri || sec_freq != sec) {
+ wpa_printf(MSG_DEBUG,
+ "40 MHz pri/sec mismatch with BSS "
+ MACSTR
+ " <%d,%d> (chan=%d%c) vs. <%d,%d>",
+ MAC2STR(bss->bssid),
+ pri, sec, pri_chan,
+ sec > pri ? '+' : '-',
+ pri_freq, sec_freq);
+ return 0;
+ }
+ }
+
+ ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems,
+ 0);
+ if (elems.ht_capabilities &&
+ elems.ht_capabilities_len >=
+ sizeof(struct ieee80211_ht_capabilities)) {
+ struct ieee80211_ht_capabilities *ht_cap =
+ (struct ieee80211_ht_capabilities *)
+ elems.ht_capabilities;
+
+ if (le_to_host16(ht_cap->ht_capabilities_info) &
+ HT_CAP_INFO_40MHZ_INTOLERANT) {
+ wpa_printf(MSG_DEBUG,
+ "40 MHz Intolerant is set on channel %d in BSS "
+ MACSTR, pri, MAC2STR(bss->bssid));
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
diff --git a/src/common/hw_features_common.h b/src/common/hw_features_common.h
new file mode 100644
index 0000000..046fccd
--- /dev/null
+++ b/src/common/hw_features_common.h
@@ -0,0 +1,34 @@
+/*
+ * Common hostapd/wpa_supplicant HW features
+ * 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 HW_FEATURES_COMMON_H
+#define HW_FEATURES_COMMON_H
+
+#include "drivers/driver.h"
+
+struct hostapd_channel_data * hw_get_channel_chan(struct hostapd_hw_modes *mode,
+ int chan, int *freq);
+struct hostapd_channel_data * hw_get_channel_freq(struct hostapd_hw_modes *mode,
+ int freq, int *chan);
+
+int hw_get_freq(struct hostapd_hw_modes *mode, int chan);
+int hw_get_chan(struct hostapd_hw_modes *mode, int freq);
+
+int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan,
+ int sec_chan);
+void get_pri_sec_chan(struct wpa_scan_res *bss, int *pri_chan, int *sec_chan);
+int check_40mhz_5g(struct hostapd_hw_modes *mode,
+ struct wpa_scan_results *scan_res, int pri_chan,
+ int sec_chan);
+int check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq, int start, int end);
+int check_40mhz_2g4(struct hostapd_hw_modes *mode,
+ struct wpa_scan_results *scan_res, int pri_chan,
+ int sec_chan);
+
+#endif /* HW_FEATURES_COMMON_H */
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 173a400..ed8d466 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -128,6 +128,15 @@
elems->vendor_ht_cap = pos;
elems->vendor_ht_cap_len = elen;
break;
+ case VENDOR_VHT_TYPE:
+ if (elen > 4 &&
+ (pos[4] == VENDOR_VHT_SUBTYPE ||
+ pos[4] == VENDOR_VHT_SUBTYPE2)) {
+ elems->vendor_vht = pos;
+ elems->vendor_vht_len = elen;
+ } else
+ return -1;
+ break;
default:
wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom "
"information element ignored "
@@ -249,6 +258,18 @@
elems->ht_operation = pos;
elems->ht_operation_len = elen;
break;
+ case WLAN_EID_MESH_CONFIG:
+ elems->mesh_config = pos;
+ elems->mesh_config_len = elen;
+ break;
+ case WLAN_EID_MESH_ID:
+ elems->mesh_id = pos;
+ elems->mesh_id_len = elen;
+ break;
+ case WLAN_EID_PEER_MGMT:
+ elems->peer_mgmt = pos;
+ elems->peer_mgmt_len = elen;
+ break;
case WLAN_EID_VHT_CAP:
elems->vht_capabilities = pos;
elems->vht_capabilities_len = elen;
@@ -290,6 +311,16 @@
elems->ssid_list = pos;
elems->ssid_list_len = elen;
break;
+ case WLAN_EID_AMPE:
+ elems->ampe = pos;
+ elems->ampe_len = elen;
+ break;
+ case WLAN_EID_MIC:
+ elems->mic = pos;
+ elems->mic_len = elen;
+ /* after mic everything is encrypted, so stop. */
+ left = elen;
+ break;
default:
unknown++;
if (!show_errors)
@@ -515,6 +546,286 @@
}
+static const char *us_op_class_cc[] = {
+ "US", "CA", NULL
+};
+
+static const char *eu_op_class_cc[] = {
+ "AL", "AM", "AT", "AZ", "BA", "BE", "BG", "BY", "CH", "CY", "CZ", "DE",
+ "DK", "EE", "EL", "ES", "FI", "FR", "GE", "HR", "HU", "IE", "IS", "IT",
+ "LI", "LT", "LU", "LV", "MD", "ME", "MK", "MT", "NL", "NO", "PL", "PT",
+ "RO", "RS", "RU", "SE", "SI", "SK", "TR", "UA", "UK", NULL
+};
+
+static const char *jp_op_class_cc[] = {
+ "JP", NULL
+};
+
+static const char *cn_op_class_cc[] = {
+ "CN", "CA", NULL
+};
+
+
+static int country_match(const char *cc[], const char *country)
+{
+ int i;
+
+ if (country == NULL)
+ return 0;
+ for (i = 0; cc[i]; i++) {
+ if (cc[i][0] == country[0] && cc[i][1] == country[1])
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int ieee80211_chan_to_freq_us(u8 op_class, u8 chan)
+{
+ switch (op_class) {
+ case 12: /* channels 1..11 */
+ case 32: /* channels 1..7; 40 MHz */
+ case 33: /* channels 5..11; 40 MHz */
+ if (chan < 1 || chan > 11)
+ return -1;
+ return 2407 + 5 * chan;
+ case 1: /* channels 36,40,44,48 */
+ case 2: /* channels 52,56,60,64; dfs */
+ case 22: /* channels 36,44; 40 MHz */
+ case 23: /* channels 52,60; 40 MHz */
+ case 27: /* channels 40,48; 40 MHz */
+ case 28: /* channels 56,64; 40 MHz */
+ if (chan < 36 || chan > 64)
+ return -1;
+ return 5000 + 5 * chan;
+ case 4: /* channels 100-144 */
+ case 24: /* channels 100-140; 40 MHz */
+ if (chan < 100 || chan > 144)
+ return -1;
+ return 5000 + 5 * chan;
+ case 3: /* channels 149,153,157,161 */
+ case 25: /* channels 149,157; 40 MHz */
+ case 26: /* channels 149,157; 40 MHz */
+ case 30: /* channels 153,161; 40 MHz */
+ case 31: /* channels 153,161; 40 MHz */
+ if (chan < 149 || chan > 161)
+ return -1;
+ return 5000 + 5 * chan;
+ case 34: /* 60 GHz band, channels 1..3 */
+ if (chan < 1 || chan > 3)
+ return -1;
+ return 56160 + 2160 * chan;
+ }
+ return -1;
+}
+
+
+static int ieee80211_chan_to_freq_eu(u8 op_class, u8 chan)
+{
+ switch (op_class) {
+ case 4: /* channels 1..13 */
+ case 11: /* channels 1..9; 40 MHz */
+ case 12: /* channels 5..13; 40 MHz */
+ if (chan < 1 || chan > 13)
+ return -1;
+ return 2407 + 5 * chan;
+ case 1: /* channels 36,40,44,48 */
+ case 2: /* channels 52,56,60,64; dfs */
+ case 5: /* channels 36,44; 40 MHz */
+ case 6: /* channels 52,60; 40 MHz */
+ case 8: /* channels 40,48; 40 MHz */
+ case 9: /* channels 56,64; 40 MHz */
+ if (chan < 36 || chan > 64)
+ return -1;
+ return 5000 + 5 * chan;
+ case 3: /* channels 100-140 */
+ case 7: /* channels 100-132; 40 MHz */
+ case 10: /* channels 104-136; 40 MHz */
+ case 16: /* channels 100-140 */
+ if (chan < 100 || chan > 140)
+ return -1;
+ return 5000 + 5 * chan;
+ case 17: /* channels 149,153,157,161,165,169 */
+ if (chan < 149 || chan > 169)
+ return -1;
+ return 5000 + 5 * chan;
+ case 18: /* 60 GHz band, channels 1..4 */
+ if (chan < 1 || chan > 4)
+ return -1;
+ return 56160 + 2160 * chan;
+ }
+ return -1;
+}
+
+
+static int ieee80211_chan_to_freq_jp(u8 op_class, u8 chan)
+{
+ switch (op_class) {
+ case 30: /* channels 1..13 */
+ case 56: /* channels 1..9; 40 MHz */
+ case 57: /* channels 5..13; 40 MHz */
+ if (chan < 1 || chan > 13)
+ return -1;
+ return 2407 + 5 * chan;
+ case 31: /* channel 14 */
+ if (chan != 14)
+ return -1;
+ return 2414 + 5 * chan;
+ case 1: /* channels 34,38,42,46(old) or 36,40,44,48 */
+ case 32: /* channels 52,56,60,64 */
+ case 33: /* channels 52,56,60,64 */
+ case 36: /* channels 36,44; 40 MHz */
+ case 37: /* channels 52,60; 40 MHz */
+ case 38: /* channels 52,60; 40 MHz */
+ case 41: /* channels 40,48; 40 MHz */
+ case 42: /* channels 56,64; 40 MHz */
+ case 43: /* channels 56,64; 40 MHz */
+ if (chan < 34 || chan > 64)
+ return -1;
+ return 5000 + 5 * chan;
+ case 34: /* channels 100-140 */
+ case 35: /* channels 100-140 */
+ case 39: /* channels 100-132; 40 MHz */
+ case 40: /* channels 100-132; 40 MHz */
+ case 44: /* channels 104-136; 40 MHz */
+ case 45: /* channels 104-136; 40 MHz */
+ case 58: /* channels 100-140 */
+ if (chan < 100 || chan > 140)
+ return -1;
+ return 5000 + 5 * chan;
+ case 59: /* 60 GHz band, channels 1..4 */
+ if (chan < 1 || chan > 3)
+ return -1;
+ return 56160 + 2160 * chan;
+ }
+ return -1;
+}
+
+
+static int ieee80211_chan_to_freq_cn(u8 op_class, u8 chan)
+{
+ switch (op_class) {
+ case 7: /* channels 1..13 */
+ case 8: /* channels 1..9; 40 MHz */
+ case 9: /* channels 5..13; 40 MHz */
+ if (chan < 1 || chan > 13)
+ return -1;
+ return 2407 + 5 * chan;
+ case 1: /* channels 36,40,44,48 */
+ case 2: /* channels 52,56,60,64; dfs */
+ case 4: /* channels 36,44; 40 MHz */
+ case 5: /* channels 52,60; 40 MHz */
+ if (chan < 36 || chan > 64)
+ return -1;
+ return 5000 + 5 * chan;
+ case 3: /* channels 149,153,157,161,165 */
+ case 6: /* channels 149,157; 40 MHz */
+ if (chan < 149 || chan > 165)
+ return -1;
+ return 5000 + 5 * chan;
+ }
+ return -1;
+}
+
+
+static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan)
+{
+ /* Table E-4 in IEEE Std 802.11-2012 - Global operating classes */
+ switch (op_class) {
+ case 81:
+ /* channels 1..13 */
+ if (chan < 1 || chan > 13)
+ return -1;
+ return 2407 + 5 * chan;
+ case 82:
+ /* channel 14 */
+ if (chan != 14)
+ return -1;
+ return 2414 + 5 * chan;
+ case 83: /* channels 1..9; 40 MHz */
+ case 84: /* channels 5..13; 40 MHz */
+ if (chan < 1 || chan > 13)
+ return -1;
+ return 2407 + 5 * chan;
+ case 115: /* channels 36,40,44,48; indoor only */
+ case 116: /* channels 36,44; 40 MHz; indoor only */
+ case 117: /* channels 40,48; 40 MHz; indoor only */
+ case 118: /* channels 52,56,60,64; dfs */
+ case 119: /* channels 52,60; 40 MHz; dfs */
+ case 120: /* channels 56,64; 40 MHz; dfs */
+ if (chan < 36 || chan > 64)
+ return -1;
+ return 5000 + 5 * chan;
+ case 121: /* channels 100-140 */
+ case 122: /* channels 100-142; 40 MHz */
+ case 123: /* channels 104-136; 40 MHz */
+ if (chan < 100 || chan > 140)
+ return -1;
+ return 5000 + 5 * chan;
+ case 124: /* channels 149,153,157,161 */
+ case 125: /* channels 149,153,157,161,165,169 */
+ case 126: /* channels 149,157; 40 MHz */
+ case 127: /* channels 153,161; 40 MHz */
+ if (chan < 149 || chan > 161)
+ return -1;
+ return 5000 + 5 * chan;
+ case 128: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
+ case 130: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
+ if (chan < 36 || chan > 161)
+ return -1;
+ return 5000 + 5 * chan;
+ case 129: /* center freqs 50, 114; 160 MHz */
+ if (chan < 50 || chan > 114)
+ return -1;
+ return 5000 + 5 * chan;
+ case 180: /* 60 GHz band, channels 1..4 */
+ if (chan < 1 || chan > 4)
+ return -1;
+ return 56160 + 2160 * chan;
+ }
+ return -1;
+}
+
+/**
+ * ieee80211_chan_to_freq - Convert channel info to frequency
+ * @country: Country code, if known; otherwise, global operating class is used
+ * @op_class: Operating class
+ * @chan: Channel number
+ * Returns: Frequency in MHz or -1 if the specified channel is unknown
+ */
+int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan)
+{
+ int freq;
+
+ if (country_match(us_op_class_cc, country)) {
+ freq = ieee80211_chan_to_freq_us(op_class, chan);
+ if (freq > 0)
+ return freq;
+ }
+
+ if (country_match(eu_op_class_cc, country)) {
+ freq = ieee80211_chan_to_freq_eu(op_class, chan);
+ if (freq > 0)
+ return freq;
+ }
+
+ if (country_match(jp_op_class_cc, country)) {
+ freq = ieee80211_chan_to_freq_jp(op_class, chan);
+ if (freq > 0)
+ return freq;
+ }
+
+ if (country_match(cn_op_class_cc, country)) {
+ freq = ieee80211_chan_to_freq_cn(op_class, chan);
+ if (freq > 0)
+ return freq;
+ }
+
+ return ieee80211_chan_to_freq_global(op_class, chan);
+}
+
+
static int is_11b(u8 rate)
{
return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16;
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index cf83057..05fe32b 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -28,10 +28,14 @@
const u8 *timeout_int;
const u8 *ht_capabilities;
const u8 *ht_operation;
+ const u8 *mesh_config;
+ const u8 *mesh_id;
+ const u8 *peer_mgmt;
const u8 *vht_capabilities;
const u8 *vht_operation;
const u8 *vht_opmode_notif;
const u8 *vendor_ht_cap;
+ const u8 *vendor_vht;
const u8 *p2p;
const u8 *wfd;
const u8 *link_id;
@@ -42,6 +46,8 @@
const u8 *bss_max_idle_period;
const u8 *ssid_list;
const u8 *osen;
+ const u8 *ampe;
+ const u8 *mic;
u8 ssid_len;
u8 supp_rates_len;
@@ -60,9 +66,13 @@
u8 timeout_int_len;
u8 ht_capabilities_len;
u8 ht_operation_len;
+ u8 mesh_config_len;
+ u8 mesh_id_len;
+ u8 peer_mgmt_len;
u8 vht_capabilities_len;
u8 vht_operation_len;
u8 vendor_ht_cap_len;
+ u8 vendor_vht_len;
u8 p2p_len;
u8 wfd_len;
u8 interworking_len;
@@ -71,6 +81,8 @@
u8 ext_capab_len;
u8 ssid_list_len;
u8 osen_len;
+ u8 ampe_len;
+ u8 mic_len;
};
typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
@@ -95,6 +107,7 @@
int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
const char *name, const char *val);
enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel);
+int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan);
int supp_rates_11b_only(struct ieee802_11_elems *elems);
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 6de71e9..97a4537 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -1,6 +1,6 @@
/*
* IEEE 802.11 Frame type definitions
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
* Copyright (c) 2007-2008 Intel Corporation
*
* This software may be distributed under the terms of the BSD license.
@@ -25,6 +25,8 @@
#define WLAN_FC_GET_TYPE(fc) (((fc) & 0x000c) >> 2)
#define WLAN_FC_GET_STYPE(fc) (((fc) & 0x00f0) >> 4)
+#define WLAN_INVALID_MGMT_SEQ 0xFFFF
+
#define WLAN_GET_SEQ_FRAG(seq) ((seq) & (BIT(3) | BIT(2) | BIT(1) | BIT(0)))
#define WLAN_GET_SEQ_SEQ(seq) \
(((seq) & (~(BIT(3) | BIT(2) | BIT(1) | BIT(0)))) >> 4)
@@ -194,6 +196,16 @@
#define WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED 26
/* IEEE 802.11e */
#define WLAN_REASON_DISASSOC_LOW_ACK 34
+/* IEEE 802.11s */
+#define WLAN_REASON_MESH_PEERING_CANCELLED 52
+#define WLAN_REASON_MESH_MAX_PEERS 53
+#define WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION 54
+#define WLAN_REASON_MESH_CLOSE_RCVD 55
+#define WLAN_REASON_MESH_MAX_RETRIES 56
+#define WLAN_REASON_MESH_CONFIRM_TIMEOUT 57
+#define WLAN_REASON_MESH_INVALID_GTK 58
+#define WLAN_REASON_MESH_INCONSISTENT_PARAMS 59
+#define WLAN_REASON_MESH_INVALID_SECURITY_CAP 60
/* Information Element IDs */
@@ -234,6 +246,7 @@
#define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62
#define WLAN_EID_WAPI 68
#define WLAN_EID_TIME_ADVERTISEMENT 69
+#define WLAN_EID_RRM_ENABLED_CAPABILITIES 70
#define WLAN_EID_20_40_BSS_COEXISTENCE 72
#define WLAN_EID_20_40_BSS_INTOLERANT 73
#define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74
@@ -249,7 +262,12 @@
#define WLAN_EID_ADV_PROTO 108
#define WLAN_EID_QOS_MAP_SET 110
#define WLAN_EID_ROAMING_CONSORTIUM 111
+#define WLAN_EID_MESH_CONFIG 113
+#define WLAN_EID_MESH_ID 114
+#define WLAN_EID_PEER_MGMT 117
#define WLAN_EID_EXT_CAPAB 127
+#define WLAN_EID_AMPE 139
+#define WLAN_EID_MIC 140
#define WLAN_EID_CCKM 156
#define WLAN_EID_VHT_CAP 191
#define WLAN_EID_VHT_OPERATION 192
@@ -277,6 +295,7 @@
#define WLAN_ACTION_WNM 10
#define WLAN_ACTION_UNPROTECTED_WNM 11
#define WLAN_ACTION_TDLS 12
+#define WLAN_ACTION_SELF_PROTECTED 15
#define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */
#define WLAN_ACTION_VENDOR_SPECIFIC 127
@@ -321,6 +340,19 @@
#define WLAN_TDLS_PEER_TRAFFIC_RESPONSE 9
#define WLAN_TDLS_DISCOVERY_REQUEST 10
+/* Radio Measurement Action codes */
+#define WLAN_RRM_RADIO_MEASUREMENT_REQUEST 0
+#define WLAN_RRM_RADIO_MEASUREMENT_REPORT 1
+#define WLAN_RRM_LINK_MEASUREMENT_REQUEST 2
+#define WLAN_RRM_LINK_MEASUREMENT_REPORT 3
+#define WLAN_RRM_NEIGHBOR_REPORT_REQUEST 4
+#define WLAN_RRM_NEIGHBOR_REPORT_RESPONSE 5
+
+/* Radio Measurement capabilities (from RRM Capabilities IE) */
+/* byte 1 (out of 5) */
+#define WLAN_RRM_CAPS_LINK_MEASUREMENT BIT(0)
+#define WLAN_RRM_CAPS_NEIGHBOR_REPORT BIT(1)
+
/* Timeout Interval Type */
#define WLAN_TIMEOUT_REASSOC_DEADLINE 1
#define WLAN_TIMEOUT_KEY_LIFETIME 2
@@ -577,6 +609,10 @@
* Entries (optional) */
u8 variable[0];
} STRUCT_PACKED bss_tm_query;
+ struct {
+ u8 action; /* 15 */
+ u8 variable[0];
+ } STRUCT_PACKED slf_prot_action;
} u;
} STRUCT_PACKED action;
} u;
@@ -638,6 +674,15 @@
le16 vht_basic_mcs_set;
} STRUCT_PACKED;
+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];
+} STRUCT_PACKED;
+
#ifdef _MSC_VER
#pragma pack(pop)
#endif /* _MSC_VER */
@@ -754,6 +799,7 @@
#define VHT_CAP_MAX_MPDU_LENGTH_7991 ((u32) BIT(0))
#define VHT_CAP_MAX_MPDU_LENGTH_11454 ((u32) BIT(1))
#define VHT_CAP_MAX_MPDU_LENGTH_MASK ((u32) BIT(0) | BIT(1))
+#define VHT_CAP_MAX_MPDU_LENGTH_MASK_SHIFT 0
#define VHT_CAP_SUPP_CHAN_WIDTH_160MHZ ((u32) BIT(2))
#define VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ ((u32) BIT(3))
#define VHT_CAP_SUPP_CHAN_WIDTH_MASK ((u32) BIT(2) | BIT(3))
@@ -767,13 +813,16 @@
#define VHT_CAP_RXSTBC_4 ((u32) BIT(10))
#define VHT_CAP_RXSTBC_MASK ((u32) BIT(8) | BIT(9) | \
BIT(10))
+#define VHT_CAP_RXSTBC_MASK_SHIFT 8
#define VHT_CAP_SU_BEAMFORMER_CAPABLE ((u32) BIT(11))
#define VHT_CAP_SU_BEAMFORMEE_CAPABLE ((u32) BIT(12))
#define VHT_CAP_BEAMFORMEE_STS_MAX ((u32) BIT(13) | \
BIT(14) | BIT(15))
+#define VHT_CAP_BEAMFORMEE_STS_MAX_SHIFT 13
#define VHT_CAP_BEAMFORMEE_STS_OFFSET 13
#define VHT_CAP_SOUNDING_DIMENSION_MAX ((u32) BIT(16) | \
BIT(17) | BIT(18))
+#define VHT_CAP_SOUNDING_DIMENSION_MAX_SHIFT 16
#define VHT_CAP_SOUNDING_DIMENSION_OFFSET 16
#define VHT_CAP_MU_BEAMFORMER_CAPABLE ((u32) BIT(19))
#define VHT_CAP_MU_BEAMFORMEE_CAPABLE ((u32) BIT(20))
@@ -788,6 +837,7 @@
#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_6 ((u32) BIT(24) | BIT(25))
#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX ((u32) BIT(23) | \
BIT(24) | BIT(25))
+#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX_SHIFT 23
#define VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB ((u32) BIT(27))
#define VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB ((u32) BIT(26) | BIT(27))
#define VHT_CAP_RX_ANTENNA_PATTERN ((u32) BIT(28))
@@ -855,6 +905,8 @@
} STRUCT_PACKED;
+#define WMM_QOSINFO_AP_UAPSD 0x80
+
#define WMM_QOSINFO_STA_AC_MASK 0x0f
#define WMM_QOSINFO_STA_SP_MASK 0x03
#define WMM_QOSINFO_STA_SP_SHIFT 5
@@ -922,11 +974,12 @@
/* Access Categories / ACI to AC coding */
-enum {
+enum wmm_ac {
WMM_AC_BE = 0 /* Best Effort */,
WMM_AC_BK = 1 /* Background */,
WMM_AC_VI = 2 /* Video */,
- WMM_AC_VO = 3 /* Voice */
+ WMM_AC_VO = 3 /* Voice */,
+ WMM_AC_NUM = 4
};
@@ -1087,8 +1140,24 @@
WFD_SUBELEM_SESSION_INFO = 9
};
+/* 802.11s */
+#define MESH_SYNC_METHOD_NEIGHBOR_OFFSET 1
+#define MESH_SYNC_METHOD_VENDOR 255
+#define MESH_PATH_PROTOCOL_HWMP 1
+#define MESH_PATH_PROTOCOL_VENDOR 255
+#define MESH_PATH_METRIC_AIRTIME 1
+#define MESH_PATH_METRIC_VENDOR 255
+
+enum plink_action_field {
+ PLINK_OPEN = 1,
+ PLINK_CONFIRM,
+ PLINK_CLOSE
+};
#define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */
+#define VENDOR_VHT_TYPE 0x04
+#define VENDOR_VHT_SUBTYPE 0x08
+#define VENDOR_VHT_SUBTYPE2 0x00
#define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */
@@ -1122,6 +1191,8 @@
#define WLAN_AKM_SUITE_FT_PSK 0x000FAC04
#define WLAN_AKM_SUITE_8021X_SHA256 0x000FAC05
#define WLAN_AKM_SUITE_PSK_SHA256 0x000FAC06
+#define WLAN_AKM_SUITE_8021X_SUITE_B 0x000FAC11
+#define WLAN_AKM_SUITE_8021X_SUITE_B_192 0x000FAC12
#define WLAN_AKM_SUITE_CCKM 0x00409600
#define WLAN_AKM_SUITE_OSEN 0x506f9a01
@@ -1247,4 +1318,30 @@
#define CHAN_SWITCH_MODE_ALLOW_TX 0
#define CHAN_SWITCH_MODE_BLOCK_TX 1
+struct tpc_report {
+ u8 eid;
+ u8 len;
+ u8 tx_power;
+ u8 link_margin;
+} STRUCT_PACKED;
+
+/* IEEE Std 802.11-2012, 8.5.7.4 - Link Measurement Request frame format */
+struct rrm_link_measurement_request {
+ u8 dialog_token;
+ s8 tx_power;
+ s8 max_tp;
+ u8 variable[0];
+} STRUCT_PACKED;
+
+/* IEEE Std 802.11-2012, 8.5.7.5 - Link Measurement Report frame format */
+struct rrm_link_measurement_report {
+ u8 dialog_token;
+ struct tpc_report tpc;
+ u8 rx_ant_id;
+ u8 tx_ant_id;
+ u8 rcpi;
+ u8 rsni;
+ u8 variable[0];
+} STRUCT_PACKED;
+
#endif /* IEEE802_11_DEFS_H */
diff --git a/src/common/privsep_commands.h b/src/common/privsep_commands.h
index 858b51d..4dc34c4 100644
--- a/src/common/privsep_commands.h
+++ b/src/common/privsep_commands.h
@@ -31,7 +31,9 @@
u8 bssid[ETH_ALEN];
u8 ssid[32];
size_t ssid_len;
+ int hwmode;
int freq;
+ int channel;
int pairwise_suite;
int group_suite;
int key_mgmt_suite;
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index ad3bdfd..ec1be86 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -50,6 +50,25 @@
* @QCA_NL80211_VENDOR_SUBCMD_NAN: NAN command/event which is used to pass
* NAN Request/Response and NAN Indication messages. These messages are
* interpreted between the framework and the firmware component.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY: Set key operation that can be
+ * used to configure PMK to the driver even when not connected. This can
+ * be used to request offloading of key management operations. Only used
+ * if device supports QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH: An extended version of
+ * NL80211_CMD_ROAM event with optional attributes including information
+ * from offloaded key management operation. Uses
+ * enum qca_wlan_vendor_attr_roam_auth attributes. Only used
+ * if device supports QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_DO_ACS: ACS command/event which is used to
+ * invoke the ACS function in device and pass selected channels to
+ * hostapd.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES: Command to get the features
+ * supported by the driver. enum qca_wlan_vendor_features defines
+ * the possible features.
*/
enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@@ -60,7 +79,42 @@
QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY = 11,
QCA_NL80211_VENDOR_SUBCMD_NAN = 12,
QCA_NL80211_VENDOR_SUBMCD_STATS_EXT = 13,
- /* 14..49 - reserved for QCA */
+ QCA_NL80211_VENDOR_SUBCMD_LL_STATS_SET = 14,
+ QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET = 15,
+ QCA_NL80211_VENDOR_SUBCMD_LL_STATS_CLR = 16,
+ QCA_NL80211_VENDOR_SUBCMD_LL_STATS_RADIO_RESULTS = 17,
+ QCA_NL80211_VENDOR_SUBCMD_LL_STATS_IFACE_RESULTS = 18,
+ QCA_NL80211_VENDOR_SUBCMD_LL_STATS_PEERS_RESULTS = 19,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_START = 20,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_STOP = 21,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_GET_VALID_CHANNELS = 22,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_GET_CAPABILITIES = 23,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_GET_CACHED_RESULTS = 24,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_SCAN_RESULTS_AVAILABLE = 25,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_FULL_SCAN_RESULT = 26,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_SCAN_EVENT = 27,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_HOTLIST_AP_FOUND = 28,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_SET_BSSID_HOTLIST = 29,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_RESET_BSSID_HOTLIST = 30,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_SIGNIFICANT_CHANGE = 31,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_SET_SIGNIFICANT_CHANGE = 32,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_RESET_SIGNIFICANT_CHANGE = 33,
+ QCA_NL80211_VENDOR_SUBCMD_TDLS_ENABLE = 34,
+ QCA_NL80211_VENDOR_SUBCMD_TDLS_DISABLE = 35,
+ QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_STATUS = 36,
+ QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE = 37,
+ QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_FEATURES = 38,
+ QCA_NL80211_VENDOR_SUBCMD_SCANNING_MAC_OUI = 39,
+ QCA_NL80211_VENDOR_SUBCMD_NO_DFS_FLAG = 40,
+ QCA_NL80211_VENDOR_SUBCMD_GSCAN_HOTLIST_AP_LOST = 41,
+ QCA_NL80211_VENDOR_SUBCMD_GET_CONCURRENCY_MATRIX = 42,
+ /* 43..49 - reserved for QCA */
+ QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY = 50,
+ QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH = 51,
+ QCA_NL80211_VENDOR_SUBCMD_APFIND = 52,
+ /* 53 - reserved for QCA */
+ QCA_NL80211_VENDOR_SUBCMD_DO_ACS = 54,
+ QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES = 55,
};
@@ -78,6 +132,8 @@
* by enum qca_roaming_policy. */
QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY = 5,
QCA_WLAN_VENDOR_ATTR_MAC_ADDR = 6,
+ /* used by QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES */
+ QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS = 7,
/* keep last */
QCA_WLAN_VENDOR_ATTR_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_AFTER_LAST - 1,
@@ -89,4 +145,53 @@
QCA_ROAMING_ALLOWED_WITHIN_ESS,
};
+enum qca_wlan_vendor_attr_roam_auth {
+ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID,
+ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE,
+ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE,
+ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED,
+ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_KEY_REPLAY_CTR,
+ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KCK,
+ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KEK,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MAX =
+ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AFTER_LAST - 1
+};
+
+enum qca_wlan_vendor_attr_acs_offload {
+ QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL,
+ QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL,
+ QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE,
+ QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED,
+ QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_ACS_MAX =
+ QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST - 1
+};
+
+enum qca_wlan_vendor_acs_hw_mode {
+ QCA_ACS_MODE_IEEE80211B,
+ QCA_ACS_MODE_IEEE80211G,
+ QCA_ACS_MODE_IEEE80211A,
+ QCA_ACS_MODE_IEEE80211AD,
+};
+
+/**
+ * enum qca_wlan_vendor_features - Vendor device/driver feature flags
+ *
+ * @QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD: Device supports key
+ * management offload, a mechanism where the station's firmware
+ * does the exchange with the AP to establish the temporal keys
+ * after roaming, rather than having the user space wpa_supplicant do it.
+ * @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits
+ */
+enum qca_wlan_vendor_features {
+ QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD = 0,
+ NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
+};
+
#endif /* QCA_VENDOR_H */
diff --git a/src/common/sae.c b/src/common/sae.c
index b67623f..5888958 100644
--- a/src/common/sae.c
+++ b/src/common/sae.c
@@ -87,7 +87,8 @@
crypto_ec_point_deinit(tmp->pwe_ecc, 1);
crypto_ec_point_deinit(tmp->own_commit_element_ecc, 0);
crypto_ec_point_deinit(tmp->peer_commit_element_ecc, 0);
- os_free(sae->tmp);
+ wpabuf_free(tmp->anti_clogging_token);
+ bin_clear_free(tmp, sizeof(*tmp));
sae->tmp = NULL;
}
@@ -623,8 +624,10 @@
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));
+ 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_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);
@@ -656,8 +659,11 @@
return;
wpabuf_put_le16(buf, sae->group); /* Finite Cyclic Group */
- if (token)
+ if (token) {
wpabuf_put_buf(buf, token);
+ wpa_hexdump(MSG_DEBUG, "SAE: Anti-clogging token",
+ wpabuf_head(token), wpabuf_len(token));
+ }
pos = wpabuf_put(buf, sae->tmp->prime_len);
crypto_bignum_to_bin(sae->tmp->own_commit_scalar, pos,
sae->tmp->prime_len, sae->tmp->prime_len);
@@ -682,8 +688,7 @@
}
-static u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups,
- u16 group)
+u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, u16 group)
{
if (allowed_groups) {
int i;
diff --git a/src/common/sae.h b/src/common/sae.h
index d82a98e..3ebf40c 100644
--- a/src/common/sae.h
+++ b/src/common/sae.h
@@ -35,6 +35,7 @@
const struct crypto_bignum *order;
struct crypto_bignum *prime_buf;
struct crypto_bignum *order_buf;
+ struct wpabuf *anti_clogging_token;
};
struct sae_data {
@@ -43,6 +44,7 @@
u8 pmk[SAE_PMK_LEN];
struct crypto_bignum *peer_commit_scalar;
int group;
+ int sync;
struct sae_temporary_data *tmp;
};
@@ -60,5 +62,6 @@
const u8 **token, size_t *token_len, int *allowed_groups);
void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf);
int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len);
+u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, u16 group);
#endif /* SAE_H */
diff --git a/src/common/version.h b/src/common/version.h
index 726289d..c662270 100644
--- a/src/common/version.h
+++ b/src/common/version.h
@@ -5,6 +5,6 @@
#define VERSION_STR_POSTFIX ""
#endif /* VERSION_STR_POSTFIX */
-#define VERSION_STR "2.3" VERSION_STR_POSTFIX
+#define VERSION_STR "2.4-devel" VERSION_STR_POSTFIX
#endif /* VERSION_H */
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index 998a51a..de81d53 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -1,6 +1,6 @@
/*
* WPA/RSN - Shared functions for supplicant and authenticator
- * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -12,17 +12,43 @@
#include "crypto/md5.h"
#include "crypto/sha1.h"
#include "crypto/sha256.h"
+#include "crypto/sha384.h"
#include "crypto/aes_wrap.h"
#include "crypto/crypto.h"
-#include "drivers/driver.h"
#include "ieee802_11_defs.h"
#include "defs.h"
#include "wpa_common.h"
+static unsigned int wpa_kck_len(int akmp)
+{
+ if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ return 24;
+ return 16;
+}
+
+
+static unsigned int wpa_kek_len(int akmp)
+{
+ if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ return 32;
+ return 16;
+}
+
+
+unsigned int wpa_mic_len(int akmp)
+{
+ if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ return 24;
+ return 16;
+}
+
+
/**
* wpa_eapol_key_mic - Calculate EAPOL-Key MIC
* @key: EAPOL-Key Key Confirmation Key (KCK)
+ * @key_len: KCK length in octets
+ * @akmp: WPA_KEY_MGMT_* used in key derivation
* @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*)
* @buf: Pointer to the beginning of the EAPOL header (version field)
* @len: Length of the EAPOL frame (from EAPOL header to the end of the frame)
@@ -38,18 +64,18 @@
* happened during final editing of the standard and the correct behavior is
* defined in the last draft (IEEE 802.11i/D10).
*/
-int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
- u8 *mic)
+int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver,
+ const u8 *buf, size_t len, u8 *mic)
{
- u8 hash[SHA1_MAC_LEN];
+ u8 hash[SHA384_MAC_LEN];
switch (ver) {
#ifndef CONFIG_FIPS
case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4:
- return hmac_md5(key, 16, buf, len, mic);
+ return hmac_md5(key, key_len, buf, len, mic);
#endif /* CONFIG_FIPS */
case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES:
- if (hmac_sha1(key, 16, buf, len, hash))
+ if (hmac_sha1(key, key_len, buf, len, hash))
return -1;
os_memcpy(mic, hash, MD5_MAC_LEN);
break;
@@ -57,11 +83,30 @@
case WPA_KEY_INFO_TYPE_AES_128_CMAC:
return omac1_aes_128(key, buf, len, mic);
#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
-#ifdef CONFIG_HS20
case WPA_KEY_INFO_TYPE_AKM_DEFINED:
- /* FIX: This should be based on negotiated AKM */
- return omac1_aes_128(key, buf, len, mic);
+ switch (akmp) {
+#ifdef CONFIG_HS20
+ case WPA_KEY_MGMT_OSEN:
+ return omac1_aes_128(key, buf, len, mic);
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_SUITEB
+ case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
+ if (hmac_sha256(key, key_len, buf, len, hash))
+ return -1;
+ os_memcpy(mic, hash, MD5_MAC_LEN);
+ break;
+#endif /* CONFIG_SUITEB */
+#ifdef CONFIG_SUITEB192
+ case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
+ if (hmac_sha384(key, key_len, buf, len, hash))
+ return -1;
+ os_memcpy(mic, hash, 24);
+ break;
+#endif /* CONFIG_SUITEB192 */
+ default:
+ return -1;
+ }
+ break;
default:
return -1;
}
@@ -80,8 +125,9 @@
* @nonce1: ANonce or SNonce
* @nonce2: SNonce or ANonce
* @ptk: Buffer for pairwise transient key
- * @ptk_len: Length of PTK
- * @use_sha256: Whether to use SHA256-based KDF
+ * @akmp: Negotiated AKM
+ * @cipher: Negotiated pairwise cipher
+ * Returns: 0 on success, -1 on failure
*
* IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
* PTK = PRF-X(PMK, "Pairwise key expansion",
@@ -92,12 +138,14 @@
* Min(MAC_I, MAC_P) || Max(MAC_I, MAC_P) ||
* Min(INonce, PNonce) || Max(INonce, PNonce))
*/
-void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
- const u8 *addr1, const u8 *addr2,
- const u8 *nonce1, const u8 *nonce2,
- u8 *ptk, size_t ptk_len, int use_sha256)
+int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
+ const u8 *addr1, const u8 *addr2,
+ const u8 *nonce1, const u8 *nonce2,
+ struct wpa_ptk *ptk, int akmp, int cipher)
{
u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN];
+ u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
+ size_t ptk_len;
if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) {
os_memcpy(data, addr1, ETH_ALEN);
@@ -117,27 +165,44 @@
WPA_NONCE_LEN);
}
+ ptk->kck_len = wpa_kck_len(akmp);
+ ptk->kek_len = wpa_kek_len(akmp);
+ ptk->tk_len = wpa_cipher_key_len(cipher);
+ ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len;
+
#ifdef CONFIG_IEEE80211W
- if (use_sha256)
+ if (wpa_key_mgmt_sha256(akmp))
sha256_prf(pmk, pmk_len, label, data, sizeof(data),
- ptk, ptk_len);
+ tmp, ptk_len);
else
#endif /* CONFIG_IEEE80211W */
- sha1_prf(pmk, pmk_len, label, data, sizeof(data), ptk,
- ptk_len);
+ sha1_prf(pmk, pmk_len, label, data, sizeof(data), tmp, ptk_len);
wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR,
MAC2STR(addr1), MAC2STR(addr2));
wpa_hexdump(MSG_DEBUG, "WPA: Nonce1", nonce1, WPA_NONCE_LEN);
wpa_hexdump(MSG_DEBUG, "WPA: Nonce2", nonce2, WPA_NONCE_LEN);
wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len);
- wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", ptk, ptk_len);
+ wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", tmp, ptk_len);
+
+ os_memcpy(ptk->kck, tmp, ptk->kck_len);
+ wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", ptk->kck, ptk->kck_len);
+
+ os_memcpy(ptk->kek, tmp + ptk->kck_len, ptk->kek_len);
+ wpa_hexdump_key(MSG_DEBUG, "WPA: KEK", ptk->kek, ptk->kek_len);
+
+ os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len);
+ wpa_hexdump_key(MSG_DEBUG, "WPA: TK", ptk->tk, ptk->tk_len);
+
+ os_memset(tmp, 0, sizeof(tmp));
+ return 0;
}
#ifdef CONFIG_IEEE80211R
-int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr,
- u8 transaction_seqnum, const u8 *mdie, size_t mdie_len,
+int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
+ const u8 *ap_addr, u8 transaction_seqnum,
+ const u8 *mdie, size_t mdie_len,
const u8 *ftie, size_t ftie_len,
const u8 *rsnie, size_t rsnie_len,
const u8 *ric, size_t ric_len, u8 *mic)
@@ -145,6 +210,12 @@
u8 *buf, *pos;
size_t buf_len;
+ if (kck_len != 16) {
+ wpa_printf(MSG_WARNING, "FT: Unsupported KCK length %u",
+ (unsigned int) kck_len);
+ return -1;
+ }
+
buf_len = 2 * ETH_ALEN + 1 + mdie_len + ftie_len + rsnie_len + ric_len;
buf = os_malloc(buf_len);
if (buf == NULL)
@@ -399,6 +470,10 @@
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_SAE)
return WPA_KEY_MGMT_FT_SAE;
#endif /* CONFIG_SAE */
+ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SUITE_B)
+ return WPA_KEY_MGMT_IEEE8021X_SUITE_B;
+ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192)
+ return WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
return 0;
}
@@ -496,7 +571,7 @@
count = WPA_GET_LE16(pos);
pos += 2;
left -= 2;
- if (count == 0 || left < count * RSN_SELECTOR_LEN) {
+ if (count == 0 || count > left / RSN_SELECTOR_LEN) {
wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
"count %u left %u", __func__, count, left);
return -4;
@@ -524,7 +599,7 @@
count = WPA_GET_LE16(pos);
pos += 2;
left -= 2;
- if (count == 0 || left < count * RSN_SELECTOR_LEN) {
+ if (count == 0 || count > left / RSN_SELECTOR_LEN) {
wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
"count %u left %u", __func__, count, left);
return -6;
@@ -547,17 +622,17 @@
}
if (left >= 2) {
- data->num_pmkid = WPA_GET_LE16(pos);
+ u16 num_pmkid = WPA_GET_LE16(pos);
pos += 2;
left -= 2;
- if (left < (int) data->num_pmkid * PMKID_LEN) {
+ if (num_pmkid > (unsigned int) left / PMKID_LEN) {
wpa_printf(MSG_DEBUG, "%s: PMKID underflow "
- "(num_pmkid=%lu left=%d)",
- __func__, (unsigned long) data->num_pmkid,
- left);
+ "(num_pmkid=%u left=%d)",
+ __func__, num_pmkid, left);
data->num_pmkid = 0;
return -9;
} else {
+ data->num_pmkid = num_pmkid;
data->pmkid = pos;
pos += data->num_pmkid * PMKID_LEN;
left -= data->num_pmkid * PMKID_LEN;
@@ -674,7 +749,7 @@
count = WPA_GET_LE16(pos);
pos += 2;
left -= 2;
- if (count == 0 || left < count * WPA_SELECTOR_LEN) {
+ if (count == 0 || count > left / WPA_SELECTOR_LEN) {
wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
"count %u left %u", __func__, count, left);
return -4;
@@ -695,7 +770,7 @@
count = WPA_GET_LE16(pos);
pos += 2;
left -= 2;
- if (count == 0 || left < count * WPA_SELECTOR_LEN) {
+ if (count == 0 || count > left / WPA_SELECTOR_LEN) {
wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
"count %u left %u", __func__, count, left);
return -6;
@@ -844,15 +919,17 @@
*
* IEEE Std 802.11r-2008 - 8.5.1.5.5
*/
-void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
- const u8 *sta_addr, const u8 *bssid,
- const u8 *pmk_r1_name,
- u8 *ptk, size_t ptk_len, u8 *ptk_name)
+int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
+ const u8 *sta_addr, const u8 *bssid,
+ const u8 *pmk_r1_name,
+ struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher)
{
u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN];
u8 *pos, hash[32];
const u8 *addr[6];
size_t len[6];
+ u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
+ size_t ptk_len;
/*
* PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce ||
@@ -868,7 +945,12 @@
os_memcpy(pos, sta_addr, ETH_ALEN);
pos += ETH_ALEN;
- sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, ptk, ptk_len);
+ ptk->kck_len = wpa_kck_len(akmp);
+ ptk->kek_len = wpa_kek_len(akmp);
+ ptk->tk_len = wpa_cipher_key_len(cipher);
+ ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len;
+
+ sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, tmp, ptk_len);
/*
* PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce ||
@@ -889,6 +971,19 @@
sha256_vector(6, addr, len, hash);
os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN);
+
+ os_memcpy(ptk->kck, tmp, ptk->kck_len);
+ os_memcpy(ptk->kek, tmp + ptk->kck_len, ptk->kek_len);
+ os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len);
+
+ wpa_hexdump_key(MSG_DEBUG, "FT: KCK", ptk->kck, ptk->kck_len);
+ wpa_hexdump_key(MSG_DEBUG, "FT: KEK", ptk->kek, ptk->kek_len);
+ wpa_hexdump_key(MSG_DEBUG, "FT: TK", ptk->tk, ptk->tk_len);
+ wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
+
+ os_memset(tmp, 0, sizeof(tmp));
+
+ return 0;
}
#endif /* CONFIG_IEEE80211R */
@@ -928,6 +1023,72 @@
}
+#ifdef CONFIG_SUITEB
+/**
+ * rsn_pmkid_suite_b - Calculate PMK identifier for Suite B AKM
+ * @kck: Key confirmation key
+ * @kck_len: Length of kck in bytes
+ * @aa: Authenticator address
+ * @spa: Supplicant address
+ * @pmkid: Buffer for PMKID
+ * Returns: 0 on success, -1 on failure
+ *
+ * IEEE Std 802.11ac-2013 - 11.6.1.3 Pairwise key hierarchy
+ * PMKID = Truncate(HMAC-SHA-256(KCK, "PMK Name" || AA || SPA))
+ */
+int rsn_pmkid_suite_b(const u8 *kck, size_t kck_len, const u8 *aa,
+ const u8 *spa, u8 *pmkid)
+{
+ char *title = "PMK Name";
+ const u8 *addr[3];
+ const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
+ unsigned char hash[SHA256_MAC_LEN];
+
+ addr[0] = (u8 *) title;
+ addr[1] = aa;
+ addr[2] = spa;
+
+ if (hmac_sha256_vector(kck, kck_len, 3, addr, len, hash) < 0)
+ return -1;
+ os_memcpy(pmkid, hash, PMKID_LEN);
+ return 0;
+}
+#endif /* CONFIG_SUITEB */
+
+
+#ifdef CONFIG_SUITEB192
+/**
+ * rsn_pmkid_suite_b_192 - Calculate PMK identifier for Suite B AKM
+ * @kck: Key confirmation key
+ * @kck_len: Length of kck in bytes
+ * @aa: Authenticator address
+ * @spa: Supplicant address
+ * @pmkid: Buffer for PMKID
+ * Returns: 0 on success, -1 on failure
+ *
+ * IEEE Std 802.11ac-2013 - 11.6.1.3 Pairwise key hierarchy
+ * PMKID = Truncate(HMAC-SHA-384(KCK, "PMK Name" || AA || SPA))
+ */
+int rsn_pmkid_suite_b_192(const u8 *kck, size_t kck_len, const u8 *aa,
+ const u8 *spa, u8 *pmkid)
+{
+ char *title = "PMK Name";
+ const u8 *addr[3];
+ const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
+ unsigned char hash[SHA384_MAC_LEN];
+
+ addr[0] = (u8 *) title;
+ addr[1] = aa;
+ addr[2] = spa;
+
+ if (hmac_sha384_vector(kck, kck_len, 3, addr, len, hash) < 0)
+ return -1;
+ os_memcpy(pmkid, hash, PMKID_LEN);
+ return 0;
+}
+#endif /* CONFIG_SUITEB192 */
+
+
/**
* wpa_cipher_txt - Convert cipher suite to a text string
* @cipher: Cipher suite (WPA_CIPHER_* enum)
@@ -997,6 +1158,18 @@
case WPA_KEY_MGMT_PSK_SHA256:
return "WPA2-PSK-SHA256";
#endif /* CONFIG_IEEE80211W */
+ case WPA_KEY_MGMT_WPS:
+ return "WPS";
+ case WPA_KEY_MGMT_SAE:
+ return "SAE";
+ case WPA_KEY_MGMT_FT_SAE:
+ return "FT-SAE";
+ case WPA_KEY_MGMT_OSEN:
+ return "OSEN";
+ case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
+ return "WPA2-EAP-SUITE-B";
+ case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
+ return "WPA2-EAP-SUITE-B-192";
default:
return "UNKNOWN";
}
@@ -1023,6 +1196,10 @@
return WLAN_AKM_SUITE_CCKM;
if (akm & WPA_KEY_MGMT_OSEN)
return WLAN_AKM_SUITE_OSEN;
+ if (akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
+ return WLAN_AKM_SUITE_8021X_SUITE_B;
+ if (akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ return WLAN_AKM_SUITE_8021X_SUITE_B_192;
return 0;
}
@@ -1417,56 +1594,56 @@
if (ciphers & WPA_CIPHER_CCMP_256) {
ret = os_snprintf(pos, end - pos, "%sCCMP-256",
pos == start ? "" : delim);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
}
if (ciphers & WPA_CIPHER_GCMP_256) {
ret = os_snprintf(pos, end - pos, "%sGCMP-256",
pos == start ? "" : delim);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
}
if (ciphers & WPA_CIPHER_CCMP) {
ret = os_snprintf(pos, end - pos, "%sCCMP",
pos == start ? "" : delim);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
}
if (ciphers & WPA_CIPHER_GCMP) {
ret = os_snprintf(pos, end - pos, "%sGCMP",
pos == start ? "" : delim);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
}
if (ciphers & WPA_CIPHER_TKIP) {
ret = os_snprintf(pos, end - pos, "%sTKIP",
pos == start ? "" : delim);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
}
if (ciphers & WPA_CIPHER_WEP104) {
ret = os_snprintf(pos, end - pos, "%sWEP104",
pos == start ? "" : delim);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
}
if (ciphers & WPA_CIPHER_WEP40) {
ret = os_snprintf(pos, end - pos, "%sWEP40",
pos == start ? "" : delim);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
}
if (ciphers & WPA_CIPHER_NONE) {
ret = os_snprintf(pos, end - pos, "%sNONE",
pos == start ? "" : delim);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
}
@@ -1497,78 +1674,3 @@
return WPA_CIPHER_CCMP_256;
return WPA_CIPHER_CCMP;
}
-
-
-static int wpa_check_wowlan_trigger(const char *start, const char *trigger,
- int capa_trigger, u8 *param_trigger)
-{
- if (os_strcmp(start, trigger) != 0)
- return 0;
- if (!capa_trigger)
- return 0;
-
- *param_trigger = 1;
- return 1;
-}
-
-
-struct wowlan_triggers *wpa_get_wowlan_triggers(const char *wowlan_triggers,
- struct wpa_driver_capa *capa)
-{
- struct wowlan_triggers *triggers;
- char *start, *end, *buf;
- int last;
-
- if (!wowlan_triggers)
- return NULL;
-
- buf = os_strdup(wowlan_triggers);
- if (buf == NULL)
- return NULL;
-
- triggers = os_zalloc(sizeof(*triggers));
- if (triggers == NULL)
- goto out;
-
-#define CHECK_TRIGGER(trigger) \
- wpa_check_wowlan_trigger(start, #trigger, \
- capa->wowlan_triggers.trigger, \
- &triggers->trigger)
-
- start = buf;
- while (*start != '\0') {
- while (isblank(*start))
- start++;
- if (*start == '\0')
- break;
- end = start;
- while (!isblank(*end) && *end != '\0')
- end++;
- last = *end == '\0';
- *end = '\0';
-
- if (!CHECK_TRIGGER(any) &&
- !CHECK_TRIGGER(disconnect) &&
- !CHECK_TRIGGER(magic_pkt) &&
- !CHECK_TRIGGER(gtk_rekey_failure) &&
- !CHECK_TRIGGER(eap_identity_req) &&
- !CHECK_TRIGGER(four_way_handshake) &&
- !CHECK_TRIGGER(rfkill_release)) {
- wpa_printf(MSG_DEBUG,
- "Unknown/unsupported wowlan trigger '%s'",
- start);
- os_free(triggers);
- triggers = NULL;
- goto out;
- }
-
- if (last)
- break;
- start = end + 1;
- }
-#undef CHECK_TRIGGER
-
-out:
- os_free(buf);
- return triggers;
-}
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index 0ef5a9d..091e317 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -1,6 +1,6 @@
/*
* WPA definitions shared between hostapd and wpa_supplicant
- * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -63,8 +63,8 @@
#define RSN_AUTH_KEY_MGMT_SAE RSN_SELECTOR(0x00, 0x0f, 0xac, 8)
#define RSN_AUTH_KEY_MGMT_FT_SAE RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
#define RSN_AUTH_KEY_MGMT_802_1X_SUITE_B RSN_SELECTOR(0x00, 0x0f, 0xac, 11)
-#define RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_384 RSN_SELECTOR(0x00, 0x0f, 0xac, 12)
-#define RSN_AUTH_KEY_MGMT_FT_802_1X_SUITE_B_384 \
+#define RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192 RSN_SELECTOR(0x00, 0x0f, 0xac, 12)
+#define RSN_AUTH_KEY_MGMT_FT_802_1X_SUITE_B_192 \
RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
#define RSN_AUTH_KEY_MGMT_CCKM RSN_SELECTOR(0x00, 0x40, 0x96, 0x00)
#define RSN_AUTH_KEY_MGMT_OSEN RSN_SELECTOR(0x50, 0x6f, 0x9a, 0x01)
@@ -191,22 +191,38 @@
/* followed by key_data_length bytes of key_data */
} STRUCT_PACKED;
+struct wpa_eapol_key_192 {
+ u8 type;
+ /* Note: key_info, key_length, and key_data_length are unaligned */
+ u8 key_info[2]; /* big endian */
+ u8 key_length[2]; /* big endian */
+ u8 replay_counter[WPA_REPLAY_COUNTER_LEN];
+ u8 key_nonce[WPA_NONCE_LEN];
+ u8 key_iv[16];
+ u8 key_rsc[WPA_KEY_RSC_LEN];
+ u8 key_id[8]; /* Reserved in IEEE 802.11i/RSN */
+ u8 key_mic[24];
+ u8 key_data_length[2]; /* big endian */
+ /* followed by key_data_length bytes of key_data */
+} STRUCT_PACKED;
+
+#define WPA_EAPOL_KEY_MIC_MAX_LEN 24
+#define WPA_KCK_MAX_LEN 24
+#define WPA_KEK_MAX_LEN 32
+#define WPA_TK_MAX_LEN 32
+
/**
* struct wpa_ptk - WPA Pairwise Transient Key
* IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
*/
struct wpa_ptk {
- u8 kck[16]; /* EAPOL-Key Key Confirmation Key (KCK) */
- u8 kek[16]; /* EAPOL-Key Key Encryption Key (KEK) */
- u8 tk1[16]; /* Temporal Key 1 (TK1) */
- union {
- u8 tk2[16]; /* Temporal Key 2 (TK2) */
- struct {
- u8 tx_mic_key[8];
- u8 rx_mic_key[8];
- } auth;
- } u;
-} STRUCT_PACKED;
+ u8 kck[WPA_KCK_MAX_LEN]; /* EAPOL-Key Key Confirmation Key (KCK) */
+ u8 kek[WPA_KEK_MAX_LEN]; /* EAPOL-Key Key Encryption Key (KEK) */
+ u8 tk[WPA_TK_MAX_LEN]; /* Temporal Key (TK) */
+ size_t kck_len;
+ size_t kek_len;
+ size_t tk_len;
+};
/* WPA IE version 1
@@ -327,16 +343,17 @@
#endif /* _MSC_VER */
-int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
- u8 *mic);
-void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
- const u8 *addr1, const u8 *addr2,
- const u8 *nonce1, const u8 *nonce2,
- u8 *ptk, size_t ptk_len, int use_sha256);
+int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver,
+ const u8 *buf, size_t len, u8 *mic);
+int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
+ const u8 *addr1, const u8 *addr2,
+ const u8 *nonce1, const u8 *nonce2,
+ struct wpa_ptk *ptk, int akmp, int cipher);
#ifdef CONFIG_IEEE80211R
-int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr,
- u8 transaction_seqnum, const u8 *mdie, size_t mdie_len,
+int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
+ const u8 *ap_addr, u8 transaction_seqnum,
+ const u8 *mdie, size_t mdie_len,
const u8 *ftie, size_t ftie_len,
const u8 *rsnie, size_t rsnie_len,
const u8 *ric, size_t ric_len, u8 *mic);
@@ -349,10 +366,10 @@
void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
const u8 *r1kh_id, const u8 *s1kh_id,
u8 *pmk_r1, u8 *pmk_r1_name);
-void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
- const u8 *sta_addr, const u8 *bssid,
- const u8 *pmk_r1_name,
- u8 *ptk, size_t ptk_len, u8 *ptk_name);
+int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
+ const u8 *sta_addr, const u8 *bssid,
+ const u8 *pmk_r1_name,
+ struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher);
#endif /* CONFIG_IEEE80211R */
struct wpa_ie_data {
@@ -374,6 +391,26 @@
void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
u8 *pmkid, int use_sha256);
+#ifdef CONFIG_SUITEB
+int rsn_pmkid_suite_b(const u8 *kck, size_t kck_len, const u8 *aa,
+ const u8 *spa, u8 *pmkid);
+#else /* CONFIG_SUITEB */
+static inline int rsn_pmkid_suite_b(const u8 *kck, size_t kck_len, const u8 *aa,
+ const u8 *spa, u8 *pmkid)
+{
+ return -1;
+}
+#endif /* CONFIG_SUITEB */
+#ifdef CONFIG_SUITEB192
+int rsn_pmkid_suite_b_192(const u8 *kck, size_t kck_len, const u8 *aa,
+ const u8 *spa, u8 *pmkid);
+#else /* CONFIG_SUITEB192 */
+static inline int rsn_pmkid_suite_b_192(const u8 *kck, size_t kck_len,
+ const u8 *aa, const u8 *spa, u8 *pmkid)
+{
+ return -1;
+}
+#endif /* CONFIG_SUITEB192 */
const char * wpa_cipher_txt(int cipher);
const char * wpa_key_mgmt_txt(int key_mgmt, int proto);
@@ -419,5 +456,6 @@
int wpa_parse_cipher(const char *value);
int wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim);
int wpa_select_ap_group_cipher(int wpa, int wpa_pairwise, int rsn_pairwise);
+unsigned int wpa_mic_len(int akmp);
#endif /* WPA_COMMON_H */
diff --git a/src/common/wpa_ctrl.c b/src/common/wpa_ctrl.c
index 5820a13..ccaaf1b 100644
--- a/src/common/wpa_ctrl.c
+++ b/src/common/wpa_ctrl.c
@@ -94,10 +94,9 @@
if (ctrl_path == NULL)
return NULL;
- ctrl = os_malloc(sizeof(*ctrl));
+ ctrl = os_zalloc(sizeof(*ctrl));
if (ctrl == NULL)
return NULL;
- os_memset(ctrl, 0, sizeof(*ctrl));
ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
if (ctrl->s < 0) {
@@ -112,7 +111,7 @@
CONFIG_CTRL_IFACE_CLIENT_DIR "/"
CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
(int) getpid(), counter);
- if (ret < 0 || (size_t) ret >= sizeof(ctrl->local.sun_path)) {
+ if (os_snprintf_error(sizeof(ctrl->local.sun_path), ret)) {
close(ctrl->s);
os_free(ctrl);
return NULL;
@@ -283,10 +282,9 @@
struct hostent *h;
#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
- ctrl = os_malloc(sizeof(*ctrl));
+ ctrl = os_zalloc(sizeof(*ctrl));
if (ctrl == NULL)
return NULL;
- os_memset(ctrl, 0, sizeof(*ctrl));
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
ctrl->s = socket(PF_INET6, SOCK_DGRAM, 0);
@@ -643,7 +641,7 @@
ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s",
ctrl_path);
#endif /* UNICODE */
- if (ret < 0 || ret >= 256) {
+ if (os_snprintf_error(256, ret)) {
os_free(ctrl);
return NULL;
}
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 4812f8d..59a3412 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -42,6 +42,8 @@
#define WPA_EVENT_EAP_METHOD "CTRL-EVENT-EAP-METHOD "
/** EAP peer certificate from TLS */
#define WPA_EVENT_EAP_PEER_CERT "CTRL-EVENT-EAP-PEER-CERT "
+/** EAP peer certificate alternative subject name component from TLS */
+#define WPA_EVENT_EAP_PEER_ALT "CTRL-EVENT-EAP-PEER-ALT "
/** EAP TLS certificate chain validation error */
#define WPA_EVENT_EAP_TLS_CERT_ERROR "CTRL-EVENT-EAP-TLS-CERT-ERROR "
/** EAP status */
@@ -58,6 +60,8 @@
#define WPA_EVENT_SCAN_STARTED "CTRL-EVENT-SCAN-STARTED "
/** New scan results available */
#define WPA_EVENT_SCAN_RESULTS "CTRL-EVENT-SCAN-RESULTS "
+/** Scan command failed */
+#define WPA_EVENT_SCAN_FAILED "CTRL-EVENT-SCAN-FAILED "
/** wpa_supplicant state change */
#define WPA_EVENT_STATE_CHANGE "CTRL-EVENT-STATE-CHANGE "
/** A new BSS entry was added (followed by BSS entry id and BSSID) */
@@ -118,6 +122,17 @@
#define WPS_EVENT_ER_AP_SETTINGS "WPS-ER-AP-SETTINGS "
#define WPS_EVENT_ER_SET_SEL_REG "WPS-ER-AP-SET-SEL-REG "
+/* MESH events */
+#define MESH_GROUP_STARTED "MESH-GROUP-STARTED "
+#define MESH_GROUP_REMOVED "MESH-GROUP-REMOVED "
+#define MESH_PEER_CONNECTED "MESH-PEER-CONNECTED "
+#define MESH_PEER_DISCONNECTED "MESH-PEER-DISCONNECTED "
+
+/* WMM AC events */
+#define WMM_AC_EVENT_TSPEC_ADDED "TSPEC-ADDED "
+#define WMM_AC_EVENT_TSPEC_REMOVED "TSPEC-REMOVED "
+#define WMM_AC_EVENT_TSPEC_REQ_FAILED "TSPEC-REQ-FAILED "
+
/** P2P device found */
#define P2P_EVENT_DEVICE_FOUND "P2P-DEVICE-FOUND "
@@ -181,12 +196,18 @@
/* parameters: <addr> <dialog_token> <freq> <status_code> <result> */
#define GAS_QUERY_DONE "GAS-QUERY-DONE "
+/* parameters: <addr> <result> */
+#define ANQP_QUERY_DONE "ANQP-QUERY-DONE "
+
#define HS20_SUBSCRIPTION_REMEDIATION "HS20-SUBSCRIPTION-REMEDIATION "
#define HS20_DEAUTH_IMMINENT_NOTICE "HS20-DEAUTH-IMMINENT-NOTICE "
#define EXT_RADIO_WORK_START "EXT-RADIO-WORK-START "
#define EXT_RADIO_WORK_TIMEOUT "EXT-RADIO-WORK-TIMEOUT "
+#define RRM_EVENT_NEIGHBOR_REP_RXED "RRM-NEIGHBOR-REP-RECEIVED "
+#define RRM_EVENT_NEIGHBOR_REP_FAILED "RRM-NEIGHBOR-REP-REQUEST-FAILED "
+
/* hostapd control interface - fixed message prefixes */
#define WPS_EVENT_PIN_NEEDED "WPS-PIN-NEEDED "
#define WPS_EVENT_NEW_AP_SETTINGS "WPS-NEW-AP-SETTINGS "
@@ -204,6 +225,9 @@
#define AP_EVENT_ENABLED "AP-ENABLED "
#define AP_EVENT_DISABLED "AP-DISABLED "
+#define INTERFACE_ENABLED "INTERFACE-ENABLED "
+#define INTERFACE_DISABLED "INTERFACE-DISABLED "
+
#define ACS_EVENT_STARTED "ACS-STARTED "
#define ACS_EVENT_COMPLETED "ACS-COMPLETED "
#define ACS_EVENT_FAILED "ACS-FAILED "
@@ -216,6 +240,9 @@
#define AP_CSA_FINISHED "AP-CSA-FINISHED "
+/* BSS Transition Management Response frame received */
+#define BSS_TM_RESP "BSS-TM-RESP "
+
/* BSS command information masks */
#define WPA_BSS_MASK_ALL 0xFFFDFFFF
@@ -237,6 +264,7 @@
#define WPA_BSS_MASK_INTERNETW BIT(15)
#define WPA_BSS_MASK_WIFI_DISPLAY BIT(16)
#define WPA_BSS_MASK_DELIM BIT(17)
+#define WPA_BSS_MASK_MESH_SCAN BIT(18)
/* VENDOR_ELEM_* frame id values */
@@ -254,6 +282,7 @@
VENDOR_ELEM_P2P_INV_RESP = 10,
VENDOR_ELEM_P2P_ASSOC_REQ = 11,
VENDOR_ELEM_P2P_ASSOC_RESP = 12,
+ VENDOR_ELEM_ASSOC_REQ = 13,
NUM_VENDOR_ELEM_FRAMES
};
@@ -383,8 +412,6 @@
*/
int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl);
-char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl);
-
#ifdef ANDROID
/**
* wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that
@@ -402,6 +429,8 @@
#define WPA_CTRL_IFACE_PORT_LIMIT 50 /* decremented from start */
#define WPA_GLOBAL_CTRL_IFACE_PORT 9878
#define WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT 20 /* incremented from start */
+
+char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl);
#endif /* CONFIG_CTRL_IFACE_UDP */
diff --git a/src/crypto/Makefile b/src/crypto/Makefile
index 2a92109..3e90350 100644
--- a/src/crypto/Makefile
+++ b/src/crypto/Makefile
@@ -26,6 +26,7 @@
aes-internal-dec.o \
aes-internal-enc.o \
aes-omac1.o \
+ aes-siv.o \
aes-unwrap.o \
aes-wrap.o \
des-internal.o \
diff --git a/src/crypto/aes-eax.c b/src/crypto/aes-eax.c
index 21941c6..15a09f8 100644
--- a/src/crypto/aes-eax.c
+++ b/src/crypto/aes-eax.c
@@ -71,7 +71,7 @@
ret = 0;
fail:
- os_free(buf);
+ bin_clear_free(buf, buf_len);
return ret;
}
diff --git a/src/crypto/aes-omac1.c b/src/crypto/aes-omac1.c
index 27895eb..375db57 100644
--- a/src/crypto/aes-omac1.c
+++ b/src/crypto/aes-omac1.c
@@ -1,5 +1,5 @@
/*
- * One-key CBC MAC (OMAC1) hash with AES-128
+ * One-key CBC MAC (OMAC1) hash with AES
*
* Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
*
@@ -27,8 +27,9 @@
/**
- * omac1_aes_128_vector - One-Key CBC MAC (OMAC1) hash with AES-128
- * @key: 128-bit key for the hash operation
+ * omac1_aes_vector - One-Key CBC MAC (OMAC1) hash with AES
+ * @key: Key for the hash operation
+ * @key_len: Key length in octets
* @num_elem: Number of elements in the data vector
* @addr: Pointers to the data areas
* @len: Lengths of the data blocks
@@ -39,15 +40,15 @@
* OMAC1 was standardized with the name CMAC by NIST in a Special Publication
* (SP) 800-38B.
*/
-int omac1_aes_128_vector(const u8 *key, size_t num_elem,
- const u8 *addr[], const size_t *len, u8 *mac)
+int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
{
void *ctx;
u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE];
const u8 *pos, *end;
size_t i, e, left, total_len;
- ctx = aes_encrypt_init(key, 16);
+ ctx = aes_encrypt_init(key, key_len);
if (ctx == NULL)
return -1;
os_memset(cbc, 0, AES_BLOCK_SIZE);
@@ -65,6 +66,13 @@
for (i = 0; i < AES_BLOCK_SIZE; i++) {
cbc[i] ^= *pos++;
if (pos >= end) {
+ /*
+ * Stop if there are no more bytes to process
+ * since there are no more entries in the array.
+ */
+ if (i + 1 == AES_BLOCK_SIZE &&
+ left == AES_BLOCK_SIZE)
+ break;
e++;
pos = addr[e];
end = pos + len[e];
@@ -83,6 +91,12 @@
for (i = 0; i < left; i++) {
cbc[i] ^= *pos++;
if (pos >= end) {
+ /*
+ * Stop if there are no more bytes to process
+ * since there are no more entries in the array.
+ */
+ if (i + 1 == left)
+ break;
e++;
pos = addr[e];
end = pos + len[e];
@@ -101,6 +115,26 @@
/**
+ * omac1_aes_128_vector - One-Key CBC MAC (OMAC1) hash with AES-128
+ * @key: 128-bit key for the hash operation
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This is a mode for using block cipher (AES in this case) for authentication.
+ * OMAC1 was standardized with the name CMAC by NIST in a Special Publication
+ * (SP) 800-38B.
+ */
+int omac1_aes_128_vector(const u8 *key, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return omac1_aes_vector(key, 16, num_elem, addr, len, mac);
+}
+
+
+/**
* omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128 (aka AES-CMAC)
* @key: 128-bit key for the hash operation
* @data: Data buffer for which a MAC is determined
@@ -116,3 +150,21 @@
{
return omac1_aes_128_vector(key, 1, &data, &data_len, mac);
}
+
+
+/**
+ * omac1_aes_256 - One-Key CBC MAC (OMAC1) hash with AES-256 (aka AES-CMAC)
+ * @key: 256-bit key for the hash operation
+ * @data: Data buffer for which a MAC is determined
+ * @data_len: Length of data buffer in bytes
+ * @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This is a mode for using block cipher (AES in this case) for authentication.
+ * OMAC1 was standardized with the name CMAC by NIST in a Special Publication
+ * (SP) 800-38B.
+ */
+int omac1_aes_256(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+ return omac1_aes_vector(key, 32, 1, &data, &data_len, mac);
+}
diff --git a/src/crypto/aes-siv.c b/src/crypto/aes-siv.c
new file mode 100644
index 0000000..5ac82c2
--- /dev/null
+++ b/src/crypto/aes-siv.c
@@ -0,0 +1,188 @@
+/*
+ * AES SIV (RFC 5297)
+ * Copyright (c) 2013 Cozybit, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "aes.h"
+#include "aes_wrap.h"
+#include "aes_siv.h"
+
+
+static const u8 zero[AES_BLOCK_SIZE];
+
+
+static void dbl(u8 *pad)
+{
+ int i, carry;
+
+ carry = pad[0] & 0x80;
+ for (i = 0; i < AES_BLOCK_SIZE - 1; i++)
+ pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7);
+ pad[AES_BLOCK_SIZE - 1] <<= 1;
+ if (carry)
+ pad[AES_BLOCK_SIZE - 1] ^= 0x87;
+}
+
+
+static void xor(u8 *a, const u8 *b)
+{
+ int i;
+
+ for (i = 0; i < AES_BLOCK_SIZE; i++)
+ *a++ ^= *b++;
+}
+
+
+static void xorend(u8 *a, int alen, const u8 *b, int blen)
+{
+ int i;
+
+ if (alen < blen)
+ return;
+
+ for (i = 0; i < blen; i++)
+ a[alen - blen + i] ^= b[i];
+}
+
+
+static void pad_block(u8 *pad, const u8 *addr, size_t len)
+{
+ os_memset(pad, 0, AES_BLOCK_SIZE);
+ os_memcpy(pad, addr, len);
+
+ if (len < AES_BLOCK_SIZE)
+ pad[len] = 0x80;
+}
+
+
+static int aes_s2v(const u8 *key, size_t num_elem, const u8 *addr[],
+ size_t *len, u8 *mac)
+{
+ u8 tmp[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
+ u8 *buf = NULL;
+ int ret;
+ size_t i;
+
+ if (!num_elem) {
+ os_memcpy(tmp, zero, sizeof(zero));
+ tmp[AES_BLOCK_SIZE - 1] = 1;
+ return omac1_aes_128(key, tmp, sizeof(tmp), mac);
+ }
+
+ ret = omac1_aes_128(key, zero, sizeof(zero), tmp);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < num_elem - 1; i++) {
+ ret = omac1_aes_128(key, addr[i], len[i], tmp2);
+ if (ret)
+ return ret;
+
+ dbl(tmp);
+ xor(tmp, tmp2);
+ }
+ if (len[i] >= AES_BLOCK_SIZE) {
+ buf = os_malloc(len[i]);
+ if (!buf)
+ return -ENOMEM;
+
+ os_memcpy(buf, addr[i], len[i]);
+ xorend(buf, len[i], tmp, AES_BLOCK_SIZE);
+ ret = omac1_aes_128(key, buf, len[i], mac);
+ bin_clear_free(buf, len[i]);
+ return ret;
+ }
+
+ dbl(tmp);
+ pad_block(tmp2, addr[i], len[i]);
+ xor(tmp, tmp2);
+
+ return omac1_aes_128(key, tmp, sizeof(tmp), mac);
+}
+
+
+int aes_siv_encrypt(const u8 *key, const u8 *pw,
+ size_t pwlen, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *out)
+{
+ const u8 *_addr[6];
+ size_t _len[6];
+ const u8 *k1 = key, *k2 = key + 16;
+ u8 v[AES_BLOCK_SIZE];
+ size_t i;
+ u8 *iv, *crypt_pw;
+
+ if (num_elem > ARRAY_SIZE(_addr) - 1)
+ return -1;
+
+ for (i = 0; i < num_elem; i++) {
+ _addr[i] = addr[i];
+ _len[i] = len[i];
+ }
+ _addr[num_elem] = pw;
+ _len[num_elem] = pwlen;
+
+ if (aes_s2v(k1, num_elem + 1, _addr, _len, v))
+ return -1;
+
+ iv = out;
+ crypt_pw = out + AES_BLOCK_SIZE;
+
+ os_memcpy(iv, v, AES_BLOCK_SIZE);
+ os_memcpy(crypt_pw, pw, pwlen);
+
+ /* zero out 63rd and 31st bits of ctr (from right) */
+ v[8] &= 0x7f;
+ v[12] &= 0x7f;
+ return aes_128_ctr_encrypt(k2, v, crypt_pw, pwlen);
+}
+
+
+int aes_siv_decrypt(const u8 *key, const u8 *iv_crypt, size_t iv_c_len,
+ size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *out)
+{
+ const u8 *_addr[6];
+ size_t _len[6];
+ const u8 *k1 = key, *k2 = key + 16;
+ size_t crypt_len;
+ size_t i;
+ int ret;
+ u8 iv[AES_BLOCK_SIZE];
+ u8 check[AES_BLOCK_SIZE];
+
+ if (iv_c_len < AES_BLOCK_SIZE || num_elem > ARRAY_SIZE(_addr) - 1)
+ return -1;
+ crypt_len = iv_c_len - AES_BLOCK_SIZE;
+
+ for (i = 0; i < num_elem; i++) {
+ _addr[i] = addr[i];
+ _len[i] = len[i];
+ }
+ _addr[num_elem] = out;
+ _len[num_elem] = crypt_len;
+
+ os_memcpy(iv, iv_crypt, AES_BLOCK_SIZE);
+ os_memcpy(out, iv_crypt + AES_BLOCK_SIZE, crypt_len);
+
+ iv[8] &= 0x7f;
+ iv[12] &= 0x7f;
+
+ ret = aes_128_ctr_encrypt(k2, iv, out, crypt_len);
+ if (ret)
+ return ret;
+
+ ret = aes_s2v(k1, num_elem + 1, _addr, _len, check);
+ if (ret)
+ return ret;
+ if (os_memcmp(check, iv_crypt, AES_BLOCK_SIZE) == 0)
+ return 0;
+
+ return -1;
+}
diff --git a/src/crypto/aes_siv.h b/src/crypto/aes_siv.h
new file mode 100644
index 0000000..463cf65
--- /dev/null
+++ b/src/crypto/aes_siv.h
@@ -0,0 +1,19 @@
+/*
+ * AES SIV (RFC 5297)
+ * Copyright (c) 2013 Cozybit, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef AES_SIV_H
+#define AES_SIV_H
+
+int aes_siv_encrypt(const u8 *key, const u8 *pw,
+ size_t pwlen, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *out);
+int aes_siv_decrypt(const u8 *key, const u8 *iv_crypt, size_t iv_c_len,
+ size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *out);
+
+#endif /* AES_SIV_H */
diff --git a/src/crypto/aes_wrap.h b/src/crypto/aes_wrap.h
index 6b3727c..4a14209 100644
--- a/src/crypto/aes_wrap.h
+++ b/src/crypto/aes_wrap.h
@@ -2,7 +2,7 @@
* AES-based functions
*
* - AES Key Wrap Algorithm (RFC3394)
- * - One-Key CBC MAC (OMAC1) hash with AES-128
+ * - One-Key CBC MAC (OMAC1) hash with AES-128 and AES-256
* - AES-128 CTR mode encryption
* - AES-128 EAX mode encryption/decryption
* - AES-128 CBC
@@ -22,11 +22,16 @@
u8 *cipher);
int __must_check aes_unwrap(const u8 *kek, size_t kek_len, int n,
const u8 *cipher, u8 *plain);
+int __must_check omac1_aes_vector(const u8 *key, size_t key_len,
+ size_t num_elem, const u8 *addr[],
+ const size_t *len, u8 *mac);
int __must_check omac1_aes_128_vector(const u8 *key, size_t num_elem,
const u8 *addr[], const size_t *len,
u8 *mac);
int __must_check omac1_aes_128(const u8 *key, const u8 *data, size_t data_len,
u8 *mac);
+int __must_check omac1_aes_256(const u8 *key, const u8 *data, size_t data_len,
+ u8 *mac);
int __must_check aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out);
int __must_check aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
u8 *data, size_t data_len);
diff --git a/src/crypto/crypto_module_tests.c b/src/crypto/crypto_module_tests.c
new file mode 100644
index 0000000..7137c27
--- /dev/null
+++ b/src/crypto/crypto_module_tests.c
@@ -0,0 +1,1679 @@
+/*
+ * crypto module tests
+ * Copyright (c) 2014-2015, 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 "crypto/aes_siv.h"
+#include "crypto/aes_wrap.h"
+#include "crypto/aes.h"
+#include "crypto/ms_funcs.h"
+#include "crypto/crypto.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
+
+
+static int test_siv(void)
+{
+#ifdef CONFIG_MESH
+ /* RFC 5297, A.1. Deterministic Authenticated Encryption Example */
+ u8 key[] = {
+ 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
+ 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+ };
+ u8 ad[] = {
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27
+ };
+ u8 plaintext[] = {
+ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+ 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee
+ };
+ u8 iv_c[] = {
+ 0x85, 0x63, 0x2d, 0x07, 0xc6, 0xe8, 0xf3, 0x7f,
+ 0x95, 0x0a, 0xcd, 0x32, 0x0a, 0x2e, 0xcc, 0x93,
+ 0x40, 0xc0, 0x2b, 0x96, 0x90, 0xc4, 0xdc, 0x04,
+ 0xda, 0xef, 0x7f, 0x6a, 0xfe, 0x5c
+ };
+ /* RFC 5297, A.2. Nonce-Based Authenticated Encryption Example */
+ u8 key_2[] = {
+ 0x7f, 0x7e, 0x7d, 0x7c, 0x7b, 0x7a, 0x79, 0x78,
+ 0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x70,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f
+ };
+ u8 ad1_2[] = {
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+ 0xde, 0xad, 0xda, 0xda, 0xde, 0xad, 0xda, 0xda,
+ 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
+ 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00
+ };
+ u8 ad2_2[] = {
+ 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80,
+ 0x90, 0xa0
+ };
+ u8 nonce_2[] = {
+ 0x09, 0xf9, 0x11, 0x02, 0x9d, 0x74, 0xe3, 0x5b,
+ 0xd8, 0x41, 0x56, 0xc5, 0x63, 0x56, 0x88, 0xc0
+ };
+ u8 plaintext_2[] = {
+ 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
+ 0x73, 0x6f, 0x6d, 0x65, 0x20, 0x70, 0x6c, 0x61,
+ 0x69, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x20, 0x74,
+ 0x6f, 0x20, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70,
+ 0x74, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20,
+ 0x53, 0x49, 0x56, 0x2d, 0x41, 0x45, 0x53
+ };
+ u8 iv_c_2[] = {
+ 0x7b, 0xdb, 0x6e, 0x3b, 0x43, 0x26, 0x67, 0xeb,
+ 0x06, 0xf4, 0xd1, 0x4b, 0xff, 0x2f, 0xbd, 0x0f,
+ 0xcb, 0x90, 0x0f, 0x2f, 0xdd, 0xbe, 0x40, 0x43,
+ 0x26, 0x60, 0x19, 0x65, 0xc8, 0x89, 0xbf, 0x17,
+ 0xdb, 0xa7, 0x7c, 0xeb, 0x09, 0x4f, 0xa6, 0x63,
+ 0xb7, 0xa3, 0xf7, 0x48, 0xba, 0x8a, 0xf8, 0x29,
+ 0xea, 0x64, 0xad, 0x54, 0x4a, 0x27, 0x2e, 0x9c,
+ 0x48, 0x5b, 0x62, 0xa3, 0xfd, 0x5c, 0x0d
+ };
+ u8 out[2 * AES_BLOCK_SIZE + sizeof(plaintext_2)];
+ const u8 *addr[3];
+ size_t len[3];
+
+ /* RFC 5297, A.1. Deterministic Authenticated Encryption Example */
+ addr[0] = ad;
+ len[0] = sizeof(ad);
+
+ if (aes_siv_encrypt(key, plaintext, sizeof(plaintext),
+ 1, addr, len, out)) {
+ wpa_printf(MSG_ERROR, "AES-SIV mode encryption failed");
+ return 1;
+ }
+ if (os_memcmp(out, iv_c, sizeof(iv_c)) != 0) {
+ wpa_printf(MSG_ERROR,
+ "AES-SIV mode encryption returned invalid cipher text");
+ return 1;
+ }
+
+ if (aes_siv_decrypt(key, iv_c, sizeof(iv_c), 1, addr, len, out)) {
+ wpa_printf(MSG_ERROR, "AES-SIV mode decryption failed");
+ return 1;
+ }
+ if (os_memcmp(out, plaintext, sizeof(plaintext)) != 0) {
+ wpa_printf(MSG_ERROR,
+ "AES-SIV mode decryption returned invalid plain text");
+ return 1;
+ }
+
+ /* RFC 5297, A.2. Nonce-Based Authenticated Encryption Example */
+ addr[0] = ad1_2;
+ len[0] = sizeof(ad1_2);
+ addr[1] = ad2_2;
+ len[1] = sizeof(ad2_2);
+ addr[2] = nonce_2;
+ len[2] = sizeof(nonce_2);
+
+ if (aes_siv_encrypt(key_2, plaintext_2, sizeof(plaintext_2),
+ 3, addr, len, out)) {
+ wpa_printf(MSG_ERROR, "AES-SIV mode encryption failed");
+ return 1;
+ }
+ if (os_memcmp(out, iv_c_2, sizeof(iv_c_2)) != 0) {
+ wpa_printf(MSG_ERROR,
+ "AES-SIV mode encryption returned invalid cipher text");
+ return 1;
+ }
+
+ if (aes_siv_decrypt(key_2, iv_c_2, sizeof(iv_c_2), 3, addr, len, out)) {
+ wpa_printf(MSG_ERROR, "AES-SIV mode decryption failed");
+ return 1;
+ }
+ if (os_memcmp(out, plaintext_2, sizeof(plaintext_2)) != 0) {
+ wpa_printf(MSG_ERROR,
+ "AES-SIV mode decryption returned invalid plain text");
+ return 1;
+ }
+
+ wpa_printf(MSG_INFO, "AES-SIV test cases passed");
+#endif /* CONFIG_MESH */
+
+ return 0;
+}
+
+
+/* OMAC1 AES-128 test vectors from
+ * http://csrc.nist.gov/CryptoToolkit/modes/proposedmodes/omac/omac-ad.pdf
+ * which are same as the examples from NIST SP800-38B
+ * http://csrc.nist.gov/CryptoToolkit/modes/800-38_Series_Publications/SP800-38B.pdf
+ */
+
+struct omac1_test_vector {
+ u8 k[16];
+ u8 msg[64];
+ int msg_len;
+ u8 tag[16];
+};
+
+static struct omac1_test_vector omac1_test_vectors[] =
+{
+ {
+ { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
+ { },
+ 0,
+ { 0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28,
+ 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46 }
+ },
+ {
+ { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
+ { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+ 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a},
+ 16,
+ { 0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44,
+ 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c }
+ },
+ {
+ { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
+ { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+ 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+ 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11 },
+ 40,
+ { 0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30,
+ 0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27 }
+ },
+ {
+ { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
+ { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+ 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+ 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+ 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+ 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+ 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 },
+ 64,
+ { 0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92,
+ 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe }
+ },
+};
+
+
+static int test_omac1_vector(struct omac1_test_vector *tv, unsigned int i)
+{
+ u8 key[] = {
+ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
+ };
+ u8 msg[] = { 0x12, 0x34, 0x56 };
+ u8 result[24], result2[24];
+ const u8 *addr[3];
+ size_t len[3];
+
+ if (omac1_aes_128(tv->k, tv->msg, tv->msg_len, result) ||
+ os_memcmp(result, tv->tag, 16) != 0) {
+ wpa_printf(MSG_ERROR, "OMAC1-AES-128 test vector %u failed", i);
+ return 1;
+ }
+
+ if (tv->msg_len > 1) {
+
+ addr[0] = tv->msg;
+ len[0] = 1;
+ addr[1] = tv->msg + 1;
+ len[1] = tv->msg_len - 1;
+
+ if (omac1_aes_128_vector(tv->k, 2, addr, len, result) ||
+ os_memcmp(result, tv->tag, 16) != 0) {
+ wpa_printf(MSG_ERROR,
+ "OMAC1-AES-128(vector) test vector %u failed",
+ i);
+ return 1;
+ }
+
+ addr[0] = tv->msg;
+ len[0] = tv->msg_len - 2;
+ addr[1] = tv->msg + tv->msg_len - 2;
+ len[1] = 1;
+ addr[2] = tv->msg + tv->msg_len - 1;
+ len[2] = 1;
+
+ if (omac1_aes_128_vector(tv->k, 3, addr, len, result) ||
+ os_memcmp(result, tv->tag, 16) != 0) {
+ wpa_printf(MSG_ERROR,
+ "OMAC1-AES-128(vector2) test vector %u failed",
+ i);
+ return 1;
+ }
+ }
+
+ addr[0] = &msg[0];
+ len[0] = 1;
+ addr[1] = &msg[1];
+ len[1] = 1;
+ addr[2] = &msg[2];
+ len[2] = 1;
+ if (omac1_aes_128(key, msg, sizeof(msg), result) ||
+ omac1_aes_128_vector(key, 3, addr, len, result2) ||
+ os_memcmp(result, result2, 16) != 0) {
+ wpa_printf(MSG_ERROR, "OMAC1-AES-128 short test mismatch");
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int test_omac1(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(omac1_test_vectors); i++) {
+ if (test_omac1_vector(&omac1_test_vectors[i], i))
+ return 1;
+ }
+
+ wpa_printf(MSG_INFO, "OMAC1-AES-128 test cases passed");
+
+ return 0;
+}
+
+
+static int test_eax(void)
+{
+#ifdef EAP_PSK
+ u8 msg[] = { 0xF7, 0xFB };
+ u8 key[] = { 0x91, 0x94, 0x5D, 0x3F, 0x4D, 0xCB, 0xEE, 0x0B,
+ 0xF4, 0x5E, 0xF5, 0x22, 0x55, 0xF0, 0x95, 0xA4 };
+ u8 nonce[] = { 0xBE, 0xCA, 0xF0, 0x43, 0xB0, 0xA2, 0x3D, 0x84,
+ 0x31, 0x94, 0xBA, 0x97, 0x2C, 0x66, 0xDE, 0xBD };
+ u8 hdr[] = { 0xFA, 0x3B, 0xFD, 0x48, 0x06, 0xEB, 0x53, 0xFA };
+ u8 cipher[] = { 0x19, 0xDD, 0x5C, 0x4C, 0x93, 0x31, 0x04, 0x9D,
+ 0x0B, 0xDA, 0xB0, 0x27, 0x74, 0x08, 0xF6, 0x79,
+ 0x67, 0xE5 };
+ u8 data[sizeof(msg)], tag[AES_BLOCK_SIZE];
+
+ os_memcpy(data, msg, sizeof(msg));
+ if (aes_128_eax_encrypt(key, nonce, sizeof(nonce), hdr, sizeof(hdr),
+ data, sizeof(data), tag)) {
+ wpa_printf(MSG_ERROR, "AES-128 EAX mode encryption failed");
+ return 1;
+ }
+ if (os_memcmp(data, cipher, sizeof(data)) != 0) {
+ wpa_printf(MSG_ERROR,
+ "AES-128 EAX mode encryption returned invalid cipher text");
+ return 1;
+ }
+ if (os_memcmp(tag, cipher + sizeof(data), AES_BLOCK_SIZE) != 0) {
+ wpa_printf(MSG_ERROR,
+ "AES-128 EAX mode encryption returned invalid tag");
+ return 1;
+ }
+
+ if (aes_128_eax_decrypt(key, nonce, sizeof(nonce), hdr, sizeof(hdr),
+ data, sizeof(data), tag)) {
+ wpa_printf(MSG_ERROR, "AES-128 EAX mode decryption failed");
+ return 1;
+ }
+ if (os_memcmp(data, msg, sizeof(data)) != 0) {
+ wpa_printf(MSG_ERROR,
+ "AES-128 EAX mode decryption returned invalid plain text");
+ return 1;
+ }
+
+ wpa_printf(MSG_INFO, "AES-128 EAX mode test cases passed");
+#endif /* EAP_PSK */
+
+ return 0;
+}
+
+
+static int test_cbc(void)
+{
+ struct cbc_test_vector {
+ u8 key[16];
+ u8 iv[16];
+ u8 plain[32];
+ u8 cipher[32];
+ size_t len;
+ } vectors[] = {
+ {
+ { 0x06, 0xa9, 0x21, 0x40, 0x36, 0xb8, 0xa1, 0x5b,
+ 0x51, 0x2e, 0x03, 0xd5, 0x34, 0x12, 0x00, 0x06 },
+ { 0x3d, 0xaf, 0xba, 0x42, 0x9d, 0x9e, 0xb4, 0x30,
+ 0xb4, 0x22, 0xda, 0x80, 0x2c, 0x9f, 0xac, 0x41 },
+ "Single block msg",
+ { 0xe3, 0x53, 0x77, 0x9c, 0x10, 0x79, 0xae, 0xb8,
+ 0x27, 0x08, 0x94, 0x2d, 0xbe, 0x77, 0x18, 0x1a },
+ 16
+ },
+ {
+ { 0xc2, 0x86, 0x69, 0x6d, 0x88, 0x7c, 0x9a, 0xa0,
+ 0x61, 0x1b, 0xbb, 0x3e, 0x20, 0x25, 0xa4, 0x5a },
+ { 0x56, 0x2e, 0x17, 0x99, 0x6d, 0x09, 0x3d, 0x28,
+ 0xdd, 0xb3, 0xba, 0x69, 0x5a, 0x2e, 0x6f, 0x58 },
+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f },
+ { 0xd2, 0x96, 0xcd, 0x94, 0xc2, 0xcc, 0xcf, 0x8a,
+ 0x3a, 0x86, 0x30, 0x28, 0xb5, 0xe1, 0xdc, 0x0a,
+ 0x75, 0x86, 0x60, 0x2d, 0x25, 0x3c, 0xff, 0xf9,
+ 0x1b, 0x82, 0x66, 0xbe, 0xa6, 0xd6, 0x1a, 0xb1 },
+ 32
+ }
+ };
+ int ret = 0;
+ u8 *buf;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(vectors); i++) {
+ struct cbc_test_vector *tv = &vectors[i];
+
+ buf = os_malloc(tv->len);
+ if (buf == NULL) {
+ ret++;
+ break;
+ }
+
+ os_memcpy(buf, tv->plain, tv->len);
+ if (aes_128_cbc_encrypt(tv->key, tv->iv, buf, tv->len) ||
+ os_memcmp(buf, tv->cipher, tv->len) != 0) {
+ wpa_printf(MSG_ERROR, "AES-CBC encrypt %d failed", i);
+ ret++;
+ }
+
+ os_memcpy(buf, tv->cipher, tv->len);
+ if (aes_128_cbc_decrypt(tv->key, tv->iv, buf, tv->len) ||
+ os_memcmp(buf, tv->plain, tv->len) != 0) {
+ wpa_printf(MSG_ERROR, "AES-CBC decrypt %d failed", i);
+ ret++;
+ }
+
+ os_free(buf);
+ }
+
+ return ret;
+}
+
+
+static int test_ecb(void)
+{
+#ifdef EAP_PSK
+ struct ecb_test_vector {
+ char *key;
+ char *plaintext;
+ char *ciphertext;
+ } vectors[] = {
+ /* CAVS 11.1 - ECBGFSbox128.rsp */
+ {
+ "00000000000000000000000000000000",
+ "f34481ec3cc627bacd5dc3fb08f273e6",
+ "0336763e966d92595a567cc9ce537f5e"
+ },
+ {
+ "00000000000000000000000000000000",
+ "9798c4640bad75c7c3227db910174e72",
+ "a9a1631bf4996954ebc093957b234589"
+ },
+ {
+ "00000000000000000000000000000000",
+ "96ab5c2ff612d9dfaae8c31f30c42168",
+ "ff4f8391a6a40ca5b25d23bedd44a597"
+ },
+ {
+ "00000000000000000000000000000000",
+ "6a118a874519e64e9963798a503f1d35",
+ "dc43be40be0e53712f7e2bf5ca707209"
+ },
+ {
+ "00000000000000000000000000000000",
+ "cb9fceec81286ca3e989bd979b0cb284",
+ "92beedab1895a94faa69b632e5cc47ce"
+ },
+ {
+ "00000000000000000000000000000000",
+ "b26aeb1874e47ca8358ff22378f09144",
+ "459264f4798f6a78bacb89c15ed3d601"
+ },
+ {
+ "00000000000000000000000000000000",
+ "58c8e00b2631686d54eab84b91f0aca1",
+ "08a4e2efec8a8e3312ca7460b9040bbf"
+ },
+ /* CAVS 11.1 - ECBKeySbox128.rsp */
+ {
+ "10a58869d74be5a374cf867cfb473859",
+ "00000000000000000000000000000000",
+ "6d251e6944b051e04eaa6fb4dbf78465"
+ },
+ {
+ "caea65cdbb75e9169ecd22ebe6e54675",
+ "00000000000000000000000000000000",
+ "6e29201190152df4ee058139def610bb",
+ }
+ };
+ int ret = 0;
+ unsigned int i;
+ u8 key[16], plain[16], cipher[16], out[16];
+
+ for (i = 0; i < ARRAY_SIZE(vectors); i++) {
+ struct ecb_test_vector *tv = &vectors[i];
+
+ if (hexstr2bin(tv->key, key, sizeof(key)) ||
+ hexstr2bin(tv->plaintext, plain, sizeof(plain)) ||
+ hexstr2bin(tv->ciphertext, cipher, sizeof(cipher))) {
+ wpa_printf(MSG_ERROR, "Invalid AES-ECB test vector %u",
+ i);
+ ret++;
+ continue;
+ }
+
+ if (aes_128_encrypt_block(key, plain, out) < 0 ||
+ os_memcmp(out, cipher, 16) != 0) {
+ wpa_printf(MSG_ERROR, "AES-ECB encrypt %u failed", i);
+ ret++;
+ }
+ }
+
+ if (!ret)
+ wpa_printf(MSG_INFO, "AES ECB mode test cases passed");
+
+ return ret;
+#endif /* EAP_PSK */
+
+ return 0;
+}
+
+
+static int test_key_wrap(void)
+{
+ int ret = 0;
+
+ /* RFC 3394 - Test vector 4.1 */
+ u8 kek41[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
+ };
+ u8 plain41[] = {
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
+ };
+ u8 crypt41[] = {
+ 0x1F, 0xA6, 0x8B, 0x0A, 0x81, 0x12, 0xB4, 0x47,
+ 0xAE, 0xF3, 0x4B, 0xD8, 0xFB, 0x5A, 0x7B, 0x82,
+ 0x9D, 0x3E, 0x86, 0x23, 0x71, 0xD2, 0xCF, 0xE5
+ };
+ /* RFC 3394 - Test vector 4.2 */
+ u8 kek42[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
+ };
+ u8 plain42[] = {
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
+ };
+ u8 crypt42[] = {
+ 0x96, 0x77, 0x8B, 0x25, 0xAE, 0x6C, 0xA4, 0x35,
+ 0xF9, 0x2B, 0x5B, 0x97, 0xC0, 0x50, 0xAE, 0xD2,
+ 0x46, 0x8A, 0xB8, 0xA1, 0x7A, 0xD8, 0x4E, 0x5D
+ };
+ /* RFC 3394 - Test vector 4.3 */
+ u8 kek43[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
+ };
+ u8 plain43[] = {
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
+ };
+ u8 crypt43[] = {
+ 0x64, 0xE8, 0xC3, 0xF9, 0xCE, 0x0F, 0x5B, 0xA2,
+ 0x63, 0xE9, 0x77, 0x79, 0x05, 0x81, 0x8A, 0x2A,
+ 0x93, 0xC8, 0x19, 0x1E, 0x7D, 0x6E, 0x8A, 0xE7,
+ };
+ /* RFC 3394 - Test vector 4.4 */
+ u8 kek44[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
+ };
+ u8 plain44[] = {
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
+ };
+ u8 crypt44[] = {
+ 0x03, 0x1D, 0x33, 0x26, 0x4E, 0x15, 0xD3, 0x32,
+ 0x68, 0xF2, 0x4E, 0xC2, 0x60, 0x74, 0x3E, 0xDC,
+ 0xE1, 0xC6, 0xC7, 0xDD, 0xEE, 0x72, 0x5A, 0x93,
+ 0x6B, 0xA8, 0x14, 0x91, 0x5C, 0x67, 0x62, 0xD2
+ };
+ /* RFC 3394 - Test vector 4.5 */
+ u8 kek45[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
+ };
+ u8 plain45[] = {
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
+ };
+ u8 crypt45[] = {
+ 0xA8, 0xF9, 0xBC, 0x16, 0x12, 0xC6, 0x8B, 0x3F,
+ 0xF6, 0xE6, 0xF4, 0xFB, 0xE3, 0x0E, 0x71, 0xE4,
+ 0x76, 0x9C, 0x8B, 0x80, 0xA3, 0x2C, 0xB8, 0x95,
+ 0x8C, 0xD5, 0xD1, 0x7D, 0x6B, 0x25, 0x4D, 0xA1,
+ };
+ /* RFC 3394 - Test vector 4.6 */
+ u8 kek46[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
+ };
+ u8 plain46[] = {
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
+ };
+ u8 crypt46[] = {
+ 0x28, 0xC9, 0xF4, 0x04, 0xC4, 0xB8, 0x10, 0xF4,
+ 0xCB, 0xCC, 0xB3, 0x5C, 0xFB, 0x87, 0xF8, 0x26,
+ 0x3F, 0x57, 0x86, 0xE2, 0xD8, 0x0E, 0xD3, 0x26,
+ 0xCB, 0xC7, 0xF0, 0xE7, 0x1A, 0x99, 0xF4, 0x3B,
+ 0xFB, 0x98, 0x8B, 0x9B, 0x7A, 0x02, 0xDD, 0x21
+ };
+ u8 result[40];
+
+ wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.1");
+ if (aes_wrap(kek41, sizeof(kek41), sizeof(plain41) / 8, plain41,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-128 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, crypt41, sizeof(crypt41)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-128 failed");
+ ret++;
+ }
+ if (aes_unwrap(kek41, sizeof(kek41), sizeof(plain41) / 8, crypt41,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-128 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, plain41, sizeof(plain41)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-128 failed");
+ ret++;
+ }
+
+ wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.2");
+ if (aes_wrap(kek42, sizeof(kek42), sizeof(plain42) / 8, plain42,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-192 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, crypt42, sizeof(crypt42)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-192 failed");
+ ret++;
+ }
+ if (aes_unwrap(kek42, sizeof(kek42), sizeof(plain42) / 8, crypt42,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-192 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, plain42, sizeof(plain42)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-192 failed");
+ ret++;
+ }
+
+ wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.3");
+ if (aes_wrap(kek43, sizeof(kek43), sizeof(plain43) / 8, plain43,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-256 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, crypt43, sizeof(crypt43)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-256 failed");
+ ret++;
+ }
+ if (aes_unwrap(kek43, sizeof(kek43), sizeof(plain43) / 8, crypt43,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-256 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, plain43, sizeof(plain43)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-256 failed");
+ ret++;
+ }
+
+ wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.4");
+ if (aes_wrap(kek44, sizeof(kek44), sizeof(plain44) / 8, plain44,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-192 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, crypt44, sizeof(crypt44)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-192 failed");
+ ret++;
+ }
+ if (aes_unwrap(kek44, sizeof(kek44), sizeof(plain44) / 8, crypt44,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-192 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, plain44, sizeof(plain44)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-192 failed");
+ ret++;
+ }
+
+ wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.5");
+ if (aes_wrap(kek45, sizeof(kek45), sizeof(plain45) / 8, plain45,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-256 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, crypt45, sizeof(crypt45)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-256 failed");
+ ret++;
+ }
+ if (aes_unwrap(kek45, sizeof(kek45), sizeof(plain45) / 8, crypt45,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-256 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, plain45, sizeof(plain45)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-256 failed");
+ ret++;
+ }
+
+ wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.6");
+ if (aes_wrap(kek46, sizeof(kek46), sizeof(plain46) / 8, plain46,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-256 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, crypt46, sizeof(crypt46)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-256 failed");
+ ret++;
+ }
+ if (aes_unwrap(kek46, sizeof(kek46), sizeof(plain46) / 8, crypt46,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-256 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, plain46, sizeof(plain46)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-256 failed");
+ ret++;
+ }
+
+ if (!ret)
+ wpa_printf(MSG_INFO, "AES key wrap/unwrap test cases passed");
+
+ return ret;
+}
+
+
+static int test_md5(void)
+{
+ struct {
+ char *data;
+ char *hash;
+ } tests[] = {
+ {
+ "",
+ "\xd4\x1d\x8c\xd9\x8f\x00\xb2\x04"
+ "\xe9\x80\x09\x98\xec\xf8\x42\x7e"
+ },
+ {
+ "a",
+ "\x0c\xc1\x75\xb9\xc0\xf1\xb6\xa8"
+ "\x31\xc3\x99\xe2\x69\x77\x26\x61"
+ },
+ {
+ "abc",
+ "\x90\x01\x50\x98\x3c\xd2\x4f\xb0"
+ "\xd6\x96\x3f\x7d\x28\xe1\x7f\x72"
+ },
+ {
+ "message digest",
+ "\xf9\x6b\x69\x7d\x7c\xb7\x93\x8d"
+ "\x52\x5a\x2f\x31\xaa\xf1\x61\xd0"
+ },
+ {
+ "abcdefghijklmnopqrstuvwxyz",
+ "\xc3\xfc\xd3\xd7\x61\x92\xe4\x00"
+ "\x7d\xfb\x49\x6c\xca\x67\xe1\x3b"
+ },
+ {
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+ "0123456789",
+ "\xd1\x74\xab\x98\xd2\x77\xd9\xf5"
+ "\xa5\x61\x1c\x2c\x9f\x41\x9d\x9f"
+ },
+ {
+ "12345678901234567890123456789012345678901234567890"
+ "123456789012345678901234567890",
+ "\x57\xed\xf4\xa2\x2b\xe3\xc9\x55"
+ "\xac\x49\xda\x2e\x21\x07\xb6\x7a"
+ }
+ };
+ unsigned int i;
+ u8 hash[16];
+ const u8 *addr[2];
+ size_t len[2];
+ int errors = 0;
+
+ for (i = 0; i < ARRAY_SIZE(tests); i++) {
+ wpa_printf(MSG_INFO, "MD5 test case %d", i);
+
+ addr[0] = (u8 *) tests[i].data;
+ len[0] = strlen(tests[i].data);
+ if (md5_vector(1, addr, len, hash) < 0 ||
+ os_memcmp(hash, tests[i].hash, 16) != 0) {
+ wpa_printf(MSG_INFO, " FAIL");
+ errors++;
+ } else
+ wpa_printf(MSG_INFO, " OK");
+
+ if (len[0]) {
+ addr[0] = (u8 *) tests[i].data;
+ len[0] = strlen(tests[i].data);
+ addr[1] = (u8 *) tests[i].data + 1;
+ len[1] = strlen(tests[i].data) - 1;
+ if (md5_vector(1, addr, len, hash) < 0 ||
+ os_memcmp(hash, tests[i].hash, 16) != 0) {
+ wpa_printf(MSG_INFO, " FAIL");
+ errors++;
+ } else
+ wpa_printf(MSG_INFO, " OK");
+ }
+ }
+
+ if (!errors)
+ wpa_printf(MSG_INFO, "MD5 test cases passed");
+
+ return errors;
+}
+
+
+static int test_eap_fast(void)
+{
+#ifdef EAP_FAST
+ /* RFC 4851, Appendix B.1 */
+ const u8 pac_key[] = {
+ 0x0B, 0x97, 0x39, 0x0F, 0x37, 0x51, 0x78, 0x09,
+ 0x81, 0x1E, 0xFD, 0x9C, 0x6E, 0x65, 0x94, 0x2B,
+ 0x63, 0x2C, 0xE9, 0x53, 0x89, 0x38, 0x08, 0xBA,
+ 0x36, 0x0B, 0x03, 0x7C, 0xD1, 0x85, 0xE4, 0x14
+ };
+ const u8 seed[] = {
+ 0x3F, 0xFB, 0x11, 0xC4, 0x6C, 0xBF, 0xA5, 0x7A,
+ 0x54, 0x40, 0xDA, 0xE8, 0x22, 0xD3, 0x11, 0xD3,
+ 0xF7, 0x6D, 0xE4, 0x1D, 0xD9, 0x33, 0xE5, 0x93,
+ 0x70, 0x97, 0xEB, 0xA9, 0xB3, 0x66, 0xF4, 0x2A,
+ 0x00, 0x00, 0x00, 0x02, 0x6A, 0x66, 0x43, 0x2A,
+ 0x8D, 0x14, 0x43, 0x2C, 0xEC, 0x58, 0x2D, 0x2F,
+ 0xC7, 0x9C, 0x33, 0x64, 0xBA, 0x04, 0xAD, 0x3A,
+ 0x52, 0x54, 0xD6, 0xA5, 0x79, 0xAD, 0x1E, 0x00
+ };
+ const u8 master_secret[] = {
+ 0x4A, 0x1A, 0x51, 0x2C, 0x01, 0x60, 0xBC, 0x02,
+ 0x3C, 0xCF, 0xBC, 0x83, 0x3F, 0x03, 0xBC, 0x64,
+ 0x88, 0xC1, 0x31, 0x2F, 0x0B, 0xA9, 0xA2, 0x77,
+ 0x16, 0xA8, 0xD8, 0xE8, 0xBD, 0xC9, 0xD2, 0x29,
+ 0x38, 0x4B, 0x7A, 0x85, 0xBE, 0x16, 0x4D, 0x27,
+ 0x33, 0xD5, 0x24, 0x79, 0x87, 0xB1, 0xC5, 0xA2
+ };
+ const u8 key_block[] = {
+ 0x59, 0x59, 0xBE, 0x8E, 0x41, 0x3A, 0x77, 0x74,
+ 0x8B, 0xB2, 0xE5, 0xD3, 0x60, 0xAC, 0x4D, 0x35,
+ 0xDF, 0xFB, 0xC8, 0x1E, 0x9C, 0x24, 0x9C, 0x8B,
+ 0x0E, 0xC3, 0x1D, 0x72, 0xC8, 0x84, 0x9D, 0x57,
+ 0x48, 0x51, 0x2E, 0x45, 0x97, 0x6C, 0x88, 0x70,
+ 0xBE, 0x5F, 0x01, 0xD3, 0x64, 0xE7, 0x4C, 0xBB,
+ 0x11, 0x24, 0xE3, 0x49, 0xE2, 0x3B, 0xCD, 0xEF,
+ 0x7A, 0xB3, 0x05, 0x39, 0x5D, 0x64, 0x8A, 0x44,
+ 0x11, 0xB6, 0x69, 0x88, 0x34, 0x2E, 0x8E, 0x29,
+ 0xD6, 0x4B, 0x7D, 0x72, 0x17, 0x59, 0x28, 0x05,
+ 0xAF, 0xF9, 0xB7, 0xFF, 0x66, 0x6D, 0xA1, 0x96,
+ 0x8F, 0x0B, 0x5E, 0x06, 0x46, 0x7A, 0x44, 0x84,
+ 0x64, 0xC1, 0xC8, 0x0C, 0x96, 0x44, 0x09, 0x98,
+ 0xFF, 0x92, 0xA8, 0xB4, 0xC6, 0x42, 0x28, 0x71
+ };
+ const u8 sks[] = {
+ 0xD6, 0x4B, 0x7D, 0x72, 0x17, 0x59, 0x28, 0x05,
+ 0xAF, 0xF9, 0xB7, 0xFF, 0x66, 0x6D, 0xA1, 0x96,
+ 0x8F, 0x0B, 0x5E, 0x06, 0x46, 0x7A, 0x44, 0x84,
+ 0x64, 0xC1, 0xC8, 0x0C, 0x96, 0x44, 0x09, 0x98,
+ 0xFF, 0x92, 0xA8, 0xB4, 0xC6, 0x42, 0x28, 0x71
+ };
+ const u8 isk[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ const u8 imck[] = {
+ 0x16, 0x15, 0x3C, 0x3F, 0x21, 0x55, 0xEF, 0xD9,
+ 0x7F, 0x34, 0xAE, 0xC8, 0x1A, 0x4E, 0x66, 0x80,
+ 0x4C, 0xC3, 0x76, 0xF2, 0x8A, 0xA9, 0x6F, 0x96,
+ 0xC2, 0x54, 0x5F, 0x8C, 0xAB, 0x65, 0x02, 0xE1,
+ 0x18, 0x40, 0x7B, 0x56, 0xBE, 0xEA, 0xA7, 0xC5,
+ 0x76, 0x5D, 0x8F, 0x0B, 0xC5, 0x07, 0xC6, 0xB9,
+ 0x04, 0xD0, 0x69, 0x56, 0x72, 0x8B, 0x6B, 0xB8,
+ 0x15, 0xEC, 0x57, 0x7B
+ };
+ const u8 msk[] = {
+ 0x4D, 0x83, 0xA9, 0xBE, 0x6F, 0x8A, 0x74, 0xED,
+ 0x6A, 0x02, 0x66, 0x0A, 0x63, 0x4D, 0x2C, 0x33,
+ 0xC2, 0xDA, 0x60, 0x15, 0xC6, 0x37, 0x04, 0x51,
+ 0x90, 0x38, 0x63, 0xDA, 0x54, 0x3E, 0x14, 0xB9,
+ 0x27, 0x99, 0x18, 0x1E, 0x07, 0xBF, 0x0F, 0x5A,
+ 0x5E, 0x3C, 0x32, 0x93, 0x80, 0x8C, 0x6C, 0x49,
+ 0x67, 0xED, 0x24, 0xFE, 0x45, 0x40, 0xA0, 0x59,
+ 0x5E, 0x37, 0xC2, 0xE9, 0xD0, 0x5D, 0x0A, 0xE3
+ };
+ const u8 emsk[] = {
+ 0x3A, 0xD4, 0xAB, 0xDB, 0x76, 0xB2, 0x7F, 0x3B,
+ 0xEA, 0x32, 0x2C, 0x2B, 0x74, 0xF4, 0x28, 0x55,
+ 0xEF, 0x2D, 0xBA, 0x78, 0xC9, 0x57, 0x2F, 0x0D,
+ 0x06, 0xCD, 0x51, 0x7C, 0x20, 0x93, 0x98, 0xA9,
+ 0x76, 0xEA, 0x70, 0x21, 0xD7, 0x0E, 0x25, 0x54,
+ 0x97, 0xED, 0xB2, 0x8A, 0xF6, 0xED, 0xFD, 0x0A,
+ 0x2A, 0xE7, 0xA1, 0x58, 0x90, 0x10, 0x50, 0x44,
+ 0xB3, 0x82, 0x85, 0xDB, 0x06, 0x14, 0xD2, 0xF9
+ };
+ /* RFC 4851, Appendix B.2 */
+ u8 tlv[] = {
+ 0x80, 0x0C, 0x00, 0x38, 0x00, 0x01, 0x01, 0x00,
+ 0xD8, 0x6A, 0x8C, 0x68, 0x3C, 0x32, 0x31, 0xA8,
+ 0x56, 0x63, 0xB6, 0x40, 0x21, 0xFE, 0x21, 0x14,
+ 0x4E, 0xE7, 0x54, 0x20, 0x79, 0x2D, 0x42, 0x62,
+ 0xC9, 0xBF, 0x53, 0x7F, 0x54, 0xFD, 0xAC, 0x58,
+ 0x43, 0x24, 0x6E, 0x30, 0x92, 0x17, 0x6D, 0xCF,
+ 0xE6, 0xE0, 0x69, 0xEB, 0x33, 0x61, 0x6A, 0xCC,
+ 0x05, 0xC5, 0x5B, 0xB7
+ };
+ const u8 compound_mac[] = {
+ 0x43, 0x24, 0x6E, 0x30, 0x92, 0x17, 0x6D, 0xCF,
+ 0xE6, 0xE0, 0x69, 0xEB, 0x33, 0x61, 0x6A, 0xCC,
+ 0x05, 0xC5, 0x5B, 0xB7
+ };
+ u8 buf[512];
+ const u8 *simck, *cmk;
+ int errors = 0;
+
+ wpa_printf(MSG_INFO, "EAP-FAST test cases");
+
+ wpa_printf(MSG_INFO, "- T-PRF (SHA1) test case / master_secret");
+ if (sha1_t_prf(pac_key, sizeof(pac_key),
+ "PAC to master secret label hash",
+ seed, sizeof(seed), buf, sizeof(master_secret)) < 0 ||
+ os_memcmp(master_secret, buf, sizeof(master_secret)) != 0) {
+ wpa_printf(MSG_INFO, "T-PRF test - FAILED!");
+ errors++;
+ }
+
+ wpa_printf(MSG_INFO, "- PRF (TLS, SHA1/MD5) test case / key_block");
+ if (tls_prf_sha1_md5(master_secret, sizeof(master_secret),
+ "key expansion", seed, sizeof(seed),
+ buf, sizeof(key_block)) ||
+ os_memcmp(key_block, buf, sizeof(key_block)) != 0) {
+ wpa_printf(MSG_INFO, "PRF test - FAILED!");
+ errors++;
+ }
+
+ wpa_printf(MSG_INFO, "- T-PRF (SHA1) test case / IMCK");
+ if (sha1_t_prf(sks, sizeof(sks), "Inner Methods Compound Keys",
+ isk, sizeof(isk), buf, sizeof(imck)) < 0 ||
+ os_memcmp(imck, buf, sizeof(imck)) != 0) {
+ wpa_printf(MSG_INFO, "T-PRF test - FAILED!");
+ errors++;
+ }
+
+ simck = imck;
+ cmk = imck + 40;
+
+ wpa_printf(MSG_INFO, "- T-PRF (SHA1) test case / MSK");
+ if (sha1_t_prf(simck, 40, "Session Key Generating Function",
+ (u8 *) "", 0, buf, sizeof(msk)) < 0 ||
+ os_memcmp(msk, buf, sizeof(msk)) != 0) {
+ wpa_printf(MSG_INFO, "T-PRF test - FAILED!");
+ errors++;
+ }
+
+ wpa_printf(MSG_INFO, "- T-PRF (SHA1) test case / EMSK");
+ if (sha1_t_prf(simck, 40, "Extended Session Key Generating Function",
+ (u8 *) "", 0, buf, sizeof(msk)) < 0 ||
+ os_memcmp(emsk, buf, sizeof(emsk)) != 0) {
+ wpa_printf(MSG_INFO, "T-PRF test - FAILED!");
+ errors++;
+ }
+
+ wpa_printf(MSG_INFO, "- Compound MAC test case");
+ os_memset(tlv + sizeof(tlv) - 20, 0, 20);
+ if (hmac_sha1(cmk, 20, tlv, sizeof(tlv), tlv + sizeof(tlv) - 20) < 0 ||
+ os_memcmp(tlv + sizeof(tlv) - 20, compound_mac,
+ sizeof(compound_mac)) != 0) {
+ wpa_printf(MSG_INFO, "Compound MAC test - FAILED!");
+ errors++;
+ }
+
+ return errors;
+#else /* EAP_FAST */
+ return 0;
+#endif /* EAP_FAST */
+}
+
+
+static u8 key0[] =
+{
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b
+};
+static u8 data0[] = "Hi There";
+static u8 prf0[] =
+{
+ 0xbc, 0xd4, 0xc6, 0x50, 0xb3, 0x0b, 0x96, 0x84,
+ 0x95, 0x18, 0x29, 0xe0, 0xd7, 0x5f, 0x9d, 0x54,
+ 0xb8, 0x62, 0x17, 0x5e, 0xd9, 0xf0, 0x06, 0x06,
+ 0xe1, 0x7d, 0x8d, 0xa3, 0x54, 0x02, 0xff, 0xee,
+ 0x75, 0xdf, 0x78, 0xc3, 0xd3, 0x1e, 0x0f, 0x88,
+ 0x9f, 0x01, 0x21, 0x20, 0xc0, 0x86, 0x2b, 0xeb,
+ 0x67, 0x75, 0x3e, 0x74, 0x39, 0xae, 0x24, 0x2e,
+ 0xdb, 0x83, 0x73, 0x69, 0x83, 0x56, 0xcf, 0x5a
+};
+
+static u8 key1[] = "Jefe";
+static u8 data1[] = "what do ya want for nothing?";
+static u8 prf1[] =
+{
+ 0x51, 0xf4, 0xde, 0x5b, 0x33, 0xf2, 0x49, 0xad,
+ 0xf8, 0x1a, 0xeb, 0x71, 0x3a, 0x3c, 0x20, 0xf4,
+ 0xfe, 0x63, 0x14, 0x46, 0xfa, 0xbd, 0xfa, 0x58,
+ 0x24, 0x47, 0x59, 0xae, 0x58, 0xef, 0x90, 0x09,
+ 0xa9, 0x9a, 0xbf, 0x4e, 0xac, 0x2c, 0xa5, 0xfa,
+ 0x87, 0xe6, 0x92, 0xc4, 0x40, 0xeb, 0x40, 0x02,
+ 0x3e, 0x7b, 0xab, 0xb2, 0x06, 0xd6, 0x1d, 0xe7,
+ 0xb9, 0x2f, 0x41, 0x52, 0x90, 0x92, 0xb8, 0xfc
+};
+
+
+static u8 key2[] =
+{
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa
+};
+static u8 data2[] =
+{
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd
+};
+static u8 prf2[] =
+{
+ 0xe1, 0xac, 0x54, 0x6e, 0xc4, 0xcb, 0x63, 0x6f,
+ 0x99, 0x76, 0x48, 0x7b, 0xe5, 0xc8, 0x6b, 0xe1,
+ 0x7a, 0x02, 0x52, 0xca, 0x5d, 0x8d, 0x8d, 0xf1,
+ 0x2c, 0xfb, 0x04, 0x73, 0x52, 0x52, 0x49, 0xce,
+ 0x9d, 0xd8, 0xd1, 0x77, 0xea, 0xd7, 0x10, 0xbc,
+ 0x9b, 0x59, 0x05, 0x47, 0x23, 0x91, 0x07, 0xae,
+ 0xf7, 0xb4, 0xab, 0xd4, 0x3d, 0x87, 0xf0, 0xa6,
+ 0x8f, 0x1c, 0xbd, 0x9e, 0x2b, 0x6f, 0x76, 0x07
+};
+
+
+struct passphrase_test {
+ char *passphrase;
+ char *ssid;
+ char psk[32];
+};
+
+static struct passphrase_test passphrase_tests[] =
+{
+ {
+ "password",
+ "IEEE",
+ {
+ 0xf4, 0x2c, 0x6f, 0xc5, 0x2d, 0xf0, 0xeb, 0xef,
+ 0x9e, 0xbb, 0x4b, 0x90, 0xb3, 0x8a, 0x5f, 0x90,
+ 0x2e, 0x83, 0xfe, 0x1b, 0x13, 0x5a, 0x70, 0xe2,
+ 0x3a, 0xed, 0x76, 0x2e, 0x97, 0x10, 0xa1, 0x2e
+ }
+ },
+ {
+ "ThisIsAPassword",
+ "ThisIsASSID",
+ {
+ 0x0d, 0xc0, 0xd6, 0xeb, 0x90, 0x55, 0x5e, 0xd6,
+ 0x41, 0x97, 0x56, 0xb9, 0xa1, 0x5e, 0xc3, 0xe3,
+ 0x20, 0x9b, 0x63, 0xdf, 0x70, 0x7d, 0xd5, 0x08,
+ 0xd1, 0x45, 0x81, 0xf8, 0x98, 0x27, 0x21, 0xaf
+ }
+ },
+ {
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ",
+ {
+ 0xbe, 0xcb, 0x93, 0x86, 0x6b, 0xb8, 0xc3, 0x83,
+ 0x2c, 0xb7, 0x77, 0xc2, 0xf5, 0x59, 0x80, 0x7c,
+ 0x8c, 0x59, 0xaf, 0xcb, 0x6e, 0xae, 0x73, 0x48,
+ 0x85, 0x00, 0x13, 0x00, 0xa9, 0x81, 0xcc, 0x62
+ }
+ },
+};
+
+#define NUM_PASSPHRASE_TESTS ARRAY_SIZE(passphrase_tests)
+
+
+struct rfc6070_test {
+ char *p;
+ char *s;
+ int c;
+ char dk[32];
+ size_t dk_len;
+};
+
+static struct rfc6070_test rfc6070_tests[] =
+{
+ {
+ "password",
+ "salt",
+ 1,
+ {
+ 0x0c, 0x60, 0xc8, 0x0f, 0x96, 0x1f, 0x0e, 0x71,
+ 0xf3, 0xa9, 0xb5, 0x24, 0xaf, 0x60, 0x12, 0x06,
+ 0x2f, 0xe0, 0x37, 0xa6
+ },
+ 20
+ },
+ {
+ "password",
+ "salt",
+ 2,
+ {
+ 0xea, 0x6c, 0x01, 0x4d, 0xc7, 0x2d, 0x6f, 0x8c,
+ 0xcd, 0x1e, 0xd9, 0x2a, 0xce, 0x1d, 0x41, 0xf0,
+ 0xd8, 0xde, 0x89, 0x57
+ },
+ 20
+ },
+ {
+ "password",
+ "salt",
+ 4096,
+ {
+ 0x4b, 0x00, 0x79, 0x01, 0xb7, 0x65, 0x48, 0x9a,
+ 0xbe, 0xad, 0x49, 0xd9, 0x26, 0xf7, 0x21, 0xd0,
+ 0x65, 0xa4, 0x29, 0xc1
+ },
+ 20
+ },
+#if 0 /* This takes quite long to derive.. */
+ {
+ "password",
+ "salt",
+ 16777216,
+ {
+ 0xee, 0xfe, 0x3d, 0x61, 0xcd, 0x4d, 0xa4, 0xe4,
+ 0xe9, 0x94, 0x5b, 0x3d, 0x6b, 0xa2, 0x15, 0x8c,
+ 0x26, 0x34, 0xe9, 0x84
+ },
+ 20
+ },
+#endif
+ {
+ "passwordPASSWORDpassword",
+ "saltSALTsaltSALTsaltSALTsaltSALTsalt",
+ 4096,
+ {
+ 0x3d, 0x2e, 0xec, 0x4f, 0xe4, 0x1c, 0x84, 0x9b,
+ 0x80, 0xc8, 0xd8, 0x36, 0x62, 0xc0, 0xe4, 0x4a,
+ 0x8b, 0x29, 0x1a, 0x96, 0x4c, 0xf2, 0xf0, 0x70,
+ 0x38
+ },
+ 25
+ },
+#if 0 /* \0 not currently supported in passphrase parameters.. */
+ {
+ "pass\0word",
+ "sa\0lt",
+ 4096,
+ {
+ 0x56, 0xfa, 0x6a, 0xa7, 0x55, 0x48, 0x09, 0x9d,
+ 0xcc, 0x37, 0xd7, 0xf0, 0x34, 0x25, 0xe0, 0xc3
+ },
+ 16
+ },
+#endif
+};
+
+#define NUM_RFC6070_TESTS ARRAY_SIZE(rfc6070_tests)
+
+
+static int test_sha1(void)
+{
+ u8 res[512];
+ int ret = 0;
+ unsigned int i;
+
+ wpa_printf(MSG_INFO, "PRF-SHA1 test cases:");
+
+ if (sha1_prf(key0, sizeof(key0), "prefix", data0, sizeof(data0) - 1,
+ res, sizeof(prf0)) == 0 &&
+ os_memcmp(res, prf0, sizeof(prf0)) == 0)
+ wpa_printf(MSG_INFO, "Test case 0 - OK");
+ else {
+ wpa_printf(MSG_INFO, "Test case 0 - FAILED!");
+ ret++;
+ }
+
+ if (sha1_prf(key1, sizeof(key1) - 1, "prefix", data1, sizeof(data1) - 1,
+ res, sizeof(prf1)) == 0 &&
+ os_memcmp(res, prf1, sizeof(prf1)) == 0)
+ wpa_printf(MSG_INFO, "Test case 1 - OK");
+ else {
+ wpa_printf(MSG_INFO, "Test case 1 - FAILED!");
+ ret++;
+ }
+
+ if (sha1_prf(key2, sizeof(key2), "prefix", data2, sizeof(data2),
+ res, sizeof(prf2)) == 0 &&
+ os_memcmp(res, prf2, sizeof(prf2)) == 0)
+ wpa_printf(MSG_INFO, "Test case 2 - OK");
+ else {
+ wpa_printf(MSG_INFO, "Test case 2 - FAILED!");
+ ret++;
+ }
+
+ ret += test_eap_fast();
+
+ wpa_printf(MSG_INFO, "PBKDF2-SHA1 Passphrase test cases:");
+ for (i = 0; i < NUM_PASSPHRASE_TESTS; i++) {
+ u8 psk[32];
+ struct passphrase_test *test = &passphrase_tests[i];
+
+ if (pbkdf2_sha1(test->passphrase,
+ (const u8 *) test->ssid, strlen(test->ssid),
+ 4096, psk, 32) == 0 &&
+ os_memcmp(psk, test->psk, 32) == 0)
+ wpa_printf(MSG_INFO, "Test case %d - OK", i);
+ else {
+ wpa_printf(MSG_INFO, "Test case %d - FAILED!", i);
+ ret++;
+ }
+ }
+
+ wpa_printf(MSG_INFO, "PBKDF2-SHA1 test cases (RFC 6070):");
+ for (i = 0; i < NUM_RFC6070_TESTS; i++) {
+ u8 dk[25];
+ struct rfc6070_test *test = &rfc6070_tests[i];
+
+ if (pbkdf2_sha1(test->p, (const u8 *) test->s, strlen(test->s),
+ test->c, dk, test->dk_len) == 0 &&
+ os_memcmp(dk, test->dk, test->dk_len) == 0)
+ wpa_printf(MSG_INFO, "Test case %d - OK", i);
+ else {
+ wpa_printf(MSG_INFO, "Test case %d - FAILED!", i);
+ ret++;
+ }
+ }
+
+ if (!ret)
+ wpa_printf(MSG_INFO, "SHA1 test cases passed");
+ return ret;
+}
+
+
+struct {
+ char *data;
+ u8 hash[32];
+} tests[] = {
+ {
+ "abc",
+ {
+ 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea,
+ 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23,
+ 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
+ 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad
+ }
+ },
+ {
+ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+ {
+ 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8,
+ 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39,
+ 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67,
+ 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1
+ }
+ }
+};
+
+struct hmac_test {
+ u8 key[80];
+ size_t key_len;
+ u8 data[128];
+ size_t data_len;
+ u8 hash[32];
+} hmac_tests[] = {
+ /* draft-ietf-ipsec-ciph-sha-256-01.txt */
+ {
+ {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20
+ },
+ 32,
+ "abc", 3,
+ {
+ 0xa2, 0x1b, 0x1f, 0x5d, 0x4c, 0xf4, 0xf7, 0x3a,
+ 0x4d, 0xd9, 0x39, 0x75, 0x0f, 0x7a, 0x06, 0x6a,
+ 0x7f, 0x98, 0xcc, 0x13, 0x1c, 0xb1, 0x6a, 0x66,
+ 0x92, 0x75, 0x90, 0x21, 0xcf, 0xab, 0x81, 0x81
+ }
+ },
+ {
+ {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20
+ },
+ 32,
+ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+ 56,
+ {
+ 0x10, 0x4f, 0xdc, 0x12, 0x57, 0x32, 0x8f, 0x08,
+ 0x18, 0x4b, 0xa7, 0x31, 0x31, 0xc5, 0x3c, 0xae,
+ 0xe6, 0x98, 0xe3, 0x61, 0x19, 0x42, 0x11, 0x49,
+ 0xea, 0x8c, 0x71, 0x24, 0x56, 0x69, 0x7d, 0x30
+ }
+ },
+ {
+ {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20
+ },
+ 32,
+ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+ 112,
+ {
+ 0x47, 0x03, 0x05, 0xfc, 0x7e, 0x40, 0xfe, 0x34,
+ 0xd3, 0xee, 0xb3, 0xe7, 0x73, 0xd9, 0x5a, 0xab,
+ 0x73, 0xac, 0xf0, 0xfd, 0x06, 0x04, 0x47, 0xa5,
+ 0xeb, 0x45, 0x95, 0xbf, 0x33, 0xa9, 0xd1, 0xa3
+ }
+ },
+ {
+ {
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b
+ },
+ 32,
+ "Hi There",
+ 8,
+ {
+ 0x19, 0x8a, 0x60, 0x7e, 0xb4, 0x4b, 0xfb, 0xc6,
+ 0x99, 0x03, 0xa0, 0xf1, 0xcf, 0x2b, 0xbd, 0xc5,
+ 0xba, 0x0a, 0xa3, 0xf3, 0xd9, 0xae, 0x3c, 0x1c,
+ 0x7a, 0x3b, 0x16, 0x96, 0xa0, 0xb6, 0x8c, 0xf7
+ }
+ },
+ {
+ "Jefe",
+ 4,
+ "what do ya want for nothing?",
+ 28,
+ {
+ 0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e,
+ 0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7,
+ 0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83,
+ 0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43
+ }
+ },
+ {
+ {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
+ },
+ 32,
+ {
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd
+ },
+ 50,
+ {
+ 0xcd, 0xcb, 0x12, 0x20, 0xd1, 0xec, 0xcc, 0xea,
+ 0x91, 0xe5, 0x3a, 0xba, 0x30, 0x92, 0xf9, 0x62,
+ 0xe5, 0x49, 0xfe, 0x6c, 0xe9, 0xed, 0x7f, 0xdc,
+ 0x43, 0x19, 0x1f, 0xbd, 0xe4, 0x5c, 0x30, 0xb0
+ }
+ },
+ {
+ {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+ 0x21, 0x22, 0x23, 0x24, 0x25
+ },
+ 37,
+ {
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd
+ },
+ 50,
+ {
+ 0xd4, 0x63, 0x3c, 0x17, 0xf6, 0xfb, 0x8d, 0x74,
+ 0x4c, 0x66, 0xde, 0xe0, 0xf8, 0xf0, 0x74, 0x55,
+ 0x6e, 0xc4, 0xaf, 0x55, 0xef, 0x07, 0x99, 0x85,
+ 0x41, 0x46, 0x8e, 0xb4, 0x9b, 0xd2, 0xe9, 0x17
+ }
+ },
+ {
+ {
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c
+ },
+ 32,
+ "Test With Truncation",
+ 20,
+ {
+ 0x75, 0x46, 0xaf, 0x01, 0x84, 0x1f, 0xc0, 0x9b,
+ 0x1a, 0xb9, 0xc3, 0x74, 0x9a, 0x5f, 0x1c, 0x17,
+ 0xd4, 0xf5, 0x89, 0x66, 0x8a, 0x58, 0x7b, 0x27,
+ 0x00, 0xa9, 0xc9, 0x7c, 0x11, 0x93, 0xcf, 0x42
+ }
+ },
+ {
+ {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
+ },
+ 80,
+ "Test Using Larger Than Block-Size Key - Hash Key First",
+ 54,
+ {
+ 0x69, 0x53, 0x02, 0x5e, 0xd9, 0x6f, 0x0c, 0x09,
+ 0xf8, 0x0a, 0x96, 0xf7, 0x8e, 0x65, 0x38, 0xdb,
+ 0xe2, 0xe7, 0xb8, 0x20, 0xe3, 0xdd, 0x97, 0x0e,
+ 0x7d, 0xdd, 0x39, 0x09, 0x1b, 0x32, 0x35, 0x2f
+ }
+ },
+ {
+ {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
+ },
+ 80,
+ "Test Using Larger Than Block-Size Key and Larger Than One "
+ "Block-Size Data",
+ 73,
+ {
+ 0x63, 0x55, 0xac, 0x22, 0xe8, 0x90, 0xd0, 0xa3,
+ 0xc8, 0x48, 0x1a, 0x5c, 0xa4, 0x82, 0x5b, 0xc8,
+ 0x84, 0xd3, 0xe7, 0xa1, 0xff, 0x98, 0xa2, 0xfc,
+ 0x2a, 0xc7, 0xd8, 0xe0, 0x64, 0xc3, 0xb2, 0xe6
+ }
+ }
+};
+
+
+static int test_sha256(void)
+{
+ unsigned int i;
+ u8 hash[32];
+ const u8 *addr[2];
+ size_t len[2];
+ int errors = 0;
+
+ for (i = 0; i < ARRAY_SIZE(tests); i++) {
+ wpa_printf(MSG_INFO, "SHA256 test case %d:", i + 1);
+
+ addr[0] = (u8 *) tests[i].data;
+ len[0] = strlen(tests[i].data);
+ sha256_vector(1, addr, len, hash);
+ if (memcmp(hash, tests[i].hash, 32) != 0) {
+ wpa_printf(MSG_INFO, " FAIL");
+ errors++;
+ } else
+ wpa_printf(MSG_INFO, " OK");
+
+ if (len[0]) {
+ addr[0] = (u8 *) tests[i].data;
+ len[0] = 1;
+ addr[1] = (u8 *) tests[i].data + 1;
+ len[1] = strlen(tests[i].data) - 1;
+ sha256_vector(2, addr, len, hash);
+ if (memcmp(hash, tests[i].hash, 32) != 0) {
+ wpa_printf(MSG_INFO, " FAIL");
+ errors++;
+ } else
+ wpa_printf(MSG_INFO, " OK");
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(hmac_tests); i++) {
+ struct hmac_test *t = &hmac_tests[i];
+
+ wpa_printf(MSG_INFO, "HMAC-SHA256 test case %d:", i + 1);
+
+ if (hmac_sha256(t->key, t->key_len, t->data, t->data_len,
+ hash) < 0 ||
+ os_memcmp(hash, t->hash, 32) != 0) {
+ wpa_printf(MSG_INFO, " FAIL");
+ errors++;
+ } else
+ wpa_printf(MSG_INFO, " OK");
+
+ addr[0] = t->data;
+ len[0] = t->data_len;
+ if (hmac_sha256_vector(t->key, t->key_len, 1, addr, len,
+ hash) < 0 ||
+ os_memcmp(hash, t->hash, 32) != 0) {
+ wpa_printf(MSG_INFO, " FAIL");
+ errors++;
+ } else
+ wpa_printf(MSG_INFO, " OK");
+
+ if (len[0]) {
+ addr[0] = t->data;
+ len[0] = 1;
+ addr[1] = t->data + 1;
+ len[1] = t->data_len - 1;
+ if (hmac_sha256_vector(t->key, t->key_len, 2, addr, len,
+ hash) < 0 ||
+ os_memcmp(hash, t->hash, 32) != 0) {
+ wpa_printf(MSG_INFO, " FAIL");
+ errors++;
+ } else
+ wpa_printf(MSG_INFO, " OK");
+ }
+ }
+
+ wpa_printf(MSG_INFO, "Test IEEE 802.11r KDF");
+ sha256_prf((u8 *) "abc", 3, "KDF test", (u8 *) "data", 4,
+ hash, sizeof(hash));
+ /* TODO: add proper test case for this */
+
+ if (!errors)
+ wpa_printf(MSG_INFO, "SHA256 test cases passed");
+ return errors;
+}
+
+
+static int test_ms_funcs(void)
+{
+ /* Test vector from RFC2759 example */
+ char *username = "User";
+ char *password = "clientPass";
+ u8 auth_challenge[] = {
+ 0x5B, 0x5D, 0x7C, 0x7D, 0x7B, 0x3F, 0x2F, 0x3E,
+ 0x3C, 0x2C, 0x60, 0x21, 0x32, 0x26, 0x26, 0x28
+ };
+ u8 peer_challenge[] = {
+ 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A,
+ 0x28, 0x29, 0x5F, 0x2B, 0x3A, 0x33, 0x7C, 0x7E
+ };
+ u8 password_hash[] = {
+ 0x44, 0xEB, 0xBA, 0x8D, 0x53, 0x12, 0xB8, 0xD6,
+ 0x11, 0x47, 0x44, 0x11, 0xF5, 0x69, 0x89, 0xAE
+ };
+ u8 nt_response[] = {
+ 0x82, 0x30, 0x9E, 0xCD, 0x8D, 0x70, 0x8B, 0x5E,
+ 0xA0, 0x8F, 0xAA, 0x39, 0x81, 0xCD, 0x83, 0x54,
+ 0x42, 0x33, 0x11, 0x4A, 0x3D, 0x85, 0xD6, 0xDF
+ };
+ u8 password_hash_hash[] = {
+ 0x41, 0xC0, 0x0C, 0x58, 0x4B, 0xD2, 0xD9, 0x1C,
+ 0x40, 0x17, 0xA2, 0xA1, 0x2F, 0xA5, 0x9F, 0x3F
+ };
+ u8 authenticator_response[] = {
+ 0x40, 0x7A, 0x55, 0x89, 0x11, 0x5F, 0xD0, 0xD6,
+ 0x20, 0x9F, 0x51, 0x0F, 0xE9, 0xC0, 0x45, 0x66,
+ 0x93, 0x2C, 0xDA, 0x56
+ };
+ u8 master_key[] = {
+ 0xFD, 0xEC, 0xE3, 0x71, 0x7A, 0x8C, 0x83, 0x8C,
+ 0xB3, 0x88, 0xE5, 0x27, 0xAE, 0x3C, 0xDD, 0x31
+ };
+ u8 send_start_key[] = {
+ 0x8B, 0x7C, 0xDC, 0x14, 0x9B, 0x99, 0x3A, 0x1B,
+ 0xA1, 0x18, 0xCB, 0x15, 0x3F, 0x56, 0xDC, 0xCB
+ };
+ u8 buf[32];
+ int errors = 0;
+
+ if (nt_password_hash((u8 *) password, os_strlen(password), buf) ||
+ os_memcmp(password_hash, buf, sizeof(password_hash)) != 0) {
+ wpa_printf(MSG_ERROR, "nt_password_hash failed");
+ errors++;
+ }
+
+ if (generate_nt_response(auth_challenge, peer_challenge,
+ (u8 *) username, os_strlen(username),
+ (u8 *) password, os_strlen(password), buf) ||
+ os_memcmp(nt_response, buf, sizeof(nt_response)) != 0) {
+ wpa_printf(MSG_ERROR, "generate_nt_response failed");
+ errors++;
+ }
+
+ if (hash_nt_password_hash(password_hash, buf) ||
+ os_memcmp(password_hash_hash, buf,
+ sizeof(password_hash_hash)) != 0) {
+ wpa_printf(MSG_ERROR, "hash_nt_password_hash failed");
+ errors++;
+ }
+
+ if (generate_authenticator_response((u8 *) password,
+ os_strlen(password),
+ peer_challenge, auth_challenge,
+ (u8 *) username,
+ os_strlen(username),
+ nt_response, buf) ||
+ os_memcmp(authenticator_response, buf,
+ sizeof(authenticator_response)) != 0) {
+ wpa_printf(MSG_ERROR, "generate_authenticator_response failed");
+ errors++;
+ }
+
+ if (get_master_key(password_hash_hash, nt_response, buf) ||
+ os_memcmp(master_key, buf, sizeof(master_key)) != 0) {
+ wpa_printf(MSG_ERROR, "get_master_key failed");
+ errors++;
+ }
+
+ if (get_asymetric_start_key(master_key, buf, sizeof(send_start_key),
+ 1, 1) ||
+ os_memcmp(send_start_key, buf, sizeof(send_start_key)) != 0) {
+ wpa_printf(MSG_ERROR, "get_asymetric_start_key failed");
+ errors++;
+ }
+
+ if (errors)
+ wpa_printf(MSG_ERROR, "ms_funcs: %d errors", errors);
+ else
+ wpa_printf(MSG_INFO, "ms_funcs test cases passed");
+
+ return errors;
+}
+
+
+int crypto_module_tests(void)
+{
+ int ret = 0;
+
+ wpa_printf(MSG_INFO, "crypto module tests");
+ if (test_siv() ||
+ test_omac1() ||
+ test_eax() ||
+ test_cbc() ||
+ test_ecb() ||
+ test_key_wrap() ||
+ test_md5() ||
+ test_sha1() ||
+ test_sha256() ||
+ test_ms_funcs())
+ ret = -1;
+
+ return ret;
+}
diff --git a/src/crypto/crypto_nss.c b/src/crypto/crypto_nss.c
deleted file mode 100644
index acd0a55..0000000
--- a/src/crypto/crypto_nss.c
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Crypto wrapper functions for NSS
- * 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 "includes.h"
-#include <nspr/prtypes.h>
-#include <nspr/plarenas.h>
-#include <nspr/plhash.h>
-#include <nspr/prtime.h>
-#include <nspr/prinrval.h>
-#include <nspr/prclist.h>
-#include <nspr/prlock.h>
-#include <nss/sechash.h>
-#include <nss/pk11pub.h>
-
-#include "common.h"
-#include "crypto.h"
-
-
-static int nss_hash(HASH_HashType type, unsigned int max_res_len,
- size_t num_elem, const u8 *addr[], const size_t *len,
- u8 *mac)
-{
- HASHContext *ctx;
- size_t i;
- unsigned int reslen;
-
- ctx = HASH_Create(type);
- if (ctx == NULL)
- return -1;
-
- HASH_Begin(ctx);
- for (i = 0; i < num_elem; i++)
- HASH_Update(ctx, addr[i], len[i]);
- HASH_End(ctx, mac, &reslen, max_res_len);
- HASH_Destroy(ctx);
-
- return 0;
-}
-
-
-void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
-{
- PK11Context *ctx = NULL;
- PK11SlotInfo *slot;
- SECItem *param = NULL;
- PK11SymKey *symkey = NULL;
- SECItem item;
- int olen;
- u8 pkey[8], next, tmp;
- int i;
-
- /* Add parity bits to the key */
- next = 0;
- for (i = 0; i < 7; i++) {
- tmp = key[i];
- pkey[i] = (tmp >> i) | next | 1;
- next = tmp << (7 - i);
- }
- pkey[i] = next | 1;
-
- slot = PK11_GetBestSlot(CKM_DES_ECB, NULL);
- if (slot == NULL) {
- wpa_printf(MSG_ERROR, "NSS: PK11_GetBestSlot failed");
- goto out;
- }
-
- item.type = siBuffer;
- item.data = pkey;
- item.len = 8;
- symkey = PK11_ImportSymKey(slot, CKM_DES_ECB, PK11_OriginDerive,
- CKA_ENCRYPT, &item, NULL);
- if (symkey == NULL) {
- wpa_printf(MSG_ERROR, "NSS: PK11_ImportSymKey failed");
- goto out;
- }
-
- param = PK11_GenerateNewParam(CKM_DES_ECB, symkey);
- if (param == NULL) {
- wpa_printf(MSG_ERROR, "NSS: PK11_GenerateNewParam failed");
- goto out;
- }
-
- ctx = PK11_CreateContextBySymKey(CKM_DES_ECB, CKA_ENCRYPT,
- symkey, param);
- if (ctx == NULL) {
- wpa_printf(MSG_ERROR, "NSS: PK11_CreateContextBySymKey("
- "CKM_DES_ECB) failed");
- goto out;
- }
-
- if (PK11_CipherOp(ctx, cypher, &olen, 8, (void *) clear, 8) !=
- SECSuccess) {
- wpa_printf(MSG_ERROR, "NSS: PK11_CipherOp failed");
- goto out;
- }
-
-out:
- if (ctx)
- PK11_DestroyContext(ctx, PR_TRUE);
- if (symkey)
- PK11_FreeSymKey(symkey);
- if (param)
- SECITEM_FreeItem(param, PR_TRUE);
-}
-
-
-int rc4_skip(const u8 *key, size_t keylen, size_t skip,
- u8 *data, size_t data_len)
-{
- return -1;
-}
-
-
-int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
- return nss_hash(HASH_AlgMD5, 16, num_elem, addr, len, mac);
-}
-
-
-int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
- return nss_hash(HASH_AlgSHA1, 20, num_elem, addr, len, mac);
-}
-
-
-int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
- u8 *mac)
-{
- return nss_hash(HASH_AlgSHA256, 32, num_elem, addr, len, mac);
-}
-
-
-void * aes_encrypt_init(const u8 *key, size_t len)
-{
- return NULL;
-}
-
-
-void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
-{
-}
-
-
-void aes_encrypt_deinit(void *ctx)
-{
-}
-
-
-void * aes_decrypt_init(const u8 *key, size_t len)
-{
- return NULL;
-}
-
-
-void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
-{
-}
-
-
-void aes_decrypt_deinit(void *ctx)
-{
-}
-
-
-int crypto_mod_exp(const u8 *base, size_t base_len,
- const u8 *power, size_t power_len,
- const u8 *modulus, size_t modulus_len,
- u8 *result, size_t *result_len)
-{
- return -1;
-}
-
-
-struct crypto_cipher {
-};
-
-
-struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
- const u8 *iv, const u8 *key,
- size_t key_len)
-{
- return NULL;
-}
-
-
-int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
- u8 *crypt, size_t len)
-{
- return -1;
-}
-
-
-int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
- u8 *plain, size_t len)
-{
- return -1;
-}
-
-
-void crypto_cipher_deinit(struct crypto_cipher *ctx)
-{
-}
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index b4c59d1..f79055c 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -1,6 +1,6 @@
/*
* Wrapper functions for OpenSSL libcrypto
- * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -28,6 +28,7 @@
#include "dh_group5.h"
#include "sha1.h"
#include "sha256.h"
+#include "sha384.h"
#include "crypto.h"
#if OPENSSL_VERSION_NUMBER < 0x00907000
@@ -258,7 +259,7 @@
"in AES encrypt", len);
}
EVP_CIPHER_CTX_cleanup(c);
- os_free(c);
+ bin_clear_free(c, sizeof(*c));
}
@@ -309,7 +310,7 @@
"in AES decrypt", len);
}
EVP_CIPHER_CTX_cleanup(c);
- os_free(ctx);
+ bin_clear_free(c, sizeof(*c));
}
@@ -507,8 +508,8 @@
return dh;
err:
- wpabuf_free(pubkey);
- wpabuf_free(privkey);
+ wpabuf_clear_free(pubkey);
+ wpabuf_clear_free(privkey);
DH_free(dh);
return NULL;
}
@@ -581,7 +582,7 @@
err:
BN_clear_free(pub_key);
- wpabuf_free(res);
+ wpabuf_clear_free(res);
return NULL;
}
@@ -638,7 +639,7 @@
HMAC_Init_ex(&ctx->ctx, key, key_len, md, NULL);
#else /* openssl < 0.9.9 */
if (HMAC_Init_ex(&ctx->ctx, key, key_len, md, NULL) != 1) {
- os_free(ctx);
+ bin_clear_free(ctx, sizeof(*ctx));
return NULL;
}
#endif /* openssl < 0.9.9 */
@@ -664,7 +665,7 @@
return -2;
if (mac == NULL || len == NULL) {
- os_free(ctx);
+ bin_clear_free(ctx, sizeof(*ctx));
return 0;
}
@@ -676,7 +677,7 @@
res = HMAC_Final(&ctx->ctx, mac, &mdlen);
#endif /* openssl < 0.9.9 */
HMAC_CTX_cleanup(&ctx->ctx);
- os_free(ctx);
+ bin_clear_free(ctx, sizeof(*ctx));
if (res == 1) {
*len = mdlen;
@@ -693,11 +694,11 @@
#if OPENSSL_VERSION_NUMBER < 0x00908000
if (PKCS5_PBKDF2_HMAC_SHA1(passphrase, os_strlen(passphrase),
(unsigned char *) ssid,
- ssid_len, 4096, buflen, buf) != 1)
+ ssid_len, iterations, buflen, buf) != 1)
return -1;
#else /* openssl < 0.9.8 */
if (PKCS5_PBKDF2_HMAC_SHA1(passphrase, os_strlen(passphrase), ssid,
- ssid_len, 4096, buflen, buf) != 1)
+ ssid_len, iterations, buflen, buf) != 1)
return -1;
#endif /* openssl < 0.9.8 */
return 0;
@@ -786,6 +787,40 @@
#endif /* CONFIG_SHA256 */
+#ifdef CONFIG_SHA384
+
+int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ HMAC_CTX ctx;
+ size_t i;
+ unsigned int mdlen;
+ int res;
+
+ HMAC_CTX_init(&ctx);
+ if (HMAC_Init_ex(&ctx, key, key_len, EVP_sha384(), NULL) != 1)
+ return -1;
+
+ for (i = 0; i < num_elem; i++)
+ HMAC_Update(&ctx, addr[i], len[i]);
+
+ mdlen = 32;
+ res = HMAC_Final(&ctx, mac, &mdlen);
+ HMAC_CTX_cleanup(&ctx);
+
+ return res == 1 ? 0 : -1;
+}
+
+
+int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha384_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA384 */
+
+
int crypto_get_random(void *buf, size_t len)
{
if (RAND_bytes(buf, len) != 1)
@@ -795,8 +830,8 @@
#ifdef CONFIG_OPENSSL_CMAC
-int omac1_aes_128_vector(const u8 *key, size_t num_elem,
- const u8 *addr[], const size_t *len, u8 *mac)
+int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
{
CMAC_CTX *ctx;
int ret = -1;
@@ -806,8 +841,15 @@
if (ctx == NULL)
return -1;
- if (!CMAC_Init(ctx, key, 16, EVP_aes_128_cbc(), NULL))
+ if (key_len == 32) {
+ if (!CMAC_Init(ctx, key, 32, EVP_aes_256_cbc(), NULL))
+ goto fail;
+ } else if (key_len == 16) {
+ if (!CMAC_Init(ctx, key, 16, EVP_aes_128_cbc(), NULL))
+ goto fail;
+ } else {
goto fail;
+ }
for (i = 0; i < num_elem; i++) {
if (!CMAC_Update(ctx, addr[i], len[i]))
goto fail;
@@ -822,10 +864,23 @@
}
+int omac1_aes_128_vector(const u8 *key, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return omac1_aes_vector(key, 16, num_elem, addr, len, mac);
+}
+
+
int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
{
return omac1_aes_128_vector(key, 1, &data, &data_len, mac);
}
+
+
+int omac1_aes_256(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+ return omac1_aes_vector(key, 32, 1, &data, &data_len, mac);
+}
#endif /* CONFIG_OPENSSL_CMAC */
diff --git a/src/crypto/dh_groups.c b/src/crypto/dh_groups.c
index 58e94c3..d3b2631 100644
--- a/src/crypto/dh_groups.c
+++ b/src/crypto/dh_groups.c
@@ -1198,14 +1198,14 @@
if (dh == NULL)
return NULL;
- wpabuf_free(*priv);
+ wpabuf_clear_free(*priv);
*priv = wpabuf_alloc(dh->prime_len);
if (*priv == NULL)
return NULL;
if (random_get_bytes(wpabuf_put(*priv, dh->prime_len), dh->prime_len))
{
- wpabuf_free(*priv);
+ wpabuf_clear_free(*priv);
*priv = NULL;
return NULL;
}
@@ -1224,7 +1224,7 @@
wpabuf_head(*priv), wpabuf_len(*priv),
dh->prime, dh->prime_len, wpabuf_mhead(pv),
&pv_len) < 0) {
- wpabuf_free(pv);
+ wpabuf_clear_free(pv);
wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed");
return NULL;
}
@@ -1260,7 +1260,7 @@
wpabuf_head(own_private), wpabuf_len(own_private),
dh->prime, dh->prime_len,
wpabuf_mhead(shared), &shared_len) < 0) {
- wpabuf_free(shared);
+ wpabuf_clear_free(shared);
wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed");
return NULL;
}
diff --git a/src/crypto/md5.c b/src/crypto/md5.c
index db2b8cc..f64dfd3 100644
--- a/src/crypto/md5.c
+++ b/src/crypto/md5.c
@@ -30,6 +30,7 @@
u8 tk[16];
const u8 *_addr[6];
size_t i, _len[6];
+ int res;
if (num_elem > 5) {
/*
@@ -85,7 +86,10 @@
_len[0] = 64;
_addr[1] = mac;
_len[1] = MD5_MAC_LEN;
- return md5_vector(2, _addr, _len, mac);
+ res = md5_vector(2, _addr, _len, mac);
+ os_memset(k_pad, 0, sizeof(k_pad));
+ os_memset(tk, 0, sizeof(tk));
+ return res;
}
diff --git a/src/crypto/random.c b/src/crypto/random.c
index 053740e..bc758aa 100644
--- a/src/crypto/random.c
+++ b/src/crypto/random.c
@@ -232,12 +232,8 @@
*/
fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
if (fd < 0) {
-#ifndef CONFIG_NO_STDOUT_DEBUG
- int error = errno;
- perror("open(/dev/random)");
wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s",
- strerror(error));
-#endif /* CONFIG_NO_STDOUT_DEBUG */
+ strerror(errno));
return -1;
}
@@ -417,12 +413,8 @@
random_fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
if (random_fd < 0) {
-#ifndef CONFIG_NO_STDOUT_DEBUG
- int error = errno;
- perror("open(/dev/random)");
wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s",
- strerror(error));
-#endif /* CONFIG_NO_STDOUT_DEBUG */
+ strerror(errno));
return;
}
wpa_printf(MSG_DEBUG, "random: Trying to read entropy from "
diff --git a/src/crypto/sha1-prf.c b/src/crypto/sha1-prf.c
index 90b9e74..4b2d137 100644
--- a/src/crypto/sha1-prf.c
+++ b/src/crypto/sha1-prf.c
@@ -61,6 +61,7 @@
}
counter++;
}
+ os_memset(hash, 0, sizeof(hash));
return 0;
}
diff --git a/src/crypto/sha1.c b/src/crypto/sha1.c
index d48c77d..8fce139 100644
--- a/src/crypto/sha1.c
+++ b/src/crypto/sha1.c
@@ -30,6 +30,7 @@
unsigned char tk[20];
const u8 *_addr[6];
size_t _len[6], i;
+ int ret;
if (num_elem > 5) {
/*
@@ -84,7 +85,9 @@
_len[0] = 64;
_addr[1] = mac;
_len[1] = SHA1_MAC_LEN;
- return sha1_vector(2, _addr, _len, mac);
+ ret = sha1_vector(2, _addr, _len, mac);
+ os_memset(k_pad, 0, sizeof(k_pad));
+ return ret;
}
diff --git a/src/crypto/sha256-kdf.c b/src/crypto/sha256-kdf.c
new file mode 100644
index 0000000..d8a1beb
--- /dev/null
+++ b/src/crypto/sha256-kdf.c
@@ -0,0 +1,76 @@
+/*
+ * HMAC-SHA256 KDF (RFC 5295)
+ * Copyright (c) 2014, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha256.h"
+
+
+/**
+ * hmac_sha256_kdf - HMAC-SHA256 based KDF (RFC 5295)
+ * @secret: Key for KDF
+ * @secret_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the KDF
+ * @seed: Seed value to bind into the key
+ * @seed_len: Length of the seed
+ * @out: Buffer for the generated pseudo-random key
+ * @outlen: Number of bytes of key to generate
+ * Returns: 0 on success, -1 on failure.
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key in ERP. This KDF is defined in RFC 5295, Chapter 3.1.2.
+ */
+int hmac_sha256_kdf(const u8 *secret, size_t secret_len,
+ const char *label, const u8 *seed, size_t seed_len,
+ u8 *out, size_t outlen)
+{
+ u8 T[SHA256_MAC_LEN];
+ u8 iter = 1;
+ const unsigned char *addr[4];
+ size_t len[4];
+ size_t pos, clen;
+
+ addr[0] = T;
+ len[0] = SHA256_MAC_LEN;
+ addr[1] = (const unsigned char *) label;
+ len[1] = os_strlen(label) + 1;
+ addr[2] = seed;
+ len[2] = seed_len;
+ addr[3] = &iter;
+ len[3] = 1;
+
+ if (hmac_sha256_vector(secret, secret_len, 3, &addr[1], &len[1], T) < 0)
+ return -1;
+
+ pos = 0;
+ for (;;) {
+ clen = outlen - pos;
+ if (clen > SHA256_MAC_LEN)
+ clen = SHA256_MAC_LEN;
+ os_memcpy(out + pos, T, clen);
+ pos += clen;
+
+ if (pos == outlen)
+ break;
+
+ if (iter == 255) {
+ os_memset(out, 0, outlen);
+ return -1;
+ }
+ iter++;
+
+ if (hmac_sha256_vector(secret, secret_len, 4, addr, len, T) < 0)
+ {
+ os_memset(out, 0, outlen);
+ return -1;
+ }
+ }
+
+ return 0;
+}
diff --git a/src/crypto/sha256-prf.c b/src/crypto/sha256-prf.c
index 9a11208..79791c0 100644
--- a/src/crypto/sha256-prf.c
+++ b/src/crypto/sha256-prf.c
@@ -95,4 +95,6 @@
u8 mask = 0xff << (8 - buf_len_bits % 8);
buf[pos - 1] &= mask;
}
+
+ os_memset(hash, 0, sizeof(hash));
}
diff --git a/src/crypto/sha256.h b/src/crypto/sha256.h
index 7596a52..b15f511 100644
--- a/src/crypto/sha256.h
+++ b/src/crypto/sha256.h
@@ -1,6 +1,6 @@
/*
* SHA256 hash implementation and interface functions
- * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -23,5 +23,8 @@
void tls_prf_sha256(const u8 *secret, size_t secret_len,
const char *label, const u8 *seed, size_t seed_len,
u8 *out, size_t outlen);
+int hmac_sha256_kdf(const u8 *secret, size_t secret_len,
+ const char *label, const u8 *seed, size_t seed_len,
+ u8 *out, size_t outlen);
#endif /* SHA256_H */
diff --git a/src/crypto/sha384.h b/src/crypto/sha384.h
new file mode 100644
index 0000000..e6a1fe4
--- /dev/null
+++ b/src/crypto/sha384.h
@@ -0,0 +1,19 @@
+/*
+ * SHA384 hash implementation and interface functions
+ * 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 SHA384_H
+#define SHA384_H
+
+#define SHA384_MAC_LEN 48
+
+int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac);
+int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac);
+
+#endif /* SHA384_H */
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index 65e0f79..9ae95a6 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -41,9 +41,13 @@
TLS_FAIL_ALTSUBJECT_MISMATCH = 6,
TLS_FAIL_BAD_CERTIFICATE = 7,
TLS_FAIL_SERVER_CHAIN_PROBE = 8,
- TLS_FAIL_DOMAIN_SUFFIX_MISMATCH = 9
+ TLS_FAIL_DOMAIN_SUFFIX_MISMATCH = 9,
+ TLS_FAIL_DOMAIN_MISMATCH = 10,
};
+
+#define TLS_MAX_ALT_SUBJECT 10
+
union tls_event_data {
struct {
int depth;
@@ -59,6 +63,8 @@
const struct wpabuf *cert;
const u8 *hash;
size_t hash_len;
+ const char *altsubject[TLS_MAX_ALT_SUBJECT];
+ int num_altsubject;
} peer_cert;
struct {
@@ -74,6 +80,7 @@
const char *pkcs11_module_path;
int fips_mode;
int cert_in_cb;
+ const char *openssl_ciphers;
void (*event_cb)(void *ctx, enum tls_event ev,
union tls_event_data *data);
@@ -87,6 +94,7 @@
#define TLS_CONN_REQUIRE_OCSP BIT(4)
#define TLS_CONN_DISABLE_TLSv1_1 BIT(5)
#define TLS_CONN_DISABLE_TLSv1_2 BIT(6)
+#define TLS_CONN_EAP_FAST BIT(7)
/**
* struct tls_connection_params - Parameters for TLS connection
@@ -100,7 +108,11 @@
* @altsubject_match: String to match in the alternative subject of the peer
* certificate or %NULL to allow all alternative subjects
* @suffix_match: String to suffix match in the dNSName or CN of the peer
- * certificate or %NULL to allow all domain names
+ * certificate or %NULL to allow all domain names. This may allow subdomains an
+ * wildcard certificates. Each domain name label must have a full match.
+ * @domain_match: String to match in the dNSName or CN of the peer
+ * certificate or %NULL to allow all domain names. This requires a full,
+ * case-insensitive match.
* @client_cert: File or reference name for client X.509 certificate in PEM or
* DER format
* @client_cert_blob: client_cert as inlined data or %NULL if not used
@@ -123,6 +135,7 @@
* specific for now)
* @cert_id: the certificate's id when using engine
* @ca_cert_id: the CA certificate's id when using engine
+ * @openssl_ciphers: OpenSSL cipher configuration
* @flags: Parameter options (TLS_CONN_*)
* @ocsp_stapling_response: DER encoded file with cached OCSP stapling response
* or %NULL if OCSP is not enabled
@@ -143,6 +156,7 @@
const char *subject_match;
const char *altsubject_match;
const char *suffix_match;
+ const char *domain_match;
const char *client_cert;
const u8 *client_cert_blob;
size_t client_cert_blob_len;
@@ -161,6 +175,7 @@
const char *key_id;
const char *cert_id;
const char *ca_cert_id;
+ const char *openssl_ciphers;
unsigned int flags;
const char *ocsp_stapling_response;
@@ -552,4 +567,6 @@
void tls_connection_set_test_flags(struct tls_connection *conn, u32 flags);
+int tls_get_library_version(char *buf, size_t buf_len);
+
#endif /* TLS_H */
diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c
index cb23eb9..65db6fc 100644
--- a/src/crypto/tls_gnutls.c
+++ b/src/crypto/tls_gnutls.c
@@ -12,61 +12,15 @@
#ifdef PKCS12_FUNCS
#include <gnutls/pkcs12.h>
#endif /* PKCS12_FUNCS */
+#if GNUTLS_VERSION_NUMBER >= 0x030103
+#include <gnutls/ocsp.h>
+#endif /* 3.1.3 */
#include "common.h"
+#include "crypto/crypto.h"
#include "tls.h"
-#define WPA_TLS_RANDOM_SIZE 32
-#define WPA_TLS_MASTER_SIZE 48
-
-
-#if LIBGNUTLS_VERSION_NUMBER < 0x010302
-/* GnuTLS 1.3.2 added functions for using master secret. Older versions require
- * use of internal structures to get the master_secret and
- * {server,client}_random.
- */
-#define GNUTLS_INTERNAL_STRUCTURE_HACK
-#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
-
-
-#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
-/*
- * It looks like gnutls does not provide access to client/server_random and
- * master_key. This is somewhat unfortunate since these are needed for key
- * derivation in EAP-{TLS,TTLS,PEAP,FAST}. Workaround for now is a horrible
- * hack that copies the gnutls_session_int definition from gnutls_int.h so that
- * we can get the needed information.
- */
-
-typedef u8 uint8;
-typedef unsigned char opaque;
-typedef struct {
- uint8 suite[2];
-} cipher_suite_st;
-
-typedef struct {
- gnutls_connection_end_t entity;
- gnutls_kx_algorithm_t kx_algorithm;
- gnutls_cipher_algorithm_t read_bulk_cipher_algorithm;
- gnutls_mac_algorithm_t read_mac_algorithm;
- gnutls_compression_method_t read_compression_algorithm;
- gnutls_cipher_algorithm_t write_bulk_cipher_algorithm;
- gnutls_mac_algorithm_t write_mac_algorithm;
- gnutls_compression_method_t write_compression_algorithm;
- cipher_suite_st current_cipher_suite;
- opaque master_secret[WPA_TLS_MASTER_SIZE];
- opaque client_random[WPA_TLS_RANDOM_SIZE];
- opaque server_random[WPA_TLS_RANDOM_SIZE];
- /* followed by stuff we are not interested in */
-} security_parameters_st;
-
-struct gnutls_session_int {
- security_parameters_st security_parameters;
- /* followed by things we are not interested in */
-};
-#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
-
static int tls_gnutls_ref_count = 0;
struct tls_global {
@@ -78,17 +32,23 @@
int params_set;
gnutls_certificate_credentials_t xcred;
+
+ void (*event_cb)(void *ctx, enum tls_event ev,
+ union tls_event_data *data);
+ void *cb_ctx;
+ int cert_in_cb;
};
struct tls_connection {
- gnutls_session session;
- char *subject_match, *altsubject_match;
+ struct tls_global *global;
+ gnutls_session_t session;
int read_alerts, write_alerts, failed;
u8 *pre_shared_secret;
size_t pre_shared_secret_len;
int established;
int verify_peer;
+ unsigned int disable_time_checks:1;
struct wpabuf *push_buf;
struct wpabuf *pull_buf;
@@ -96,9 +56,16 @@
int params_set;
gnutls_certificate_credentials_t xcred;
+
+ char *suffix_match;
+ char *domain_match;
+ unsigned int flags;
};
+static int tls_connection_verify_peer(gnutls_session_t session);
+
+
static void tls_log_func(int level, const char *msg)
{
char *s, *pos;
@@ -129,17 +96,11 @@
{
struct tls_global *global;
-#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
- /* Because of the horrible hack to get master_secret and client/server
- * random, we need to make sure that the gnutls version is something
- * that is expected to have same structure definition for the session
- * data.. */
- const char *ver;
- const char *ok_ver[] = { "1.2.3", "1.2.4", "1.2.5", "1.2.6", "1.2.9",
- "1.3.2",
- NULL };
- int i;
-#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
+ if (tls_gnutls_ref_count == 0) {
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: Library version %s (runtime) - %s (build)",
+ gnutls_check_version(NULL), GNUTLS_VERSION);
+ }
global = os_zalloc(sizeof(*global));
if (global == NULL)
@@ -151,28 +112,16 @@
}
tls_gnutls_ref_count++;
-#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
- ver = gnutls_check_version(NULL);
- if (ver == NULL) {
- tls_deinit(global);
- return NULL;
- }
- wpa_printf(MSG_DEBUG, "%s - gnutls version %s", __func__, ver);
- for (i = 0; ok_ver[i]; i++) {
- if (strcmp(ok_ver[i], ver) == 0)
- break;
- }
- if (ok_ver[i] == NULL) {
- wpa_printf(MSG_INFO, "Untested gnutls version %s - this needs "
- "to be tested and enabled in tls_gnutls.c", ver);
- tls_deinit(global);
- return NULL;
- }
-#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
-
gnutls_global_set_log_function(tls_log_func);
if (wpa_debug_show_keys)
gnutls_global_set_log_level(11);
+
+ if (conf) {
+ global->event_cb = conf->event_cb;
+ global->cb_ctx = conf->cb_ctx;
+ global->cert_in_cb = conf->cert_in_cb;
+ }
+
return global;
}
@@ -199,7 +148,7 @@
}
-static ssize_t tls_pull_func(gnutls_transport_ptr ptr, void *buf,
+static ssize_t tls_pull_func(gnutls_transport_ptr_t ptr, void *buf,
size_t len)
{
struct tls_connection *conn = (struct tls_connection *) ptr;
@@ -228,7 +177,7 @@
}
-static ssize_t tls_push_func(gnutls_transport_ptr ptr, const void *buf,
+static ssize_t tls_push_func(gnutls_transport_ptr_t ptr, const void *buf,
size_t len)
{
struct tls_connection *conn = (struct tls_connection *) ptr;
@@ -246,12 +195,7 @@
static int tls_gnutls_init_session(struct tls_global *global,
struct tls_connection *conn)
{
-#if LIBGNUTLS_VERSION_NUMBER >= 0x020200
const char *err;
-#else /* LIBGNUTLS_VERSION_NUMBER >= 0x020200 */
- const int cert_types[2] = { GNUTLS_CRT_X509, 0 };
- const int protos[2] = { GNUTLS_TLS1, 0 };
-#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020200 */
int ret;
ret = gnutls_init(&conn->session,
@@ -266,7 +210,6 @@
if (ret < 0)
goto fail;
-#if LIBGNUTLS_VERSION_NUMBER >= 0x020200
ret = gnutls_priority_set_direct(conn->session, "NORMAL:-VERS-SSL3.0",
&err);
if (ret < 0) {
@@ -274,19 +217,11 @@
"'%s'", err);
goto fail;
}
-#else /* LIBGNUTLS_VERSION_NUMBER >= 0x020200 */
- ret = gnutls_certificate_type_set_priority(conn->session, cert_types);
- if (ret < 0)
- goto fail;
-
- ret = gnutls_protocol_set_priority(conn->session, protos);
- if (ret < 0)
- goto fail;
-#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020200 */
gnutls_transport_set_pull_function(conn->session, tls_pull_func);
gnutls_transport_set_push_function(conn->session, tls_push_func);
- gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr) conn);
+ gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr_t) conn);
+ gnutls_session_set_ptr(conn->session, conn);
return 0;
@@ -307,6 +242,7 @@
conn = os_zalloc(sizeof(*conn));
if (conn == NULL)
return NULL;
+ conn->global = global;
if (tls_gnutls_init_session(global, conn)) {
os_free(conn);
@@ -342,10 +278,10 @@
gnutls_certificate_free_credentials(conn->xcred);
gnutls_deinit(conn->session);
os_free(conn->pre_shared_secret);
- os_free(conn->subject_match);
- os_free(conn->altsubject_match);
wpabuf_free(conn->push_buf);
wpabuf_free(conn->pull_buf);
+ os_free(conn->suffix_match);
+ os_free(conn->domain_match);
os_free(conn);
}
@@ -403,104 +339,6 @@
}
-#if 0
-static int tls_match_altsubject(X509 *cert, const char *match)
-{
- GENERAL_NAME *gen;
- char *field, *tmp;
- void *ext;
- int i, found = 0;
- size_t len;
-
- ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
-
- for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
- gen = sk_GENERAL_NAME_value(ext, i);
- switch (gen->type) {
- case GEN_EMAIL:
- field = "EMAIL";
- break;
- case GEN_DNS:
- field = "DNS";
- break;
- case GEN_URI:
- field = "URI";
- break;
- default:
- field = NULL;
- wpa_printf(MSG_DEBUG, "TLS: altSubjectName: "
- "unsupported type=%d", gen->type);
- break;
- }
-
- if (!field)
- continue;
-
- wpa_printf(MSG_DEBUG, "TLS: altSubjectName: %s:%s",
- field, gen->d.ia5->data);
- len = os_strlen(field) + 1 +
- strlen((char *) gen->d.ia5->data) + 1;
- tmp = os_malloc(len);
- if (tmp == NULL)
- continue;
- snprintf(tmp, len, "%s:%s", field, gen->d.ia5->data);
- if (strstr(tmp, match))
- found++;
- os_free(tmp);
- }
-
- return found;
-}
-#endif
-
-
-#if 0
-static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
-{
- char buf[256];
- X509 *err_cert;
- int err, depth;
- SSL *ssl;
- struct tls_connection *conn;
- char *match, *altmatch;
-
- err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
- err = X509_STORE_CTX_get_error(x509_ctx);
- depth = X509_STORE_CTX_get_error_depth(x509_ctx);
- ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
- SSL_get_ex_data_X509_STORE_CTX_idx());
- X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
-
- conn = SSL_get_app_data(ssl);
- match = conn ? conn->subject_match : NULL;
- altmatch = conn ? conn->altsubject_match : NULL;
-
- if (!preverify_ok) {
- wpa_printf(MSG_WARNING, "TLS: Certificate verification failed,"
- " error %d (%s) depth %d for '%s'", err,
- X509_verify_cert_error_string(err), depth, buf);
- } else {
- wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - "
- "preverify_ok=%d err=%d (%s) depth=%d buf='%s'",
- preverify_ok, err,
- X509_verify_cert_error_string(err), depth, buf);
- if (depth == 0 && match && strstr(buf, match) == NULL) {
- wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
- "match with '%s'", buf, match);
- preverify_ok = 0;
- } else if (depth == 0 && altmatch &&
- !tls_match_altsubject(err_cert, altmatch)) {
- wpa_printf(MSG_WARNING, "TLS: altSubjectName match "
- "'%s' not found", altmatch);
- preverify_ok = 0;
- }
- }
-
- return preverify_ok;
-}
-#endif
-
-
int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
const struct tls_connection_params *params)
{
@@ -509,73 +347,142 @@
if (conn == NULL || params == NULL)
return -1;
- os_free(conn->subject_match);
- conn->subject_match = NULL;
if (params->subject_match) {
- conn->subject_match = os_strdup(params->subject_match);
- if (conn->subject_match == NULL)
+ wpa_printf(MSG_INFO, "GnuTLS: subject_match not supported");
+ return -1;
+ }
+
+ if (params->altsubject_match) {
+ wpa_printf(MSG_INFO, "GnuTLS: altsubject_match not supported");
+ return -1;
+ }
+
+ os_free(conn->suffix_match);
+ conn->suffix_match = NULL;
+ if (params->suffix_match) {
+ conn->suffix_match = os_strdup(params->suffix_match);
+ if (conn->suffix_match == NULL)
return -1;
}
- os_free(conn->altsubject_match);
- conn->altsubject_match = NULL;
- if (params->altsubject_match) {
- conn->altsubject_match = os_strdup(params->altsubject_match);
- if (conn->altsubject_match == NULL)
+#if GNUTLS_VERSION_NUMBER >= 0x030300
+ os_free(conn->domain_match);
+ conn->domain_match = NULL;
+ if (params->domain_match) {
+ conn->domain_match = os_strdup(params->domain_match);
+ if (conn->domain_match == NULL)
return -1;
}
+#else /* < 3.3.0 */
+ if (params->domain_match) {
+ wpa_printf(MSG_INFO, "GnuTLS: domain_match not supported");
+ return -1;
+ }
+#endif /* >= 3.3.0 */
+
+ conn->flags = params->flags;
+
+ if (params->openssl_ciphers) {
+ wpa_printf(MSG_INFO, "GnuTLS: openssl_ciphers not supported");
+ return -1;
+ }
/* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
* to force peer validation(?) */
if (params->ca_cert) {
- conn->verify_peer = 1;
+ wpa_printf(MSG_DEBUG, "GnuTLS: Try to parse %s in DER format",
+ params->ca_cert);
ret = gnutls_certificate_set_x509_trust_file(
- conn->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM);
+ conn->xcred, params->ca_cert, GNUTLS_X509_FMT_DER);
if (ret < 0) {
- wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
- "in PEM format: %s", params->ca_cert,
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: Failed to read CA cert '%s' in DER format (%s) - try in PEM format",
+ params->ca_cert,
gnutls_strerror(ret));
ret = gnutls_certificate_set_x509_trust_file(
conn->xcred, params->ca_cert,
- GNUTLS_X509_FMT_DER);
+ GNUTLS_X509_FMT_PEM);
if (ret < 0) {
- wpa_printf(MSG_DEBUG, "Failed to read CA cert "
- "'%s' in DER format: %s",
+ wpa_printf(MSG_DEBUG,
+ "Failed to read CA cert '%s' in PEM format: %s",
params->ca_cert,
gnutls_strerror(ret));
return -1;
}
}
+ } else if (params->ca_cert_blob) {
+ gnutls_datum_t ca;
+
+ ca.data = (unsigned char *) params->ca_cert_blob;
+ ca.size = params->ca_cert_blob_len;
+
+ ret = gnutls_certificate_set_x509_trust_mem(
+ conn->xcred, &ca, GNUTLS_X509_FMT_DER);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG,
+ "Failed to parse CA cert in DER format: %s",
+ gnutls_strerror(ret));
+ ret = gnutls_certificate_set_x509_trust_mem(
+ conn->xcred, &ca, GNUTLS_X509_FMT_PEM);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG,
+ "Failed to parse CA cert in PEM format: %s",
+ gnutls_strerror(ret));
+ return -1;
+ }
+ }
+ } else if (params->ca_path) {
+ wpa_printf(MSG_INFO, "GnuTLS: ca_path not supported");
+ return -1;
+ }
+
+ conn->disable_time_checks = 0;
+ if (params->ca_cert || params->ca_cert_blob) {
+ conn->verify_peer = 1;
+ gnutls_certificate_set_verify_function(
+ conn->xcred, tls_connection_verify_peer);
if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
gnutls_certificate_set_verify_flags(
conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
}
-#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
+ conn->disable_time_checks = 1;
gnutls_certificate_set_verify_flags(
conn->xcred,
GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
}
-#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
}
if (params->client_cert && params->private_key) {
- /* TODO: private_key_passwd? */
+#if GNUTLS_VERSION_NUMBER >= 0x03010b
+ ret = gnutls_certificate_set_x509_key_file2(
+ conn->xcred, params->client_cert, params->private_key,
+ GNUTLS_X509_FMT_DER, params->private_key_passwd, 0);
+#else
+ /* private_key_passwd not (easily) supported here */
ret = gnutls_certificate_set_x509_key_file(
conn->xcred, params->client_cert, params->private_key,
- GNUTLS_X509_FMT_PEM);
+ GNUTLS_X509_FMT_DER);
+#endif
if (ret < 0) {
wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
- "in PEM format: %s", gnutls_strerror(ret));
+ "in DER format: %s", gnutls_strerror(ret));
+#if GNUTLS_VERSION_NUMBER >= 0x03010b
+ ret = gnutls_certificate_set_x509_key_file2(
+ conn->xcred, params->client_cert,
+ params->private_key, GNUTLS_X509_FMT_PEM,
+ params->private_key_passwd, 0);
+#else
ret = gnutls_certificate_set_x509_key_file(
conn->xcred, params->client_cert,
- params->private_key, GNUTLS_X509_FMT_DER);
+ params->private_key, GNUTLS_X509_FMT_PEM);
+#endif
if (ret < 0) {
wpa_printf(MSG_DEBUG, "Failed to read client "
- "cert/key in DER format: %s",
+ "cert/key in PEM format: %s",
gnutls_strerror(ret));
return ret;
}
@@ -584,7 +491,6 @@
int pkcs12_ok = 0;
#ifdef PKCS12_FUNCS
/* Try to load in PKCS#12 format */
-#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
ret = gnutls_certificate_set_x509_simple_pkcs12_file(
conn->xcred, params->private_key, GNUTLS_X509_FMT_DER,
params->private_key_passwd);
@@ -594,7 +500,6 @@
return -1;
} else
pkcs12_ok = 1;
-#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
#endif /* PKCS12_FUNCS */
if (!pkcs12_ok) {
@@ -602,8 +507,82 @@
"included");
return -1;
}
+ } else if (params->client_cert_blob && params->private_key_blob) {
+ gnutls_datum_t cert, key;
+
+ cert.data = (unsigned char *) params->client_cert_blob;
+ cert.size = params->client_cert_blob_len;
+ key.data = (unsigned char *) params->private_key_blob;
+ key.size = params->private_key_blob_len;
+
+#if GNUTLS_VERSION_NUMBER >= 0x03010b
+ ret = gnutls_certificate_set_x509_key_mem2(
+ conn->xcred, &cert, &key, GNUTLS_X509_FMT_DER,
+ params->private_key_passwd, 0);
+#else
+ /* private_key_passwd not (easily) supported here */
+ ret = gnutls_certificate_set_x509_key_mem(
+ conn->xcred, &cert, &key, GNUTLS_X509_FMT_DER);
+#endif
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
+ "in DER format: %s", gnutls_strerror(ret));
+#if GNUTLS_VERSION_NUMBER >= 0x03010b
+ ret = gnutls_certificate_set_x509_key_mem2(
+ conn->xcred, &cert, &key, GNUTLS_X509_FMT_PEM,
+ params->private_key_passwd, 0);
+#else
+ /* private_key_passwd not (easily) supported here */
+ ret = gnutls_certificate_set_x509_key_mem(
+ conn->xcred, &cert, &key, GNUTLS_X509_FMT_PEM);
+#endif
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "Failed to read client "
+ "cert/key in PEM format: %s",
+ gnutls_strerror(ret));
+ return ret;
+ }
+ }
+ } else if (params->private_key_blob) {
+#ifdef PKCS12_FUNCS
+ gnutls_datum_t key;
+
+ key.data = (unsigned char *) params->private_key_blob;
+ key.size = params->private_key_blob_len;
+
+ /* Try to load in PKCS#12 format */
+ ret = gnutls_certificate_set_x509_simple_pkcs12_mem(
+ conn->xcred, &key, GNUTLS_X509_FMT_DER,
+ params->private_key_passwd);
+ if (ret != 0) {
+ wpa_printf(MSG_DEBUG, "Failed to load private_key in "
+ "PKCS#12 format: %s", gnutls_strerror(ret));
+ return -1;
+ }
+#else /* PKCS12_FUNCS */
+ wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not included");
+ return -1;
+#endif /* PKCS12_FUNCS */
}
+#if GNUTLS_VERSION_NUMBER >= 0x030103
+ if (params->flags & (TLS_CONN_REQUEST_OCSP | TLS_CONN_REQUIRE_OCSP)) {
+ ret = gnutls_ocsp_status_request_enable_client(conn->session,
+ NULL, 0, NULL);
+ if (ret != GNUTLS_E_SUCCESS) {
+ wpa_printf(MSG_INFO,
+ "GnuTLS: Failed to enable OCSP client");
+ return -1;
+ }
+ }
+#else /* 3.1.3 */
+ if (params->flags & TLS_CONN_REQUIRE_OCSP) {
+ wpa_printf(MSG_INFO,
+ "GnuTLS: OCSP not supported by this version of GnuTLS");
+ return -1;
+ }
+#endif /* 3.1.3 */
+
conn->params_set = 1;
ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
@@ -641,17 +620,17 @@
if (params->ca_cert) {
ret = gnutls_certificate_set_x509_trust_file(
- global->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM);
+ global->xcred, params->ca_cert, GNUTLS_X509_FMT_DER);
if (ret < 0) {
wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
- "in PEM format: %s", params->ca_cert,
+ "in DER format: %s", params->ca_cert,
gnutls_strerror(ret));
ret = gnutls_certificate_set_x509_trust_file(
global->xcred, params->ca_cert,
- GNUTLS_X509_FMT_DER);
+ GNUTLS_X509_FMT_PEM);
if (ret < 0) {
wpa_printf(MSG_DEBUG, "Failed to read CA cert "
- "'%s' in DER format: %s",
+ "'%s' in PEM format: %s",
params->ca_cert,
gnutls_strerror(ret));
goto fail;
@@ -664,29 +643,27 @@
GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
}
-#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
gnutls_certificate_set_verify_flags(
global->xcred,
GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
}
-#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
}
if (params->client_cert && params->private_key) {
/* TODO: private_key_passwd? */
ret = gnutls_certificate_set_x509_key_file(
global->xcred, params->client_cert,
- params->private_key, GNUTLS_X509_FMT_PEM);
+ params->private_key, GNUTLS_X509_FMT_DER);
if (ret < 0) {
wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
- "in PEM format: %s", gnutls_strerror(ret));
+ "in DER format: %s", gnutls_strerror(ret));
ret = gnutls_certificate_set_x509_key_file(
global->xcred, params->client_cert,
- params->private_key, GNUTLS_X509_FMT_DER);
+ params->private_key, GNUTLS_X509_FMT_PEM);
if (ret < 0) {
wpa_printf(MSG_DEBUG, "Failed to read client "
- "cert/key in DER format: %s",
+ "cert/key in PEM format: %s",
gnutls_strerror(ret));
goto fail;
}
@@ -695,7 +672,6 @@
int pkcs12_ok = 0;
#ifdef PKCS12_FUNCS
/* Try to load in PKCS#12 format */
-#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
ret = gnutls_certificate_set_x509_simple_pkcs12_file(
global->xcred, params->private_key,
GNUTLS_X509_FMT_DER, params->private_key_passwd);
@@ -705,7 +681,6 @@
goto fail;
} else
pkcs12_ok = 1;
-#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
#endif /* PKCS12_FUNCS */
if (!pkcs12_ok) {
@@ -750,37 +725,23 @@
int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
struct tls_keys *keys)
{
-#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
- security_parameters_st *sec;
-#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
+#if GNUTLS_VERSION_NUMBER >= 0x030012
+ gnutls_datum_t client, server;
if (conn == NULL || conn->session == NULL || keys == NULL)
return -1;
os_memset(keys, 0, sizeof(*keys));
-
-#if LIBGNUTLS_VERSION_NUMBER < 0x020c00
-#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
- sec = &conn->session->security_parameters;
- keys->master_key = sec->master_secret;
- keys->master_key_len = WPA_TLS_MASTER_SIZE;
- keys->client_random = sec->client_random;
- keys->server_random = sec->server_random;
-#else /* GNUTLS_INTERNAL_STRUCTURE_HACK */
- keys->client_random =
- (u8 *) gnutls_session_get_client_random(conn->session);
- keys->server_random =
- (u8 *) gnutls_session_get_server_random(conn->session);
- /* No access to master_secret */
-#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
-#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020c00 */
-
-#if LIBGNUTLS_VERSION_NUMBER < 0x020c00
- keys->client_random_len = WPA_TLS_RANDOM_SIZE;
- keys->server_random_len = WPA_TLS_RANDOM_SIZE;
-#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020c00 */
+ gnutls_session_get_random(conn->session, &client, &server);
+ keys->client_random = client.data;
+ keys->server_random = server.data;
+ keys->client_random_len = client.size;
+ keys->server_random_len = client.size;
return 0;
+#else /* 3.0.18 */
+ return -1;
+#endif /* 3.0.18 */
}
@@ -788,86 +749,317 @@
const char *label, int server_random_first,
u8 *out, size_t out_len)
{
-#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
if (conn == NULL || conn->session == NULL)
return -1;
return gnutls_prf(conn->session, os_strlen(label), label,
server_random_first, 0, NULL, out_len, (char *) out);
-#else /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
- return -1;
-#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
}
-static int tls_connection_verify_peer(struct tls_connection *conn,
- gnutls_alert_description_t *err)
+static void gnutls_tls_fail_event(struct tls_connection *conn,
+ const gnutls_datum_t *cert, int depth,
+ const char *subject, const char *err_str,
+ enum tls_fail_reason reason)
{
+ union tls_event_data ev;
+ struct tls_global *global = conn->global;
+ struct wpabuf *cert_buf = NULL;
+
+ if (global->event_cb == NULL)
+ return;
+
+ os_memset(&ev, 0, sizeof(ev));
+ ev.cert_fail.depth = depth;
+ ev.cert_fail.subject = subject ? subject : "";
+ ev.cert_fail.reason = reason;
+ ev.cert_fail.reason_txt = err_str;
+ if (cert) {
+ cert_buf = wpabuf_alloc_copy(cert->data, cert->size);
+ ev.cert_fail.cert = cert_buf;
+ }
+ global->event_cb(global->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
+ wpabuf_free(cert_buf);
+}
+
+
+#if GNUTLS_VERSION_NUMBER < 0x030300
+static int server_eku_purpose(gnutls_x509_crt_t cert)
+{
+ unsigned int i;
+
+ for (i = 0; ; i++) {
+ char oid[128];
+ size_t oid_size = sizeof(oid);
+ int res;
+
+ res = gnutls_x509_crt_get_key_purpose_oid(cert, i, oid,
+ &oid_size, NULL);
+ if (res == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
+ if (i == 0) {
+ /* No EKU - assume any use allowed */
+ return 1;
+ }
+ break;
+ }
+
+ if (res < 0) {
+ wpa_printf(MSG_INFO, "GnuTLS: Failed to get EKU");
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG, "GnuTLS: Certificate purpose: %s", oid);
+ if (os_strcmp(oid, GNUTLS_KP_TLS_WWW_SERVER) == 0 ||
+ os_strcmp(oid, GNUTLS_KP_ANY) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+#endif /* < 3.3.0 */
+
+
+static int check_ocsp(struct tls_connection *conn, gnutls_session_t session,
+ gnutls_alert_description_t *err)
+{
+#if GNUTLS_VERSION_NUMBER >= 0x030103
+ gnutls_datum_t response, buf;
+ gnutls_ocsp_resp_t resp;
+ unsigned int cert_status;
+ int res;
+
+ if (!(conn->flags & (TLS_CONN_REQUEST_OCSP | TLS_CONN_REQUIRE_OCSP)))
+ return 0;
+
+ if (!gnutls_ocsp_status_request_is_checked(session, 0)) {
+ if (conn->flags & TLS_CONN_REQUIRE_OCSP) {
+ wpa_printf(MSG_INFO,
+ "GnuTLS: No valid OCSP response received");
+ goto ocsp_error;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: Valid OCSP response was not received - continue since OCSP was not required");
+ return 0;
+ }
+
+ /*
+ * GnuTLS has already verified the OCSP response in
+ * check_ocsp_response() and rejected handshake if the certificate was
+ * found to be revoked. However, if the response indicates that the
+ * status is unknown, handshake continues and reaches here. We need to
+ * re-import the OCSP response to check for unknown certificate status,
+ * but we do not need to repeat gnutls_ocsp_resp_check_crt() and
+ * gnutls_ocsp_resp_verify_direct() calls.
+ */
+
+ res = gnutls_ocsp_status_request_get(session, &response);
+ if (res != GNUTLS_E_SUCCESS) {
+ wpa_printf(MSG_INFO,
+ "GnuTLS: OCSP response was received, but it was not valid");
+ goto ocsp_error;
+ }
+
+ if (gnutls_ocsp_resp_init(&resp) != GNUTLS_E_SUCCESS)
+ goto ocsp_error;
+
+ res = gnutls_ocsp_resp_import(resp, &response);
+ if (res != GNUTLS_E_SUCCESS) {
+ wpa_printf(MSG_INFO,
+ "GnuTLS: Could not parse received OCSP response: %s",
+ gnutls_strerror(res));
+ gnutls_ocsp_resp_deinit(resp);
+ goto ocsp_error;
+ }
+
+ res = gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_FULL, &buf);
+ if (res == GNUTLS_E_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "GnuTLS: %s", buf.data);
+ gnutls_free(buf.data);
+ }
+
+ res = gnutls_ocsp_resp_get_single(resp, 0, NULL, NULL, NULL,
+ NULL, &cert_status, NULL,
+ NULL, NULL, NULL);
+ gnutls_ocsp_resp_deinit(resp);
+ if (res != GNUTLS_E_SUCCESS) {
+ wpa_printf(MSG_INFO,
+ "GnuTLS: Failed to extract OCSP information: %s",
+ gnutls_strerror(res));
+ goto ocsp_error;
+ }
+
+ if (cert_status == GNUTLS_OCSP_CERT_GOOD) {
+ wpa_printf(MSG_DEBUG, "GnuTLS: OCSP cert status: good");
+ } else if (cert_status == GNUTLS_OCSP_CERT_REVOKED) {
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: OCSP cert status: revoked");
+ goto ocsp_error;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: OCSP cert status: unknown");
+ if (conn->flags & TLS_CONN_REQUIRE_OCSP)
+ goto ocsp_error;
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: OCSP was not required, so allow connection to continue");
+ }
+
+ return 0;
+
+ocsp_error:
+ gnutls_tls_fail_event(conn, NULL, 0, NULL,
+ "bad certificate status response",
+ TLS_FAIL_REVOKED);
+ *err = GNUTLS_A_CERTIFICATE_REVOKED;
+ return -1;
+#else /* GnuTLS 3.1.3 or newer */
+ return 0;
+#endif /* GnuTLS 3.1.3 or newer */
+}
+
+
+static int tls_connection_verify_peer(gnutls_session_t session)
+{
+ struct tls_connection *conn;
unsigned int status, num_certs, i;
struct os_time now;
const gnutls_datum_t *certs;
gnutls_x509_crt_t cert;
+ gnutls_alert_description_t err;
+ int res;
- if (gnutls_certificate_verify_peers2(conn->session, &status) < 0) {
+ conn = gnutls_session_get_ptr(session);
+ if (!conn->verify_peer) {
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: No peer certificate verification enabled");
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG, "GnuTSL: Verifying peer certificate");
+
+#if GNUTLS_VERSION_NUMBER >= 0x030300
+ {
+ gnutls_typed_vdata_st data[1];
+ unsigned int elements = 0;
+
+ os_memset(data, 0, sizeof(data));
+ if (!conn->global->server) {
+ data[elements].type = GNUTLS_DT_KEY_PURPOSE_OID;
+ data[elements].data = (void *) GNUTLS_KP_TLS_WWW_SERVER;
+ elements++;
+ }
+ res = gnutls_certificate_verify_peers(session, data, 1,
+ &status);
+ }
+#else /* < 3.3.0 */
+ res = gnutls_certificate_verify_peers2(session, &status);
+#endif
+ if (res < 0) {
wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
"certificate chain");
- *err = GNUTLS_A_INTERNAL_ERROR;
- return -1;
+ err = GNUTLS_A_INTERNAL_ERROR;
+ goto out;
+ }
+
+#if GNUTLS_VERSION_NUMBER >= 0x030104
+ {
+ gnutls_datum_t info;
+ int ret, type;
+
+ type = gnutls_certificate_type_get(session);
+ ret = gnutls_certificate_verification_status_print(status, type,
+ &info, 0);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: Failed to print verification status");
+ err = GNUTLS_A_INTERNAL_ERROR;
+ goto out;
+ }
+ wpa_printf(MSG_DEBUG, "GnuTLS: %s", info.data);
+ gnutls_free(info.data);
+ }
+#endif /* GnuTLS 3.1.4 or newer */
+
+ certs = gnutls_certificate_get_peers(session, &num_certs);
+ if (certs == NULL || num_certs == 0) {
+ wpa_printf(MSG_INFO, "TLS: No peer certificate chain received");
+ err = GNUTLS_A_UNKNOWN_CA;
+ goto out;
}
if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
- *err = GNUTLS_A_INTERNAL_ERROR;
if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
wpa_printf(MSG_INFO, "TLS: Certificate uses insecure "
"algorithm");
- *err = GNUTLS_A_INSUFFICIENT_SECURITY;
+ gnutls_tls_fail_event(conn, NULL, 0, NULL,
+ "certificate uses insecure algorithm",
+ TLS_FAIL_BAD_CERTIFICATE);
+ err = GNUTLS_A_INSUFFICIENT_SECURITY;
+ goto out;
}
-#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
if (status & GNUTLS_CERT_NOT_ACTIVATED) {
wpa_printf(MSG_INFO, "TLS: Certificate not yet "
"activated");
- *err = GNUTLS_A_CERTIFICATE_EXPIRED;
+ gnutls_tls_fail_event(conn, NULL, 0, NULL,
+ "certificate not yet valid",
+ TLS_FAIL_NOT_YET_VALID);
+ err = GNUTLS_A_CERTIFICATE_EXPIRED;
+ goto out;
}
if (status & GNUTLS_CERT_EXPIRED) {
wpa_printf(MSG_INFO, "TLS: Certificate expired");
- *err = GNUTLS_A_CERTIFICATE_EXPIRED;
+ gnutls_tls_fail_event(conn, NULL, 0, NULL,
+ "certificate has expired",
+ TLS_FAIL_EXPIRED);
+ err = GNUTLS_A_CERTIFICATE_EXPIRED;
+ goto out;
}
-#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
- return -1;
+ gnutls_tls_fail_event(conn, NULL, 0, NULL,
+ "untrusted certificate",
+ TLS_FAIL_UNTRUSTED);
+ err = GNUTLS_A_INTERNAL_ERROR;
+ goto out;
}
if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
"known issuer");
- *err = GNUTLS_A_UNKNOWN_CA;
- return -1;
+ gnutls_tls_fail_event(conn, NULL, 0, NULL, "signed not found",
+ TLS_FAIL_UNTRUSTED);
+ err = GNUTLS_A_UNKNOWN_CA;
+ goto out;
}
if (status & GNUTLS_CERT_REVOKED) {
wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
- *err = GNUTLS_A_CERTIFICATE_REVOKED;
- return -1;
+ gnutls_tls_fail_event(conn, NULL, 0, NULL,
+ "certificate revoked",
+ TLS_FAIL_REVOKED);
+ err = GNUTLS_A_CERTIFICATE_REVOKED;
+ goto out;
}
+ if (status != 0) {
+ wpa_printf(MSG_INFO, "TLS: Unknown verification status: %d",
+ status);
+ err = GNUTLS_A_INTERNAL_ERROR;
+ goto out;
+ }
+
+ if (check_ocsp(conn, session, &err))
+ goto out;
+
os_get_time(&now);
- certs = gnutls_certificate_get_peers(conn->session, &num_certs);
- if (certs == NULL) {
- wpa_printf(MSG_INFO, "TLS: No peer certificate chain "
- "received");
- *err = GNUTLS_A_UNKNOWN_CA;
- return -1;
- }
-
for (i = 0; i < num_certs; i++) {
char *buf;
size_t len;
if (gnutls_x509_crt_init(&cert) < 0) {
wpa_printf(MSG_INFO, "TLS: Certificate initialization "
"failed");
- *err = GNUTLS_A_BAD_CERTIFICATE;
- return -1;
+ err = GNUTLS_A_BAD_CERTIFICATE;
+ goto out;
}
if (gnutls_x509_crt_import(cert, &certs[i],
@@ -875,8 +1067,8 @@
wpa_printf(MSG_INFO, "TLS: Could not parse peer "
"certificate %d/%d", i + 1, num_certs);
gnutls_x509_crt_deinit(cert);
- *err = GNUTLS_A_BAD_CERTIFICATE;
- return -1;
+ err = GNUTLS_A_BAD_CERTIFICATE;
+ goto out;
}
gnutls_x509_crt_get_dn(cert, NULL, &len);
@@ -889,26 +1081,128 @@
wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s",
i + 1, num_certs, buf);
+ if (conn->global->event_cb) {
+ struct wpabuf *cert_buf = NULL;
+ union tls_event_data ev;
+#ifdef CONFIG_SHA256
+ u8 hash[32];
+ const u8 *_addr[1];
+ size_t _len[1];
+#endif /* CONFIG_SHA256 */
+
+ os_memset(&ev, 0, sizeof(ev));
+ if (conn->global->cert_in_cb) {
+ cert_buf = wpabuf_alloc_copy(certs[i].data,
+ certs[i].size);
+ ev.peer_cert.cert = cert_buf;
+ }
+#ifdef CONFIG_SHA256
+ _addr[0] = certs[i].data;
+ _len[0] = certs[i].size;
+ if (sha256_vector(1, _addr, _len, hash) == 0) {
+ ev.peer_cert.hash = hash;
+ ev.peer_cert.hash_len = sizeof(hash);
+ }
+#endif /* CONFIG_SHA256 */
+ ev.peer_cert.depth = i;
+ ev.peer_cert.subject = buf;
+ conn->global->event_cb(conn->global->cb_ctx,
+ TLS_PEER_CERTIFICATE, &ev);
+ wpabuf_free(cert_buf);
+ }
+
if (i == 0) {
- /* TODO: validate subject_match and altsubject_match */
+ if (conn->suffix_match &&
+ !gnutls_x509_crt_check_hostname(
+ cert, conn->suffix_match)) {
+ wpa_printf(MSG_WARNING,
+ "TLS: Domain suffix match '%s' not found",
+ conn->suffix_match);
+ gnutls_tls_fail_event(
+ conn, &certs[i], i, buf,
+ "Domain suffix mismatch",
+ TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
+ err = GNUTLS_A_BAD_CERTIFICATE;
+ gnutls_x509_crt_deinit(cert);
+ os_free(buf);
+ goto out;
+ }
+
+#if GNUTLS_VERSION_NUMBER >= 0x030300
+ if (conn->domain_match &&
+ !gnutls_x509_crt_check_hostname2(
+ cert, conn->domain_match,
+ GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS)) {
+ wpa_printf(MSG_WARNING,
+ "TLS: Domain match '%s' not found",
+ conn->domain_match);
+ gnutls_tls_fail_event(
+ conn, &certs[i], i, buf,
+ "Domain mismatch",
+ TLS_FAIL_DOMAIN_MISMATCH);
+ err = GNUTLS_A_BAD_CERTIFICATE;
+ gnutls_x509_crt_deinit(cert);
+ os_free(buf);
+ goto out;
+ }
+#endif /* >= 3.3.0 */
+
+ /* TODO: validate altsubject_match.
+ * For now, any such configuration is rejected in
+ * tls_connection_set_params() */
+
+#if GNUTLS_VERSION_NUMBER < 0x030300
+ /*
+ * gnutls_certificate_verify_peers() not available, so
+ * need to check EKU separately.
+ */
+ if (!conn->global->server &&
+ !server_eku_purpose(cert)) {
+ wpa_printf(MSG_WARNING,
+ "GnuTLS: No server EKU");
+ gnutls_tls_fail_event(
+ conn, &certs[i], i, buf,
+ "No server EKU",
+ TLS_FAIL_BAD_CERTIFICATE);
+ err = GNUTLS_A_BAD_CERTIFICATE;
+ gnutls_x509_crt_deinit(cert);
+ os_free(buf);
+ goto out;
+ }
+#endif /* < 3.3.0 */
+ }
+
+ if (!conn->disable_time_checks &&
+ (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
+ gnutls_x509_crt_get_activation_time(cert) > now.sec)) {
+ wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
+ "not valid at this time",
+ i + 1, num_certs);
+ gnutls_tls_fail_event(
+ conn, &certs[i], i, buf,
+ "Certificate is not valid at this time",
+ TLS_FAIL_EXPIRED);
+ gnutls_x509_crt_deinit(cert);
+ os_free(buf);
+ err = GNUTLS_A_CERTIFICATE_EXPIRED;
+ goto out;
}
os_free(buf);
- if (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
- gnutls_x509_crt_get_activation_time(cert) > now.sec) {
- wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
- "not valid at this time",
- i + 1, num_certs);
- gnutls_x509_crt_deinit(cert);
- *err = GNUTLS_A_CERTIFICATE_EXPIRED;
- return -1;
- }
-
gnutls_x509_crt_deinit(cert);
}
+ if (conn->global->event_cb != NULL)
+ conn->global->event_cb(conn->global->cb_ctx,
+ TLS_CERT_CHAIN_SUCCESS, NULL);
+
return 0;
+
+out:
+ conn->failed++;
+ gnutls_alert_send(session, GNUTLS_AL_FATAL, err);
+ return GNUTLS_E_CERTIFICATE_ERROR;
}
@@ -966,6 +1260,8 @@
ret = gnutls_handshake(conn->session);
if (ret < 0) {
+ gnutls_alert_description_t alert;
+
switch (ret) {
case GNUTLS_E_AGAIN:
if (global->server && conn->established &&
@@ -976,10 +1272,20 @@
}
break;
case GNUTLS_E_FATAL_ALERT_RECEIVED:
+ alert = gnutls_alert_get(conn->session);
wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
- __func__, gnutls_alert_get_name(
- gnutls_alert_get(conn->session)));
+ __func__, gnutls_alert_get_name(alert));
conn->read_alerts++;
+ if (conn->global->event_cb != NULL) {
+ union tls_event_data ev;
+
+ os_memset(&ev, 0, sizeof(ev));
+ ev.alert.is_local = 0;
+ ev.alert.type = gnutls_alert_get_name(alert);
+ ev.alert.description = ev.alert.type;
+ conn->global->event_cb(conn->global->cb_ctx,
+ TLS_ALERT, &ev);
+ }
/* continue */
default:
wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed "
@@ -988,18 +1294,21 @@
}
} else {
size_t size;
- gnutls_alert_description_t err;
-
- if (conn->verify_peer &&
- tls_connection_verify_peer(conn, &err)) {
- wpa_printf(MSG_INFO, "TLS: Peer certificate chain "
- "failed validation");
- conn->failed++;
- gnutls_alert_send(conn->session, GNUTLS_AL_FATAL, err);
- goto out;
- }
wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully");
+
+#if GNUTLS_VERSION_NUMBER >= 0x03010a
+ {
+ char *desc;
+
+ desc = gnutls_session_get_desc(conn->session);
+ if (desc) {
+ wpa_printf(MSG_DEBUG, "GnuTLS: %s", desc);
+ gnutls_free(desc);
+ }
+ }
+#endif /* GnuTLS 3.1.10 or newer */
+
conn->established = 1;
if (conn->push_buf == NULL) {
/* Need to return something to get final TLS ACK. */
@@ -1023,7 +1332,6 @@
*appl_data = gnutls_get_appl_data(conn);
}
-out:
out_data = conn->push_buf;
conn->push_buf = NULL;
return out_data;
@@ -1188,3 +1496,10 @@
{
return -1;
}
+
+
+int tls_get_library_version(char *buf, size_t buf_len)
+{
+ return os_snprintf(buf, buf_len, "GnuTLS build=%s run=%s",
+ GNUTLS_VERSION, gnutls_check_version(NULL));
+}
diff --git a/src/crypto/tls_internal.c b/src/crypto/tls_internal.c
index 6563ed2..0c955da 100644
--- a/src/crypto/tls_internal.c
+++ b/src/crypto/tls_internal.c
@@ -190,6 +190,31 @@
if (cred == NULL)
return -1;
+ if (params->subject_match) {
+ wpa_printf(MSG_INFO, "TLS: subject_match not supported");
+ return -1;
+ }
+
+ if (params->altsubject_match) {
+ wpa_printf(MSG_INFO, "TLS: altsubject_match not supported");
+ return -1;
+ }
+
+ if (params->suffix_match) {
+ wpa_printf(MSG_INFO, "TLS: suffix_match not supported");
+ return -1;
+ }
+
+ if (params->domain_match) {
+ wpa_printf(MSG_INFO, "TLS: domain_match not supported");
+ return -1;
+ }
+
+ if (params->openssl_ciphers) {
+ wpa_printf(MSG_INFO, "GnuTLS: openssl_ciphers not supported");
+ return -1;
+ }
+
if (tlsv1_set_ca_cert(cred, params->ca_cert,
params->ca_cert_blob, params->ca_cert_blob_len,
params->ca_path)) {
@@ -652,3 +677,9 @@
#endif /* CONFIG_TLS_INTERNAL_SERVER */
return -1;
}
+
+
+int tls_get_library_version(char *buf, size_t buf_len)
+{
+ return os_snprintf(buf, buf_len, "internal");
+}
diff --git a/src/crypto/tls_none.c b/src/crypto/tls_none.c
index 1a1092a..a6d210a 100644
--- a/src/crypto/tls_none.c
+++ b/src/crypto/tls_none.c
@@ -192,3 +192,9 @@
{
return 0;
}
+
+
+int tls_get_library_version(char *buf, size_t buf_len)
+{
+ return os_snprintf(buf, buf_len, "none");
+}
diff --git a/src/crypto/tls_nss.c b/src/crypto/tls_nss.c
deleted file mode 100644
index c53c192..0000000
--- a/src/crypto/tls_nss.c
+++ /dev/null
@@ -1,645 +0,0 @@
-/*
- * SSL/TLS interface functions for NSS
- * 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 "includes.h"
-#include <nspr/prtypes.h>
-#include <nspr/plarenas.h>
-#include <nspr/plhash.h>
-#include <nspr/prio.h>
-#include <nspr/prclist.h>
-#include <nspr/prlock.h>
-#include <nspr/prinit.h>
-#include <nspr/prerror.h>
-#include <nspr/prmem.h>
-#include <nss/nss.h>
-#include <nss/nssilckt.h>
-#include <nss/ssl.h>
-#include <nss/pk11func.h>
-#include <nss/secerr.h>
-
-#include "common.h"
-#include "tls.h"
-
-static int tls_nss_ref_count = 0;
-
-static PRDescIdentity nss_layer_id;
-
-
-struct tls_connection {
- PRFileDesc *fd;
-
- int established;
- int verify_peer;
- u8 *push_buf, *pull_buf, *pull_buf_offset;
- size_t push_buf_len, pull_buf_len;
-};
-
-
-static PRStatus nss_io_close(PRFileDesc *fd)
-{
- wpa_printf(MSG_DEBUG, "NSS: I/O close");
- return PR_SUCCESS;
-}
-
-
-static PRInt32 nss_io_read(PRFileDesc *fd, void *buf, PRInt32 amount)
-{
- wpa_printf(MSG_DEBUG, "NSS: I/O read(%d)", amount);
- return PR_FAILURE;
-}
-
-
-static PRInt32 nss_io_write(PRFileDesc *fd, const void *buf, PRInt32 amount)
-{
- wpa_printf(MSG_DEBUG, "NSS: I/O write(%d)", amount);
- return PR_FAILURE;
-}
-
-
-static PRInt32 nss_io_writev(PRFileDesc *fd, const PRIOVec *iov,
- PRInt32 iov_size, PRIntervalTime timeout)
-{
- wpa_printf(MSG_DEBUG, "NSS: I/O writev(%d)", iov_size);
- return PR_FAILURE;
-}
-
-
-static PRInt32 nss_io_recv(PRFileDesc *fd, void *buf, PRInt32 amount,
- PRIntn flags, PRIntervalTime timeout)
-{
- struct tls_connection *conn = (struct tls_connection *) fd->secret;
- u8 *end;
-
- wpa_printf(MSG_DEBUG, "NSS: I/O recv(%d)", amount);
-
- if (conn->pull_buf == NULL) {
- wpa_printf(MSG_DEBUG, "NSS: No data available to be read yet");
- return PR_FAILURE;
- }
-
- end = conn->pull_buf + conn->pull_buf_len;
- if (end - conn->pull_buf_offset < amount)
- amount = end - conn->pull_buf_offset;
- os_memcpy(buf, conn->pull_buf_offset, amount);
- conn->pull_buf_offset += amount;
- if (conn->pull_buf_offset == end) {
- wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
- os_free(conn->pull_buf);
- conn->pull_buf = conn->pull_buf_offset = NULL;
- conn->pull_buf_len = 0;
- } else {
- wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
- __func__,
- (unsigned long) (end - conn->pull_buf_offset));
- }
- return amount;
-}
-
-
-static PRInt32 nss_io_send(PRFileDesc *fd, const void *buf, PRInt32 amount,
- PRIntn flags, PRIntervalTime timeout)
-{
- struct tls_connection *conn = (struct tls_connection *) fd->secret;
- u8 *nbuf;
-
- wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
- wpa_hexdump(MSG_MSGDUMP, "NSS: I/O send data", buf, amount);
-
- nbuf = os_realloc(conn->push_buf, conn->push_buf_len + amount);
- if (nbuf == NULL) {
- wpa_printf(MSG_ERROR, "NSS: Failed to allocate memory for the "
- "data to be sent");
- return PR_FAILURE;
- }
- os_memcpy(nbuf + conn->push_buf_len, buf, amount);
- conn->push_buf = nbuf;
- conn->push_buf_len += amount;
-
- return amount;
-}
-
-
-static PRInt32 nss_io_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount,
- PRIntn flags, PRNetAddr *addr,
- PRIntervalTime timeout)
-{
- wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
- return PR_FAILURE;
-}
-
-
-static PRInt32 nss_io_sendto(PRFileDesc *fd, const void *buf, PRInt32 amount,
- PRIntn flags, const PRNetAddr *addr,
- PRIntervalTime timeout)
-{
- wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
- return PR_FAILURE;
-}
-
-
-static PRStatus nss_io_getpeername(PRFileDesc *fd, PRNetAddr *addr)
-{
- wpa_printf(MSG_DEBUG, "NSS: I/O getpeername");
-
- /*
- * It Looks like NSS only supports IPv4 and IPv6 TCP sockets. Provide a
- * fake IPv4 address to work around this even though we are not really
- * using TCP.
- */
- os_memset(addr, 0, sizeof(*addr));
- addr->inet.family = PR_AF_INET;
-
- return PR_SUCCESS;
-}
-
-
-static PRStatus nss_io_getsocketoption(PRFileDesc *fd,
- PRSocketOptionData *data)
-{
- switch (data->option) {
- case PR_SockOpt_Nonblocking:
- wpa_printf(MSG_DEBUG, "NSS: I/O getsocketoption(Nonblocking)");
- data->value.non_blocking = PR_TRUE;
- return PR_SUCCESS;
- default:
- wpa_printf(MSG_DEBUG, "NSS: I/O getsocketoption(%d)",
- data->option);
- return PR_FAILURE;
- }
-}
-
-
-static const PRIOMethods nss_io = {
- PR_DESC_LAYERED,
- nss_io_close,
- nss_io_read,
- nss_io_write,
- NULL /* available */,
- NULL /* available64 */,
- NULL /* fsync */,
- NULL /* fseek */,
- NULL /* fseek64 */,
- NULL /* fileinfo */,
- NULL /* fileinfo64 */,
- nss_io_writev,
- NULL /* connect */,
- NULL /* accept */,
- NULL /* bind */,
- NULL /* listen */,
- NULL /* shutdown */,
- nss_io_recv,
- nss_io_send,
- nss_io_recvfrom,
- nss_io_sendto,
- NULL /* poll */,
- NULL /* acceptread */,
- NULL /* transmitfile */,
- NULL /* getsockname */,
- nss_io_getpeername,
- NULL /* reserved_fn_6 */,
- NULL /* reserved_fn_5 */,
- nss_io_getsocketoption,
- NULL /* setsocketoption */,
- NULL /* sendfile */,
- NULL /* connectcontinue */,
- NULL /* reserved_fn_3 */,
- NULL /* reserved_fn_2 */,
- NULL /* reserved_fn_1 */,
- NULL /* reserved_fn_0 */
-};
-
-
-static char * nss_password_cb(PK11SlotInfo *slot, PRBool retry, void *arg)
-{
- wpa_printf(MSG_ERROR, "NSS: TODO - %s", __func__);
- return NULL;
-}
-
-
-void * tls_init(const struct tls_config *conf)
-{
- char *dir;
-
- tls_nss_ref_count++;
- if (tls_nss_ref_count > 1)
- return (void *) 1;
-
- PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
-
- nss_layer_id = PR_GetUniqueIdentity("wpa_supplicant");
-
- PK11_SetPasswordFunc(nss_password_cb);
-
- dir = getenv("SSL_DIR");
- if (dir) {
- if (NSS_Init(dir) != SECSuccess) {
- wpa_printf(MSG_ERROR, "NSS: NSS_Init(cert_dir=%s) "
- "failed", dir);
- return NULL;
- }
- } else {
- if (NSS_NoDB_Init(NULL) != SECSuccess) {
- wpa_printf(MSG_ERROR, "NSS: NSS_NoDB_Init(NULL) "
- "failed");
- return NULL;
- }
- }
-
- if (SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO, PR_FALSE) !=
- SECSuccess ||
- SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_FALSE) != SECSuccess ||
- SSL_OptionSetDefault(SSL_ENABLE_SSL2, PR_FALSE) != SECSuccess ||
- SSL_OptionSetDefault(SSL_ENABLE_TLS, PR_TRUE) != SECSuccess) {
- wpa_printf(MSG_ERROR, "NSS: SSL_OptionSetDefault failed");
- return NULL;
- }
-
- if (NSS_SetDomesticPolicy() != SECSuccess) {
- wpa_printf(MSG_ERROR, "NSS: NSS_SetDomesticPolicy() failed");
- return NULL;
- }
-
- return (void *) 1;
-}
-
-void tls_deinit(void *ssl_ctx)
-{
- tls_nss_ref_count--;
- if (tls_nss_ref_count == 0) {
- if (NSS_Shutdown() != SECSuccess)
- wpa_printf(MSG_ERROR, "NSS: NSS_Shutdown() failed");
- }
-}
-
-
-int tls_get_errors(void *tls_ctx)
-{
- return 0;
-}
-
-
-static SECStatus nss_bad_cert_cb(void *arg, PRFileDesc *fd)
-{
- struct tls_connection *conn = arg;
- SECStatus res = SECSuccess;
- PRErrorCode err;
- CERTCertificate *cert;
- char *subject, *issuer;
-
- err = PR_GetError();
- if (IS_SEC_ERROR(err))
- wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (sec err "
- "%d)", err - SEC_ERROR_BASE);
- else
- wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (err %d)",
- err);
- cert = SSL_PeerCertificate(fd);
- subject = CERT_NameToAscii(&cert->subject);
- issuer = CERT_NameToAscii(&cert->issuer);
- wpa_printf(MSG_DEBUG, "NSS: Peer certificate subject='%s' issuer='%s'",
- subject, issuer);
- CERT_DestroyCertificate(cert);
- PR_Free(subject);
- PR_Free(issuer);
- if (conn->verify_peer)
- res = SECFailure;
-
- return res;
-}
-
-
-static void nss_handshake_cb(PRFileDesc *fd, void *client_data)
-{
- struct tls_connection *conn = client_data;
- wpa_printf(MSG_DEBUG, "NSS: Handshake completed");
- conn->established = 1;
-}
-
-
-struct tls_connection * tls_connection_init(void *tls_ctx)
-{
- struct tls_connection *conn;
-
- conn = os_zalloc(sizeof(*conn));
- if (conn == NULL)
- return NULL;
-
- conn->fd = PR_CreateIOLayerStub(nss_layer_id, &nss_io);
- if (conn->fd == NULL) {
- os_free(conn);
- return NULL;
- }
- conn->fd->secret = (void *) conn;
-
- conn->fd = SSL_ImportFD(NULL, conn->fd);
- if (conn->fd == NULL) {
- os_free(conn);
- return NULL;
- }
-
- if (SSL_OptionSet(conn->fd, SSL_SECURITY, PR_TRUE) != SECSuccess ||
- SSL_OptionSet(conn->fd, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) !=
- SECSuccess ||
- SSL_OptionSet(conn->fd, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) !=
- SECSuccess ||
- SSL_OptionSet(conn->fd, SSL_ENABLE_TLS, PR_TRUE) != SECSuccess ||
- SSL_BadCertHook(conn->fd, nss_bad_cert_cb, conn) != SECSuccess ||
- SSL_HandshakeCallback(conn->fd, nss_handshake_cb, conn) !=
- SECSuccess) {
- wpa_printf(MSG_ERROR, "NSS: Failed to set options");
- PR_Close(conn->fd);
- os_free(conn);
- return NULL;
- }
-
- SSL_ResetHandshake(conn->fd, PR_FALSE);
-
- return conn;
-}
-
-
-void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
-{
- PR_Close(conn->fd);
- os_free(conn->push_buf);
- os_free(conn->pull_buf);
- os_free(conn);
-}
-
-
-int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
-{
- return conn->established;
-}
-
-
-int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
-{
- return -1;
-}
-
-
-int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
- const struct tls_connection_params *params)
-{
- wpa_printf(MSG_ERROR, "NSS: TODO - %s", __func__);
- return 0;
-}
-
-
-int tls_global_set_params(void *tls_ctx,
- const struct tls_connection_params *params)
-{
- return -1;
-}
-
-
-int tls_global_set_verify(void *tls_ctx, int check_crl)
-{
- return -1;
-}
-
-
-int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
- int verify_peer)
-{
- conn->verify_peer = verify_peer;
- return 0;
-}
-
-
-int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
- struct tls_keys *keys)
-{
- /* NSS does not export master secret or client/server random. */
- return -1;
-}
-
-
-int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
- const char *label, int server_random_first,
- u8 *out, size_t out_len)
-{
- if (conn == NULL || server_random_first) {
- wpa_printf(MSG_INFO, "NSS: Unsupported PRF request "
- "(server_random_first=%d)",
- server_random_first);
- return -1;
- }
-
- if (SSL_ExportKeyingMaterial(conn->fd, label, NULL, 0, out, out_len) !=
- SECSuccess) {
- wpa_printf(MSG_INFO, "NSS: Failed to use TLS extractor "
- "(label='%s' out_len=%d", label, (int) out_len);
- return -1;
- }
-
- return 0;
-}
-
-
-struct wpabuf * tls_connection_handshake(void *tls_ctx,
- struct tls_connection *conn,
- const struct wpabuf *in_data,
- struct wpabuf **appl_data)
-{
- struct wpabuf *out_data;
-
- wpa_printf(MSG_DEBUG, "NSS: handshake: in_len=%u",
- in_data ? (unsigned int) wpabuf_len(in_data) : 0);
-
- if (appl_data)
- *appl_data = NULL;
-
- if (in_data && wpabuf_len(in_data) > 0) {
- if (conn->pull_buf) {
- wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
- "pull_buf", __func__,
- (unsigned long) conn->pull_buf_len);
- os_free(conn->pull_buf);
- }
- conn->pull_buf = os_malloc(wpabuf_len(in_data));
- if (conn->pull_buf == NULL)
- return NULL;
- os_memcpy(conn->pull_buf, wpabuf_head(in_data),
- wpabuf_len(in_data));
- conn->pull_buf_offset = conn->pull_buf;
- conn->pull_buf_len = wpabuf_len(in_data);
- }
-
- SSL_ForceHandshake(conn->fd);
-
- if (conn->established && conn->push_buf == NULL) {
- /* Need to return something to get final TLS ACK. */
- conn->push_buf = os_malloc(1);
- }
-
- if (conn->push_buf == NULL)
- return NULL;
- out_data = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len);
- if (out_data == NULL)
- os_free(conn->push_buf);
- conn->push_buf = NULL;
- conn->push_buf_len = 0;
- return out_data;
-}
-
-
-struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
- struct tls_connection *conn,
- const struct wpabuf *in_data,
- struct wpabuf **appl_data)
-{
- return NULL;
-}
-
-
-struct wpabuf * tls_connection_encrypt(void *tls_ctx,
- struct tls_connection *conn,
- const struct wpabuf *in_data)
-{
- PRInt32 res;
- struct wpabuf *buf;
-
- wpa_printf(MSG_DEBUG, "NSS: encrypt %d bytes",
- (int) wpabuf_len(in_data));
- res = PR_Send(conn->fd, wpabuf_head(in_data), wpabuf_len(in_data), 0,
- 0);
- if (res < 0) {
- wpa_printf(MSG_ERROR, "NSS: Encryption failed");
- return NULL;
- }
- if (conn->push_buf == NULL)
- return NULL;
- buf = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len);
- if (buf == NULL)
- os_free(conn->push_buf);
- conn->push_buf = NULL;
- conn->push_buf_len = 0;
- return buf;
-}
-
-
-struct wpabuf * tls_connection_decrypt(void *tls_ctx,
- struct tls_connection *conn,
- const struct wpabuf *in_data)
-{
- PRInt32 res;
- struct wpabuf *out;
-
- wpa_printf(MSG_DEBUG, "NSS: decrypt %d bytes",
- (int) wpabuf_len(in_data));
- if (conn->pull_buf) {
- wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
- "pull_buf", __func__,
- (unsigned long) conn->pull_buf_len);
- os_free(conn->pull_buf);
- }
- conn->pull_buf = os_malloc(wpabuf_len(in_data));
- if (conn->pull_buf == NULL)
- return NULL;
- os_memcpy(conn->pull_buf, wpabuf_head(in_data), wpabuf_len(in_data));
- conn->pull_buf_offset = conn->pull_buf;
- conn->pull_buf_len = wpabuf_len(in_data);
-
- /*
- * Even though we try to disable TLS compression, it is possible that
- * this cannot be done with all TLS libraries. Add extra buffer space
- * to handle the possibility of the decrypted data being longer than
- * input data.
- */
- out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
- if (out == NULL)
- return NULL;
-
- res = PR_Recv(conn->fd, wpabuf_mhead(out), wpabuf_size(out), 0, 0);
- wpa_printf(MSG_DEBUG, "NSS: PR_Recv: %d", res);
- if (res < 0) {
- wpabuf_free(out);
- return NULL;
- }
- wpabuf_put(out, res);
-
- return out;
-}
-
-
-int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
-{
- return 0;
-}
-
-
-int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
- u8 *ciphers)
-{
- return -1;
-}
-
-
-int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
- char *buf, size_t buflen)
-{
- return -1;
-}
-
-
-int tls_connection_enable_workaround(void *tls_ctx,
- struct tls_connection *conn)
-{
- return -1;
-}
-
-
-int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
- int ext_type, const u8 *data,
- size_t data_len)
-{
- return -1;
-}
-
-
-int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
-{
- return 0;
-}
-
-
-int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
-{
- return 0;
-}
-
-
-int tls_connection_get_write_alerts(void *tls_ctx,
- struct tls_connection *conn)
-{
- return 0;
-}
-
-
-int tls_connection_get_keyblock_size(void *tls_ctx,
- struct tls_connection *conn)
-{
- return -1;
-}
-
-
-unsigned int tls_capabilities(void *tls_ctx)
-{
- return 0;
-}
-
-
-int tls_connection_set_session_ticket_cb(void *tls_ctx,
- struct tls_connection *conn,
- tls_session_ticket_cb cb,
- void *ctx)
-{
- return -1;
-}
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index e153422..e3ca068 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -45,14 +45,6 @@
#define ERR_remove_thread_state(tid) ERR_remove_state(0)
#endif
-#if OPENSSL_VERSION_NUMBER >= 0x10000000L
-/*
- * Session ticket override patch was merged into OpenSSL 0.9.9 tree on
- * 2008-11-15. This version uses a bit different API compared to the old patch.
- */
-#define CONFIG_OPENSSL_TICKET_OVERRIDE
-#endif
-
#if defined(OPENSSL_IS_BORINGSSL)
/* stack_index_t is the return type of OpenSSL's sk_XXX_num() functions. */
typedef size_t stack_index_t;
@@ -104,7 +96,7 @@
ENGINE *engine; /* functional reference to the engine */
EVP_PKEY *private_key; /* the private key if using engine */
#endif /* OPENSSL_NO_ENGINE */
- char *subject_match, *altsubject_match, *suffix_match;
+ char *subject_match, *altsubject_match, *suffix_match, *domain_match;
int read_alerts, write_alerts, failed;
tls_session_ticket_cb session_ticket_cb;
@@ -700,12 +692,15 @@
NULL, NULL
};
- if (!pkcs11_so_path || !pkcs11_module_path)
+ if (!pkcs11_so_path)
return 0;
pre_cmd[1] = pkcs11_so_path;
pre_cmd[3] = engine_id;
- post_cmd[1] = pkcs11_module_path;
+ if (pkcs11_module_path)
+ post_cmd[1] = pkcs11_module_path;
+ else
+ post_cmd[0] = NULL;
wpa_printf(MSG_DEBUG, "ENGINE: Loading pkcs11 Engine from %s",
pkcs11_so_path);
@@ -747,6 +742,7 @@
{
SSL_CTX *ssl;
struct tls_context *context;
+ const char *ciphers;
if (tls_openssl_ref_count == 0) {
tls_global = context = tls_context_new(conf);
@@ -809,7 +805,7 @@
}
tls_openssl_ref_count++;
- ssl = SSL_CTX_new(TLSv1_method());
+ ssl = SSL_CTX_new(SSLv23_method());
if (ssl == NULL) {
tls_openssl_ref_count--;
#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA
@@ -823,19 +819,22 @@
return NULL;
}
+ SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv2);
+ SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv3);
+
SSL_CTX_set_info_callback(ssl, ssl_info_cb);
#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA
SSL_CTX_set_app_data(ssl, context);
#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */
#ifndef OPENSSL_NO_ENGINE
+ wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine");
+ ERR_load_ENGINE_strings();
+ ENGINE_load_dynamic();
+
if (conf &&
(conf->opensc_engine_path || conf->pkcs11_engine_path ||
conf->pkcs11_module_path)) {
- wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine");
- ERR_load_ENGINE_strings();
- ENGINE_load_dynamic();
-
if (tls_engine_load_dynamic_opensc(conf->opensc_engine_path) ||
tls_engine_load_dynamic_pkcs11(conf->pkcs11_engine_path,
conf->pkcs11_module_path)) {
@@ -845,6 +844,18 @@
}
#endif /* OPENSSL_NO_ENGINE */
+ if (conf && conf->openssl_ciphers)
+ ciphers = conf->openssl_ciphers;
+ else
+ ciphers = "DEFAULT:!EXP:!LOW";
+ if (SSL_CTX_set_cipher_list(ssl, ciphers) != 1) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: Failed to set cipher string '%s'",
+ ciphers);
+ tls_deinit(ssl);
+ return NULL;
+ }
+
return ssl;
}
@@ -886,16 +897,6 @@
wpa_printf(MSG_ERROR, "ENGINE: Engine ID not set");
return -1;
}
-#ifndef ANDROID
- if (pin == NULL) {
- wpa_printf(MSG_ERROR, "ENGINE: Smartcard PIN not set");
- return -1;
- }
-#endif
- if (key_id == NULL) {
- wpa_printf(MSG_ERROR, "ENGINE: Key Id not set");
- return -1;
- }
ERR_clear_error();
#ifdef ANDROID
@@ -916,21 +917,34 @@
wpa_printf(MSG_DEBUG, "ENGINE: engine initialized");
#ifndef ANDROID
- if (ENGINE_ctrl_cmd_string(conn->engine, "PIN", pin, 0) == 0) {
+ if (pin && ENGINE_ctrl_cmd_string(conn->engine, "PIN", pin, 0) == 0) {
wpa_printf(MSG_ERROR, "ENGINE: cannot set pin [%s]",
ERR_error_string(ERR_get_error(), NULL));
goto err;
}
#endif
- /* load private key first in-case PIN is required for cert */
- conn->private_key = ENGINE_load_private_key(conn->engine,
- key_id, NULL, NULL);
- if (!conn->private_key) {
- wpa_printf(MSG_ERROR, "ENGINE: cannot load private key with id"
- " '%s' [%s]", key_id,
- ERR_error_string(ERR_get_error(), NULL));
- ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
- goto err;
+ if (key_id) {
+ /*
+ * Ensure that the ENGINE does not attempt to use the OpenSSL
+ * UI system to obtain a PIN, if we didn't provide one.
+ */
+ struct {
+ const void *password;
+ const char *prompt_info;
+ } key_cb = { "", NULL };
+
+ /* load private key first in-case PIN is required for cert */
+ conn->private_key = ENGINE_load_private_key(conn->engine,
+ key_id, NULL,
+ &key_cb);
+ if (!conn->private_key) {
+ wpa_printf(MSG_ERROR,
+ "ENGINE: cannot load private key with id '%s' [%s]",
+ key_id,
+ ERR_error_string(ERR_get_error(), NULL));
+ ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+ goto err;
+ }
}
/* handle a certificate and/or CA certificate */
@@ -1084,6 +1098,7 @@
os_free(conn->subject_match);
os_free(conn->altsubject_match);
os_free(conn->suffix_match);
+ os_free(conn->domain_match);
os_free(conn->session_ticket);
os_free(conn);
}
@@ -1176,7 +1191,8 @@
#ifndef CONFIG_NATIVE_WINDOWS
-static int domain_suffix_match(const u8 *val, size_t len, const char *match)
+static int domain_suffix_match(const u8 *val, size_t len, const char *match,
+ int full)
{
size_t i, match_len;
@@ -1189,7 +1205,7 @@
}
match_len = os_strlen(match);
- if (match_len > len)
+ if (match_len > len || (full && match_len != len))
return 0;
if (os_strncasecmp((const char *) val + len - match_len, match,
@@ -1208,7 +1224,7 @@
#endif /* CONFIG_NATIVE_WINDOWS */
-static int tls_match_suffix(X509 *cert, const char *match)
+static int tls_match_suffix(X509 *cert, const char *match, int full)
{
#ifdef CONFIG_NATIVE_WINDOWS
/* wincrypt.h has conflicting X509_NAME definition */
@@ -1221,7 +1237,8 @@
int dns_name = 0;
X509_NAME *name;
- wpa_printf(MSG_DEBUG, "TLS: Match domain against suffix %s", match);
+ wpa_printf(MSG_DEBUG, "TLS: Match domain against %s%s",
+ full ? "": "suffix ", match);
ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
@@ -1234,8 +1251,10 @@
gen->d.dNSName->data,
gen->d.dNSName->length);
if (domain_suffix_match(gen->d.dNSName->data,
- gen->d.dNSName->length, match) == 1) {
- wpa_printf(MSG_DEBUG, "TLS: Suffix match in dNSName found");
+ gen->d.dNSName->length, match, full) ==
+ 1) {
+ wpa_printf(MSG_DEBUG, "TLS: %s in dNSName found",
+ full ? "Match" : "Suffix match");
return 1;
}
}
@@ -1262,13 +1281,16 @@
continue;
wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate commonName",
cn->data, cn->length);
- if (domain_suffix_match(cn->data, cn->length, match) == 1) {
- wpa_printf(MSG_DEBUG, "TLS: Suffix match in commonName found");
+ if (domain_suffix_match(cn->data, cn->length, match, full) == 1)
+ {
+ wpa_printf(MSG_DEBUG, "TLS: %s in commonName found",
+ full ? "Match" : "Suffix match");
return 1;
}
}
- wpa_printf(MSG_DEBUG, "TLS: No CommonName suffix match found");
+ wpa_printf(MSG_DEBUG, "TLS: No CommonName %smatch found",
+ full ? "": "suffix ");
return 0;
#endif /* CONFIG_NATIVE_WINDOWS */
}
@@ -1363,6 +1385,11 @@
struct wpabuf *cert = NULL;
union tls_event_data ev;
struct tls_context *context = conn->context;
+ char *altsubject[TLS_MAX_ALT_SUBJECT];
+ int alt, num_altsubject = 0;
+ GENERAL_NAME *gen;
+ void *ext;
+ stack_index_t i;
#ifdef CONFIG_SHA256
u8 hash[32];
#endif /* CONFIG_SHA256 */
@@ -1389,8 +1416,52 @@
#endif /* CONFIG_SHA256 */
ev.peer_cert.depth = depth;
ev.peer_cert.subject = subject;
+
+ ext = X509_get_ext_d2i(err_cert, NID_subject_alt_name, NULL, NULL);
+ for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
+ char *pos;
+
+ if (num_altsubject == TLS_MAX_ALT_SUBJECT)
+ break;
+ gen = sk_GENERAL_NAME_value(ext, i);
+ if (gen->type != GEN_EMAIL &&
+ gen->type != GEN_DNS &&
+ gen->type != GEN_URI)
+ continue;
+
+ pos = os_malloc(10 + gen->d.ia5->length + 1);
+ if (pos == NULL)
+ break;
+ altsubject[num_altsubject++] = pos;
+
+ switch (gen->type) {
+ case GEN_EMAIL:
+ os_memcpy(pos, "EMAIL:", 6);
+ pos += 6;
+ break;
+ case GEN_DNS:
+ os_memcpy(pos, "DNS:", 4);
+ pos += 4;
+ break;
+ case GEN_URI:
+ os_memcpy(pos, "URI:", 4);
+ pos += 4;
+ break;
+ }
+
+ os_memcpy(pos, gen->d.ia5->data, gen->d.ia5->length);
+ pos += gen->d.ia5->length;
+ *pos = '\0';
+ }
+
+ for (alt = 0; alt < num_altsubject; alt++)
+ ev.peer_cert.altsubject[alt] = altsubject[alt];
+ ev.peer_cert.num_altsubject = num_altsubject;
+
context->event_cb(context->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
wpabuf_free(cert);
+ for (alt = 0; alt < num_altsubject; alt++)
+ os_free(altsubject[alt]);
}
@@ -1402,7 +1473,7 @@
SSL *ssl;
struct tls_connection *conn;
struct tls_context *context;
- char *match, *altmatch, *suffix_match;
+ char *match, *altmatch, *suffix_match, *domain_match;
const char *err_str;
err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
@@ -1430,6 +1501,7 @@
match = conn->subject_match;
altmatch = conn->altsubject_match;
suffix_match = conn->suffix_match;
+ domain_match = conn->domain_match;
if (!preverify_ok && !conn->ca_cert_verify)
preverify_ok = 1;
@@ -1499,13 +1571,21 @@
"AltSubject mismatch",
TLS_FAIL_ALTSUBJECT_MISMATCH);
} else if (depth == 0 && suffix_match &&
- !tls_match_suffix(err_cert, suffix_match)) {
+ !tls_match_suffix(err_cert, suffix_match, 0)) {
wpa_printf(MSG_WARNING, "TLS: Domain suffix match '%s' not found",
suffix_match);
preverify_ok = 0;
openssl_tls_fail_event(conn, err_cert, err, depth, buf,
"Domain suffix mismatch",
TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
+ } else if (depth == 0 && domain_match &&
+ !tls_match_suffix(err_cert, domain_match, 1)) {
+ wpa_printf(MSG_WARNING, "TLS: Domain match '%s' not found",
+ domain_match);
+ preverify_ok = 0;
+ openssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "Domain mismatch",
+ TLS_FAIL_DOMAIN_MISMATCH);
} else
openssl_tls_cert_event(conn, err_cert, depth, buf);
@@ -1769,7 +1849,8 @@
static int tls_connection_set_subject_match(struct tls_connection *conn,
const char *subject_match,
const char *altsubject_match,
- const char *suffix_match)
+ const char *suffix_match,
+ const char *domain_match)
{
os_free(conn->subject_match);
conn->subject_match = NULL;
@@ -1795,6 +1876,14 @@
return -1;
}
+ os_free(conn->domain_match);
+ conn->domain_match = NULL;
+ if (domain_match) {
+ conn->domain_match = os_strdup(domain_match);
+ if (conn->domain_match == NULL)
+ return -1;
+ }
+
return 0;
}
@@ -2852,7 +2941,7 @@
return -1;
}
ret = os_snprintf(pos, end - pos, ":%s", suite);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
break;
pos += ret;
@@ -2907,15 +2996,9 @@
if (conn == NULL || conn->ssl == NULL || ext_type != 35)
return -1;
-#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
if (SSL_set_session_ticket_ext(conn->ssl, (void *) data,
data_len) != 1)
return -1;
-#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
- if (SSL_set_hello_extension(conn->ssl, ext_type, (void *) data,
- data_len) != 1)
- return -1;
-#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
return 0;
}
@@ -3201,32 +3284,77 @@
{
int ret;
unsigned long err;
+ int can_pkcs11 = 0;
+ const char *key_id = params->key_id;
+ const char *cert_id = params->cert_id;
+ const char *ca_cert_id = params->ca_cert_id;
+ const char *engine_id = params->engine ? params->engine_id : NULL;
if (conn == NULL)
return -1;
+ /*
+ * If the engine isn't explicitly configured, and any of the
+ * cert/key fields are actually PKCS#11 URIs, then automatically
+ * use the PKCS#11 ENGINE.
+ */
+ if (!engine_id || os_strcmp(engine_id, "pkcs11") == 0)
+ can_pkcs11 = 1;
+
+ if (!key_id && params->private_key && can_pkcs11 &&
+ os_strncmp(params->private_key, "pkcs11:", 7) == 0) {
+ can_pkcs11 = 2;
+ key_id = params->private_key;
+ }
+
+ if (!cert_id && params->client_cert && can_pkcs11 &&
+ os_strncmp(params->client_cert, "pkcs11:", 7) == 0) {
+ can_pkcs11 = 2;
+ cert_id = params->client_cert;
+ }
+
+ if (!ca_cert_id && params->ca_cert && can_pkcs11 &&
+ os_strncmp(params->ca_cert, "pkcs11:", 7) == 0) {
+ can_pkcs11 = 2;
+ ca_cert_id = params->ca_cert;
+ }
+
+ /* If we need to automatically enable the PKCS#11 ENGINE, do so. */
+ if (can_pkcs11 == 2 && !engine_id)
+ engine_id = "pkcs11";
+
+ if (params->flags & TLS_CONN_EAP_FAST) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Use TLSv1_method() for EAP-FAST");
+ if (SSL_set_ssl_method(conn->ssl, TLSv1_method()) != 1) {
+ tls_show_errors(MSG_INFO, __func__,
+ "Failed to set TLSv1_method() for EAP-FAST");
+ return -1;
+ }
+ }
+
while ((err = ERR_get_error())) {
wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s",
__func__, ERR_error_string(err, NULL));
}
- if (params->engine) {
+ if (engine_id) {
wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine");
- ret = tls_engine_init(conn, params->engine_id, params->pin,
- params->key_id, params->cert_id,
- params->ca_cert_id);
+ ret = tls_engine_init(conn, engine_id, params->pin,
+ key_id, cert_id, ca_cert_id);
if (ret)
return ret;
}
if (tls_connection_set_subject_match(conn,
params->subject_match,
params->altsubject_match,
- params->suffix_match))
+ params->suffix_match,
+ params->domain_match))
return -1;
- if (params->engine && params->ca_cert_id) {
+ if (engine_id && ca_cert_id) {
if (tls_connection_engine_ca_cert(tls_ctx, conn,
- params->ca_cert_id))
+ ca_cert_id))
return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
} else if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert,
params->ca_cert_blob,
@@ -3234,15 +3362,15 @@
params->ca_path))
return -1;
- if (params->engine && params->cert_id) {
- if (tls_connection_engine_client_cert(conn, params->cert_id))
+ if (engine_id && cert_id) {
+ if (tls_connection_engine_client_cert(conn, cert_id))
return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
} else if (tls_connection_client_cert(conn, params->client_cert,
params->client_cert_blob,
params->client_cert_blob_len))
return -1;
- if (params->engine && params->key_id) {
+ if (engine_id && key_id) {
wpa_printf(MSG_DEBUG, "TLS: Using private key from engine");
if (tls_connection_engine_private_key(conn))
return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
@@ -3262,6 +3390,14 @@
return -1;
}
+ if (params->openssl_ciphers &&
+ SSL_set_cipher_list(conn->ssl, params->openssl_ciphers) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set cipher string '%s'",
+ params->openssl_ciphers);
+ return -1;
+ }
+
#ifdef SSL_OP_NO_TICKET
if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
SSL_set_options(conn->ssl, SSL_OP_NO_TICKET);
@@ -3328,6 +3464,14 @@
return -1;
}
+ if (params->openssl_ciphers &&
+ SSL_CTX_set_cipher_list(ssl_ctx, params->openssl_ciphers) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set cipher string '%s'",
+ params->openssl_ciphers);
+ return -1;
+ }
+
#ifdef SSL_OP_NO_TICKET
if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET);
@@ -3432,7 +3576,6 @@
}
-#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
static int tls_session_ticket_ext_cb(SSL *s, const unsigned char *data,
int len, void *arg)
{
@@ -3458,62 +3601,6 @@
return 1;
}
-#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
-#ifdef SSL_OP_NO_TICKET
-static void tls_hello_ext_cb(SSL *s, int client_server, int type,
- unsigned char *data, int len, void *arg)
-{
- struct tls_connection *conn = arg;
-
- if (conn == NULL || conn->session_ticket_cb == NULL)
- return;
-
- wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__,
- type, len);
-
- if (type == TLSEXT_TYPE_session_ticket && !client_server) {
- os_free(conn->session_ticket);
- conn->session_ticket = NULL;
-
- wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket "
- "extension", data, len);
- conn->session_ticket = os_malloc(len);
- if (conn->session_ticket == NULL)
- return;
-
- os_memcpy(conn->session_ticket, data, len);
- conn->session_ticket_len = len;
- }
-}
-#else /* SSL_OP_NO_TICKET */
-static int tls_hello_ext_cb(SSL *s, TLS_EXTENSION *ext, void *arg)
-{
- struct tls_connection *conn = arg;
-
- if (conn == NULL || conn->session_ticket_cb == NULL)
- return 0;
-
- wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__,
- ext->type, ext->length);
-
- os_free(conn->session_ticket);
- conn->session_ticket = NULL;
-
- if (ext->type == 35) {
- wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket "
- "extension", ext->data, ext->length);
- conn->session_ticket = os_malloc(ext->length);
- if (conn->session_ticket == NULL)
- return SSL_AD_INTERNAL_ERROR;
-
- os_memcpy(conn->session_ticket, ext->data, ext->length);
- conn->session_ticket_len = ext->length;
- }
-
- return 0;
-}
-#endif /* SSL_OP_NO_TICKET */
-#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
@@ -3530,33 +3617,12 @@
if (SSL_set_session_secret_cb(conn->ssl, tls_sess_sec_cb,
conn) != 1)
return -1;
-#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
SSL_set_session_ticket_ext_cb(conn->ssl,
tls_session_ticket_ext_cb, conn);
-#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
-#ifdef SSL_OP_NO_TICKET
- SSL_set_tlsext_debug_callback(conn->ssl, tls_hello_ext_cb);
- SSL_set_tlsext_debug_arg(conn->ssl, conn);
-#else /* SSL_OP_NO_TICKET */
- if (SSL_set_hello_extension_cb(conn->ssl, tls_hello_ext_cb,
- conn) != 1)
- return -1;
-#endif /* SSL_OP_NO_TICKET */
-#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
} else {
if (SSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1)
return -1;
-#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
SSL_set_session_ticket_ext_cb(conn->ssl, NULL, NULL);
-#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
-#ifdef SSL_OP_NO_TICKET
- SSL_set_tlsext_debug_callback(conn->ssl, NULL);
- SSL_set_tlsext_debug_arg(conn->ssl, conn);
-#else /* SSL_OP_NO_TICKET */
- if (SSL_set_hello_extension_cb(conn->ssl, NULL, NULL) != 1)
- return -1;
-#endif /* SSL_OP_NO_TICKET */
-#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
}
return 0;
@@ -3564,3 +3630,11 @@
return -1;
#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
}
+
+
+int tls_get_library_version(char *buf, size_t buf_len)
+{
+ return os_snprintf(buf, buf_len, "OpenSSL build=%s run=%s",
+ OPENSSL_VERSION_TEXT,
+ SSLeay_version(SSLEAY_VERSION));
+}
diff --git a/src/crypto/tls_schannel.c b/src/crypto/tls_schannel.c
index 2c2daa8..31a2c94 100644
--- a/src/crypto/tls_schannel.c
+++ b/src/crypto/tls_schannel.c
@@ -692,6 +692,31 @@
if (conn == NULL)
return -1;
+ if (params->subject_match) {
+ wpa_printf(MSG_INFO, "TLS: subject_match not supported");
+ return -1;
+ }
+
+ if (params->altsubject_match) {
+ wpa_printf(MSG_INFO, "TLS: altsubject_match not supported");
+ return -1;
+ }
+
+ if (params->suffix_match) {
+ wpa_printf(MSG_INFO, "TLS: suffix_match not supported");
+ return -1;
+ }
+
+ if (params->domain_match) {
+ wpa_printf(MSG_INFO, "TLS: domain_match not supported");
+ return -1;
+ }
+
+ if (params->openssl_ciphers) {
+ wpa_printf(MSG_INFO, "GnuTLS: openssl_ciphers not supported");
+ return -1;
+ }
+
if (global->my_cert_store == NULL &&
(global->my_cert_store = CertOpenSystemStore(0, TEXT("MY"))) ==
NULL) {
@@ -730,3 +755,9 @@
{
return 0;
}
+
+
+int tls_get_library_version(char *buf, size_t buf_len)
+{
+ return os_snprintf(buf, buf_len, "schannel");
+}
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 6af7294..c9e860f 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1,6 +1,6 @@
/*
* Driver interface definition
- * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -23,8 +23,7 @@
#include "utils/list.h"
#define HOSTAPD_CHAN_DISABLED 0x00000001
-#define HOSTAPD_CHAN_PASSIVE_SCAN 0x00000002
-#define HOSTAPD_CHAN_NO_IBSS 0x00000004
+#define HOSTAPD_CHAN_NO_IR 0x00000002
#define HOSTAPD_CHAN_RADAR 0x00000008
#define HOSTAPD_CHAN_HT40PLUS 0x00000010
#define HOSTAPD_CHAN_HT40MINUS 0x00000020
@@ -42,6 +41,12 @@
#define HOSTAPD_CHAN_VHT_50_30 0x00002000
#define HOSTAPD_CHAN_VHT_70_10 0x00004000
+#define HOSTAPD_CHAN_INDOOR_ONLY 0x00010000
+#define HOSTAPD_CHAN_GO_CONCURRENT 0x00020000
+
+/**
+ * enum reg_change_initiator - Regulatory change initiator
+ */
enum reg_change_initiator {
REGDOM_SET_BY_CORE,
REGDOM_SET_BY_USER,
@@ -50,6 +55,9 @@
REGDOM_BEACON_HINT,
};
+/**
+ * enum reg_type - Regulatory change types
+ */
enum reg_type {
REGDOM_TYPE_UNKNOWN,
REGDOM_TYPE_COUNTRY,
@@ -82,8 +90,8 @@
*/
u8 max_tx_power;
- /*
- * survey_list - Linked list of surveys
+ /**
+ * survey_list - Linked list of surveys (struct freq_survey)
*/
struct dl_list survey_list;
@@ -102,7 +110,9 @@
long double interference_factor;
#endif /* CONFIG_ACS */
- /* DFS CAC time in milliseconds */
+ /**
+ * dfs_cac_ms - DFS CAC time in milliseconds
+ */
unsigned int dfs_cac_ms;
};
@@ -170,10 +180,12 @@
#define IEEE80211_MODE_INFRA 0
#define IEEE80211_MODE_IBSS 1
#define IEEE80211_MODE_AP 2
+#define IEEE80211_MODE_MESH 5
#define IEEE80211_CAP_ESS 0x0001
#define IEEE80211_CAP_IBSS 0x0002
#define IEEE80211_CAP_PRIVACY 0x0010
+#define IEEE80211_CAP_RRM 0x1000
/* DMG (60 GHz) IEEE 802.11ad */
/* type - bits 0..1 */
@@ -186,7 +198,6 @@
#define WPA_SCAN_NOISE_INVALID BIT(1)
#define WPA_SCAN_LEVEL_INVALID BIT(2)
#define WPA_SCAN_LEVEL_DBM BIT(3)
-#define WPA_SCAN_AUTHENTICATED BIT(4)
#define WPA_SCAN_ASSOCIATED BIT(5)
/**
@@ -213,6 +224,11 @@
* constructed of the IEs that are available. This field will also need to
* include SSID in IE format. All drivers are encouraged to be extended to
* report all IEs to make it easier to support future additions.
+ *
+ * This structure data is followed by ie_len octets of IEs from Probe Response
+ * frame (or if the driver does not indicate source of IEs, these may also be
+ * from Beacon frame). After the first set of IEs, another set of IEs may follow
+ * (with beacon_ie_len octets of data) if the driver provides both IE sets.
*/
struct wpa_scan_res {
unsigned int flags;
@@ -227,13 +243,7 @@
unsigned int age;
size_t ie_len;
size_t beacon_ie_len;
- /*
- * Followed by ie_len octets of IEs from Probe Response frame (or if
- * the driver does not indicate source of IEs, these may also be from
- * Beacon frame). After the first set of IEs, another set of IEs may
- * follow (with beacon_ie_len octets of data) if the driver provides
- * both IE sets.
- */
+ /* Followed by ie_len + beacon_ie_len octets of IE data */
};
/**
@@ -370,6 +380,27 @@
*/
unsigned int low_priority:1;
+ /**
+ * mac_addr_rand - Requests driver to randomize MAC address
+ */
+ unsigned int mac_addr_rand:1;
+
+ /**
+ * mac_addr - MAC address used with randomization. The address cannot be
+ * a multicast one, i.e., bit 0 of byte 0 should not be set.
+ */
+ const u8 *mac_addr;
+
+ /**
+ * mac_addr_mask - MAC address mask used with randomization.
+ *
+ * Bits that are 0 in the mask should be randomized. Bits that are 1 in
+ * the mask should be taken as is from mac_addr. The mask should not
+ * allow the generation of a multicast address, i.e., bit 0 of byte 0
+ * must be set.
+ */
+ const u8 *mac_addr_mask;
+
/*
* NOTE: Whenever adding new parameters here, please make sure
* wpa_scan_clone_params() and wpa_scan_free_params() get updated with
@@ -399,34 +430,95 @@
*/
int p2p;
+ /**
+ * sae_data - SAE elements for Authentication frame
+ *
+ * This buffer starts with the Authentication transaction sequence
+ * number field. If SAE is not used, this pointer is %NULL.
+ */
const u8 *sae_data;
+
+ /**
+ * sae_data_len - Length of sae_data buffer in octets
+ */
size_t sae_data_len;
-
};
+/**
+ * enum wps_mode - WPS mode
+ */
enum wps_mode {
- WPS_MODE_NONE /* no WPS provisioning being used */,
- WPS_MODE_OPEN /* WPS provisioning with AP that is in open mode */,
- WPS_MODE_PRIVACY /* WPS provisioning with AP that is using protection
- */
+ /**
+ * WPS_MODE_NONE - No WPS provisioning being used
+ */
+ WPS_MODE_NONE,
+
+ /**
+ * WPS_MODE_OPEN - WPS provisioning with AP that is in open mode
+ */
+ WPS_MODE_OPEN,
+
+ /**
+ * WPS_MODE_PRIVACY - WPS provisioning with AP that is using protection
+ */
+ WPS_MODE_PRIVACY
};
+/**
+ * struct hostapd_freq_params - Channel parameters
+ */
struct hostapd_freq_params {
- int mode;
- int freq;
- int channel;
- /* for HT */
- int ht_enabled;
- int sec_channel_offset; /* 0 = HT40 disabled, -1 = HT40 enabled,
- * secondary channel below primary, 1 = HT40
- * enabled, secondary channel above primary */
+ /**
+ * mode - Mode/band (HOSTAPD_MODE_IEEE80211A, ..)
+ */
+ enum hostapd_hw_mode mode;
- /* for VHT */
+ /**
+ * freq - Primary channel center frequency in MHz
+ */
+ int freq;
+
+ /**
+ * channel - Channel number
+ */
+ int channel;
+
+ /**
+ * ht_enabled - Whether HT is enabled
+ */
+ int ht_enabled;
+
+ /**
+ * sec_channel_offset - Secondary channel offset for HT40
+ *
+ * 0 = HT40 disabled,
+ * -1 = HT40 enabled, secondary channel below primary,
+ * 1 = HT40 enabled, secondary channel above primary
+ */
+ int sec_channel_offset;
+
+ /**
+ * vht_enabled - Whether VHT is enabled
+ */
int vht_enabled;
- /* valid for both HT and VHT, center_freq2 is non-zero
- * only for bandwidth 80 and an 80+80 channel */
- int center_freq1, center_freq2;
+ /**
+ * center_freq1 - Segment 0 center frequency in MHz
+ *
+ * Valid for both HT and VHT.
+ */
+ int center_freq1;
+
+ /**
+ * center_freq2 - Segment 1 center frequency in MHz
+ *
+ * Non-zero only for bandwidth 80 and an 80+80 channel
+ */
+ int center_freq2;
+
+ /**
+ * bandwidth - Channel bandwidth in MHz (20, 40, 80, 160)
+ */
int bandwidth;
};
@@ -680,12 +772,21 @@
int disable_ht;
/**
- * HT Capabilities over-rides. Only bits set in the mask will be used,
- * and not all values are used by the kernel anyway. Currently, MCS,
- * MPDU and MSDU fields are used.
+ * htcaps - HT Capabilities over-rides
+ *
+ * Only bits set in the mask will be used, and not all values are used
+ * by the kernel anyway. Currently, MCS, MPDU and MSDU fields are used.
+ *
+ * Pointer to struct ieee80211_ht_capabilities.
*/
- const u8 *htcaps; /* struct ieee80211_ht_capabilities * */
- const u8 *htcaps_mask; /* struct ieee80211_ht_capabilities * */
+ const u8 *htcaps;
+
+ /**
+ * htcaps_mask - HT Capabilities over-rides mask
+ *
+ * Pointer to struct ieee80211_ht_capabilities.
+ */
+ const u8 *htcaps_mask;
#ifdef CONFIG_VHT_OVERRIDES
/**
@@ -699,6 +800,20 @@
const struct ieee80211_vht_capabilities *vhtcaps;
const struct ieee80211_vht_capabilities *vhtcaps_mask;
#endif /* CONFIG_VHT_OVERRIDES */
+
+ /**
+ * req_key_mgmt_offload - Request key management offload for connection
+ *
+ * Request key management offload for this connection if the device
+ * supports it.
+ */
+ int req_key_mgmt_offload;
+
+ /**
+ * Flag for indicating whether this association includes support for
+ * RRM (Radio Resource Measurements)
+ */
+ int rrm_used;
};
enum hide_ssid {
@@ -895,6 +1010,14 @@
int ap_max_inactivity;
/**
+ * smps_mode - SMPS mode
+ *
+ * SMPS mode to be used by the AP, specified as the relevant bits of
+ * ht_capab (i.e. HT_CAP_INFO_SMPS_*).
+ */
+ unsigned int smps_mode;
+
+ /**
* disable_dgaf - Whether group-addressed frames are disabled
*/
int disable_dgaf;
@@ -910,6 +1033,33 @@
struct hostapd_freq_params *freq;
};
+struct wpa_driver_mesh_bss_params {
+#define WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS 0x00000001
+ /*
+ * TODO: Other mesh configuration parameters would go here.
+ * See NL80211_MESHCONF_* for all the mesh config parameters.
+ */
+ unsigned int flags;
+ int peer_link_timeout;
+};
+
+struct wpa_driver_mesh_join_params {
+ const u8 *meshid;
+ int meshid_len;
+ const int *basic_rates;
+ const u8 *ies;
+ int ie_len;
+ struct hostapd_freq_params freq;
+ int beacon_int;
+ int max_peer_links;
+ struct wpa_driver_mesh_bss_params conf;
+#define WPA_DRIVER_MESH_FLAG_USER_MPM 0x00000001
+#define WPA_DRIVER_MESH_FLAG_DRIVER_MPM 0x00000002
+#define WPA_DRIVER_MESH_FLAG_SAE_AUTH 0x00000004
+#define WPA_DRIVER_MESH_FLAG_AMPE 0x00000008
+ unsigned int flags;
+};
+
/**
* struct wpa_driver_capa - Driver capability information
*/
@@ -922,6 +1072,9 @@
#define WPA_DRIVER_CAPA_KEY_MGMT_FT 0x00000020
#define WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK 0x00000040
#define WPA_DRIVER_CAPA_KEY_MGMT_WAPI_PSK 0x00000080
+#define WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B 0x00000100
+#define WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192 0x00000200
+ /** Bitfield of supported key management suites */
unsigned int key_mgmt;
#define WPA_DRIVER_CAPA_ENC_WEP40 0x00000001
@@ -937,94 +1090,123 @@
#define WPA_DRIVER_CAPA_ENC_BIP_GMAC_256 0x00000400
#define WPA_DRIVER_CAPA_ENC_BIP_CMAC_256 0x00000800
#define WPA_DRIVER_CAPA_ENC_GTK_NOT_USED 0x00001000
+ /** Bitfield of supported cipher suites */
unsigned int enc;
#define WPA_DRIVER_AUTH_OPEN 0x00000001
#define WPA_DRIVER_AUTH_SHARED 0x00000002
#define WPA_DRIVER_AUTH_LEAP 0x00000004
+ /** Bitfield of supported IEEE 802.11 authentication algorithms */
unsigned int auth;
-/* Driver generated WPA/RSN IE */
+/** Driver generated WPA/RSN IE */
#define WPA_DRIVER_FLAGS_DRIVER_IE 0x00000001
-/* Driver needs static WEP key setup after association command */
+/** Driver needs static WEP key setup after association command */
#define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC 0x00000002
-/* Driver takes care of all DFS operations */
+/** Driver takes care of all DFS operations */
#define WPA_DRIVER_FLAGS_DFS_OFFLOAD 0x00000004
-/* Driver takes care of RSN 4-way handshake internally; PMK is configured with
+/** Driver takes care of RSN 4-way handshake internally; PMK is configured with
* struct wpa_driver_ops::set_key using alg = WPA_ALG_PMK */
#define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE 0x00000008
+/** Driver is for a wired Ethernet interface */
#define WPA_DRIVER_FLAGS_WIRED 0x00000010
-/* Driver provides separate commands for authentication and association (SME in
+/** Driver provides separate commands for authentication and association (SME in
* wpa_supplicant). */
#define WPA_DRIVER_FLAGS_SME 0x00000020
-/* Driver supports AP mode */
+/** Driver supports AP mode */
#define WPA_DRIVER_FLAGS_AP 0x00000040
-/* Driver needs static WEP key setup after association has been completed */
+/** Driver needs static WEP key setup after association has been completed */
#define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE 0x00000080
-/* Driver supports dynamic HT 20/40 MHz channel changes during BSS lifetime */
+/** Driver supports dynamic HT 20/40 MHz channel changes during BSS lifetime */
#define WPA_DRIVER_FLAGS_HT_2040_COEX 0x00000100
-/* Driver supports concurrent P2P operations */
+/** Driver supports concurrent P2P operations */
#define WPA_DRIVER_FLAGS_P2P_CONCURRENT 0x00000200
-/*
+/**
* Driver uses the initial interface as a dedicated management interface, i.e.,
* it cannot be used for P2P group operations or non-P2P purposes.
*/
#define WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE 0x00000400
-/* This interface is P2P capable (P2P GO or P2P Client) */
+/** This interface is P2P capable (P2P GO or P2P Client) */
#define WPA_DRIVER_FLAGS_P2P_CAPABLE 0x00000800
-/* Driver supports station and key removal when stopping an AP */
+/** Driver supports station and key removal when stopping an AP */
#define WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT 0x00001000
-/*
+/**
* Driver uses the initial interface for P2P management interface and non-P2P
* purposes (e.g., connect to infra AP), but this interface cannot be used for
* P2P group operations.
*/
#define WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P 0x00002000
-/*
+/**
* Driver is known to use sane error codes, i.e., when it indicates that
* something (e.g., association) fails, there was indeed a failure and the
* operation does not end up getting completed successfully later.
*/
#define WPA_DRIVER_FLAGS_SANE_ERROR_CODES 0x00004000
-/* Driver supports off-channel TX */
+/** Driver supports off-channel TX */
#define WPA_DRIVER_FLAGS_OFFCHANNEL_TX 0x00008000
-/* Driver indicates TX status events for EAPOL Data frames */
+/** Driver indicates TX status events for EAPOL Data frames */
#define WPA_DRIVER_FLAGS_EAPOL_TX_STATUS 0x00010000
-/* Driver indicates TX status events for Deauth/Disassoc frames */
+/** Driver indicates TX status events for Deauth/Disassoc frames */
#define WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS 0x00020000
-/* Driver supports roaming (BSS selection) in firmware */
+/** Driver supports roaming (BSS selection) in firmware */
#define WPA_DRIVER_FLAGS_BSS_SELECTION 0x00040000
-/* Driver supports operating as a TDLS peer */
+/** Driver supports operating as a TDLS peer */
#define WPA_DRIVER_FLAGS_TDLS_SUPPORT 0x00080000
-/* Driver requires external TDLS setup/teardown/discovery */
+/** Driver requires external TDLS setup/teardown/discovery */
#define WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP 0x00100000
-/* Driver indicates support for Probe Response offloading in AP mode */
+/** Driver indicates support for Probe Response offloading in AP mode */
#define WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD 0x00200000
-/* Driver supports U-APSD in AP mode */
+/** Driver supports U-APSD in AP mode */
#define WPA_DRIVER_FLAGS_AP_UAPSD 0x00400000
-/* Driver supports inactivity timer in AP mode */
+/** Driver supports inactivity timer in AP mode */
#define WPA_DRIVER_FLAGS_INACTIVITY_TIMER 0x00800000
-/* Driver expects user space implementation of MLME in AP mode */
+/** Driver expects user space implementation of MLME in AP mode */
#define WPA_DRIVER_FLAGS_AP_MLME 0x01000000
-/* Driver supports SAE with user space SME */
+/** Driver supports SAE with user space SME */
#define WPA_DRIVER_FLAGS_SAE 0x02000000
-/* Driver makes use of OBSS scan mechanism in wpa_supplicant */
+/** Driver makes use of OBSS scan mechanism in wpa_supplicant */
#define WPA_DRIVER_FLAGS_OBSS_SCAN 0x04000000
-/* Driver supports IBSS (Ad-hoc) mode */
+/** Driver supports IBSS (Ad-hoc) mode */
#define WPA_DRIVER_FLAGS_IBSS 0x08000000
-/* Driver supports radar detection */
+/** Driver supports radar detection */
#define WPA_DRIVER_FLAGS_RADAR 0x10000000
-/* Driver supports a dedicated interface for P2P Device */
+/** Driver supports a dedicated interface for P2P Device */
#define WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE 0x20000000
-/* Driver supports QoS Mapping */
+/** Driver supports QoS Mapping */
#define WPA_DRIVER_FLAGS_QOS_MAPPING 0x40000000
-/* Driver supports CSA in AP mode */
+/** Driver supports CSA in AP mode */
#define WPA_DRIVER_FLAGS_AP_CSA 0x80000000
- unsigned int flags;
+/** Driver supports mesh */
+#define WPA_DRIVER_FLAGS_MESH 0x0000000100000000ULL
+/** Driver support ACS offload */
+#define WPA_DRIVER_FLAGS_ACS_OFFLOAD 0x0000000200000000ULL
+/** Driver supports key management offload */
+#define WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD 0x0000000400000000ULL
+/** Driver supports TDLS channel switching */
+#define WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH 0x0000000800000000ULL
+/** Driver supports IBSS with HT datarates */
+#define WPA_DRIVER_FLAGS_HT_IBSS 0x0000001000000000ULL
+ u64 flags;
+#define WPA_DRIVER_SMPS_MODE_STATIC 0x00000001
+#define WPA_DRIVER_SMPS_MODE_DYNAMIC 0x00000002
+ unsigned int smps_modes;
+
+ unsigned int wmm_ac_supported:1;
+
+ unsigned int mac_addr_rand_scan_supported:1;
+ unsigned int mac_addr_rand_sched_scan_supported:1;
+
+ /** Maximum number of supported active probe SSIDs */
int max_scan_ssids;
+
+ /** Maximum number of supported active probe SSIDs for sched_scan */
int max_sched_scan_ssids;
+
+ /** Whether sched_scan (offloaded scanning) is supported */
int sched_scan_supported;
+
+ /** Maximum number of supported match sets for sched_scan */
int max_match_sets;
/**
@@ -1042,13 +1224,13 @@
* probe_resp_offloads - Bitmap of supported protocols by the driver
* for Probe Response offloading.
*/
-/* Driver Probe Response offloading support for WPS ver. 1 */
+/** Driver Probe Response offloading support for WPS ver. 1 */
#define WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS 0x00000001
-/* Driver Probe Response offloading support for WPS ver. 2 */
+/** Driver Probe Response offloading support for WPS ver. 2 */
#define WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2 0x00000002
-/* Driver Probe Response offloading support for P2P */
+/** Driver Probe Response offloading support for P2P */
#define WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P 0x00000004
-/* Driver Probe Response offloading support for IEEE 802.11u (Interworking) */
+/** Driver Probe Response offloading support for IEEE 802.11u (Interworking) */
#define WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING 0x00000008
unsigned int probe_resp_offloads;
@@ -1069,6 +1251,24 @@
unsigned int extended_capa_len;
struct wowlan_triggers wowlan_triggers;
+
+/** Driver adds the DS Params Set IE in Probe Request frames */
+#define WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES 0x00000001
+/** Driver adds the WFA TPC IE in Probe Request frames */
+#define WPA_DRIVER_FLAGS_WFA_TPC_IE_IN_PROBES 0x00000002
+/** Driver handles quiet period requests */
+#define WPA_DRIVER_FLAGS_QUIET 0x00000004
+/**
+ * Driver is capable of inserting the current TX power value into the body of
+ * transmitted frames.
+ * Background: Some Action frames include a TPC Report IE. This IE contains a
+ * TX power field, which has to be updated by lower layers. One such Action
+ * frame is Link Measurement Report (part of RRM). Another is TPC Report (part
+ * of spectrum management). Note that this insertion takes place at a fixed
+ * offset, namely the 6th byte in the Action frame body.
+ */
+#define WPA_DRIVER_FLAGS_TX_POWER_INSERTION 0x00000008
+ u32 rrm_flags;
};
@@ -1098,6 +1298,10 @@
int vht_opmode_enabled;
u8 vht_opmode;
u32 flags; /* bitmask of WPA_STA_* flags */
+ u32 flags_mask; /* unset bits in flags */
+#ifdef CONFIG_MESH
+ enum mesh_plink_state plink_state;
+#endif /* CONFIG_MESH */
int set; /* Set STA parameters instead of add */
u8 qosinfo;
const u8 *ext_capab;
@@ -1159,16 +1363,19 @@
* WPA_IF_P2P_DEVICE - P2P Device interface is used to indentify the
* abstracted P2P Device function in the driver
*/
- WPA_IF_P2P_DEVICE
+ WPA_IF_P2P_DEVICE,
+
+ /*
+ * WPA_IF_MESH - Mesh interface
+ */
+ WPA_IF_MESH,
};
struct wpa_init_params {
void *global_priv;
const u8 *bssid;
const char *ifname;
- const u8 *ssid;
- size_t ssid_len;
- const char *test_socket;
+ const char *driver_params;
int use_pae_group_addr;
char **bridge;
size_t num_bridge;
@@ -1197,6 +1404,7 @@
#define WPA_STA_SHORT_PREAMBLE BIT(2)
#define WPA_STA_MFP BIT(3)
#define WPA_STA_TDLS_PEER BIT(4)
+#define WPA_STA_AUTHENTICATED BIT(5)
enum tdls_oper {
TDLS_DISCOVERY_REQ,
@@ -1311,6 +1519,23 @@
TDLS_PEER_WMM = BIT(2),
};
+/* valid info in the wmm_params struct */
+enum wmm_params_valid_info {
+ WMM_PARAMS_UAPSD_QUEUES_INFO = BIT(0),
+};
+
+/**
+ * struct wmm_params - WMM parameterss configured for this association
+ * @info_bitmap: Bitmap of valid wmm_params info; indicates what fields
+ * of the struct contain valid information.
+ * @uapsd_queues: Bitmap of ACs configured for uapsd (valid only if
+ * %WMM_PARAMS_UAPSD_QUEUES_INFO is set)
+ */
+struct wmm_params {
+ u8 info_bitmap;
+ u8 uapsd_queues;
+};
+
#ifdef CONFIG_MACSEC
struct macsec_init_params {
Boolean always_include_sci;
@@ -1319,6 +1544,26 @@
};
#endif /* CONFIG_MACSEC */
+enum drv_br_port_attr {
+ DRV_BR_PORT_ATTR_PROXYARP,
+ DRV_BR_PORT_ATTR_HAIRPIN_MODE,
+};
+
+enum drv_br_net_param {
+ DRV_BR_NET_PARAM_GARP_ACCEPT,
+};
+
+struct drv_acs_params {
+ /* Selected mode (HOSTAPD_MODE_*) */
+ enum hostapd_hw_mode hw_mode;
+
+ /* Indicates whether HT is enabled */
+ int ht_enabled;
+
+ /* Indicates whether HT40 is enabled */
+ int ht40_enabled;
+};
+
/**
* struct wpa_driver_ops - Driver interface API definition
@@ -1605,27 +1850,6 @@
const u8 * (*get_mac_addr)(void *priv);
/**
- * send_eapol - Optional function for sending EAPOL packets
- * @priv: private driver interface data
- * @dest: Destination MAC address
- * @proto: Ethertype
- * @data: EAPOL packet starting with IEEE 802.1X header
- * @data_len: Size of the EAPOL packet
- *
- * Returns: 0 on success, -1 on failure
- *
- * This optional function can be used to override l2_packet operations
- * with driver specific functionality. If this function pointer is set,
- * l2_packet module is not used at all and the driver interface code is
- * responsible for receiving and sending all EAPOL packets. The
- * received EAPOL packets are sent to core code with EVENT_EAPOL_RX
- * event. The driver interface is required to implement get_mac_addr()
- * handler if send_eapol() is used.
- */
- int (*send_eapol)(void *priv, const u8 *dest, u16 proto,
- const u8 *data, size_t data_len);
-
- /**
* set_operstate - Sets device operating state to DORMANT or UP
* @priv: private driver interface data
* @state: 0 = dormant, 1 = up
@@ -1700,22 +1924,6 @@
size_t ies_len);
/**
- * send_ft_action - Send FT Action frame (IEEE 802.11r)
- * @priv: Private driver interface data
- * @action: Action field value
- * @target_ap: Target AP address
- * @ies: FT IEs (MDIE, FTIE, ...) (FT Request action frame body)
- * @ies_len: Length of FT IEs in bytes
- * Returns: 0 on success, -1 on failure
- *
- * The supplicant uses this callback to request the driver to transmit
- * an FT Action frame (action category 6) for over-the-DS fast BSS
- * transition.
- */
- int (*send_ft_action)(void *priv, u8 action, const u8 *target_ap,
- const u8 *ies, size_t ies_len);
-
- /**
* get_scan_results2 - Fetch the latest scan results
* @priv: private driver interface data
*
@@ -2547,6 +2755,45 @@
u8 qos_map_set_len);
/**
+ * br_add_ip_neigh - Add a neigh to the bridge ip neigh table
+ * @priv: Private driver interface data
+ * @version: IP version of the IP address, 4 or 6
+ * @ipaddr: IP address for the neigh entry
+ * @prefixlen: IP address prefix length
+ * @addr: Corresponding MAC address
+ * Returns: 0 on success, negative (<0) on failure
+ */
+ int (*br_add_ip_neigh)(void *priv, u8 version, const u8 *ipaddr,
+ int prefixlen, const u8 *addr);
+
+ /**
+ * br_delete_ip_neigh - Remove a neigh from the bridge ip neigh table
+ * @priv: Private driver interface data
+ * @version: IP version of the IP address, 4 or 6
+ * @ipaddr: IP address for the neigh entry
+ * Returns: 0 on success, negative (<0) on failure
+ */
+ int (*br_delete_ip_neigh)(void *priv, u8 version, const u8 *ipaddr);
+
+ /**
+ * br_port_set_attr - Set a bridge port attribute
+ * @attr: Bridge port attribute to set
+ * @val: Value to be set
+ * Returns: 0 on success, negative (<0) on failure
+ */
+ int (*br_port_set_attr)(void *priv, enum drv_br_port_attr attr,
+ unsigned int val);
+
+ /**
+ * br_port_set_attr - Set a bridge network parameter
+ * @param: Bridge parameter to set
+ * @val: Value to be set
+ * Returns: 0 on success, negative (<0) on failure
+ */
+ int (*br_set_net_param)(void *priv, enum drv_br_net_param param,
+ unsigned int val);
+
+ /**
* set_wowlan - Set wake-on-wireless triggers
* @priv: Private driver interface data
* @triggers: wowlan triggers
@@ -2614,14 +2861,17 @@
* set_rekey_info - Set rekey information
* @priv: Private driver interface data
* @kek: Current KEK
+ * @kek_len: KEK length in octets
* @kck: Current KCK
+ * @kck_len: KCK length in octets
* @replay_ctr: Current EAPOL-Key Replay Counter
*
* This optional function can be used to provide information for the
* driver/firmware to process EAPOL-Key frames in Group Key Handshake
* while the host (including wpa_supplicant) is sleeping.
*/
- void (*set_rekey_info)(void *priv, const u8 *kek, const u8 *kck,
+ void (*set_rekey_info)(void *priv, const u8 *kek, size_t kek_len,
+ const u8 *kck, size_t kck_len,
const u8 *replay_ctr);
/**
@@ -2751,6 +3001,55 @@
int (*switch_channel)(void *priv, struct csa_settings *settings);
/**
+ * add_tx_ts - Add traffic stream
+ * @priv: Private driver interface data
+ * @tsid: Traffic stream ID
+ * @addr: Receiver address
+ * @user_prio: User priority of the traffic stream
+ * @admitted_time: Admitted time for this TS in units of
+ * 32 microsecond periods (per second).
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*add_tx_ts)(void *priv, u8 tsid, const u8 *addr, u8 user_prio,
+ u16 admitted_time);
+
+ /**
+ * del_tx_ts - Delete traffic stream
+ * @priv: Private driver interface data
+ * @tsid: Traffic stream ID
+ * @addr: Receiver address
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*del_tx_ts)(void *priv, u8 tsid, const u8 *addr);
+
+ /**
+ * Enable channel-switching with TDLS peer
+ * @priv: Private driver interface data
+ * @addr: MAC address of the TDLS peer
+ * @oper_class: Operating class of the switch channel
+ * @params: Channel specification
+ * Returns: 0 on success, -1 on failure
+ *
+ * The function indicates to driver that it can start switching to a
+ * different channel with a specified TDLS peer. The switching is
+ * assumed on until canceled with tdls_disable_channel_switch().
+ */
+ int (*tdls_enable_channel_switch)(
+ void *priv, const u8 *addr, u8 oper_class,
+ const struct hostapd_freq_params *params);
+
+ /**
+ * Disable channel switching with TDLS peer
+ * @priv: Private driver interface data
+ * @addr: MAC address of the TDLS peer
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function indicates to the driver that it should stop switching
+ * with a given TDLS peer.
+ */
+ int (*tdls_disable_channel_switch)(void *priv, const u8 *addr);
+
+ /**
* start_dfs_cac - Listen for radar interference on the channel
* @priv: Private driver interface data
* @freq: Channel parameters
@@ -3023,6 +3322,40 @@
*/
int (*disable_transmit_sa)(void *priv, u32 channel, u8 an);
#endif /* CONFIG_MACSEC */
+
+ /**
+ * init_mesh - Driver specific initialization for mesh
+ * @priv: Private driver interface data
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*init_mesh)(void *priv);
+
+ /**
+ * join_mesh - Join a mesh network
+ * @priv: Private driver interface data
+ * @params: Mesh configuration parameters
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*join_mesh)(void *priv,
+ struct wpa_driver_mesh_join_params *params);
+
+ /**
+ * leave_mesh - Leave a mesh network
+ * @priv: Private driver interface data
+ * Returns 0 on success, -1 on failure
+ */
+ int (*leave_mesh)(void *priv);
+
+ /**
+ * do_acs - Automatically select channel
+ * @priv: Private driver interface data
+ * @params: Parameters for ACS
+ * Returns 0 on success, -1 on failure
+ *
+ * This command can be used to offload ACS to the driver if the driver
+ * indicates support for such offloading (WPA_DRIVER_FLAGS_ACS_OFFLOAD).
+ */
+ int (*do_acs)(void *priv, struct drv_acs_params *params);
};
@@ -3211,11 +3544,6 @@
EVENT_ASSOC_TIMED_OUT,
/**
- * EVENT_FT_RRB_RX - FT (IEEE 802.11r) RRB frame received
- */
- EVENT_FT_RRB_RX,
-
- /**
* EVENT_WPS_BUTTON_PUSHED - Report hardware push button press for WPS
*/
EVENT_WPS_BUTTON_PUSHED,
@@ -3255,13 +3583,6 @@
EVENT_CANCEL_REMAIN_ON_CHANNEL,
/**
- * EVENT_MLME_RX - Report reception of frame for MLME (test use only)
- *
- * This event is used only by driver_test.c and userspace MLME.
- */
- EVENT_MLME_RX,
-
- /**
* EVENT_RX_PROBE_REQ - Indicate received Probe Request frame
*
* This event is used to indicate when a Probe Request frame has been
@@ -3289,9 +3610,7 @@
* EVENT_EAPOL_RX - Report received EAPOL frame
*
* When in AP mode with hostapd, this event is required to be used to
- * deliver the receive EAPOL frames from the driver. With
- * %wpa_supplicant, this event is used only if the send_eapol() handler
- * is used to override the use of l2_packet for EAPOL frame TX.
+ * deliver the receive EAPOL frames from the driver.
*/
EVENT_EAPOL_RX,
@@ -3498,7 +3817,20 @@
* to reduce issues due to interference or internal co-existence
* information in the driver.
*/
- EVENT_AVOID_FREQUENCIES
+ EVENT_AVOID_FREQUENCIES,
+
+ /**
+ * EVENT_NEW_PEER_CANDIDATE - new (unknown) mesh peer notification
+ */
+ EVENT_NEW_PEER_CANDIDATE,
+
+ /**
+ * EVENT_ACS_CHANNEL_SELECTED - Received selected channels by ACS
+ *
+ * Indicates a pair of primary and secondary channels chosen by ACS
+ * in device.
+ */
+ EVENT_ACS_CHANNEL_SELECTED,
};
@@ -3618,9 +3950,62 @@
unsigned int freq;
/**
+ * wmm_params - WMM parameters used in this association.
+ */
+ struct wmm_params wmm_params;
+
+ /**
* addr - Station address (for AP mode)
*/
const u8 *addr;
+
+ /**
+ * The following is the key management offload information
+ * @authorized
+ * @key_replay_ctr
+ * @key_replay_ctr_len
+ * @ptk_kck
+ * @ptk_kek_len
+ * @ptk_kek
+ * @ptk_kek_len
+ */
+
+ /**
+ * authorized - Status of key management offload,
+ * 1 = successful
+ */
+ int authorized;
+
+ /**
+ * key_replay_ctr - Key replay counter value last used
+ * in a valid EAPOL-Key frame
+ */
+ const u8 *key_replay_ctr;
+
+ /**
+ * key_replay_ctr_len - The length of key_replay_ctr
+ */
+ size_t key_replay_ctr_len;
+
+ /**
+ * ptk_kck - The derived PTK KCK
+ */
+ const u8 *ptk_kck;
+
+ /**
+ * ptk_kek_len - The length of ptk_kck
+ */
+ size_t ptk_kck_len;
+
+ /**
+ * ptk_kek - The derived PTK KEK
+ */
+ const u8 *ptk_kek;
+
+ /**
+ * ptk_kek_len - The length of ptk_kek
+ */
+ size_t ptk_kek_len;
} assoc_info;
/**
@@ -3830,15 +4215,6 @@
} timeout_event;
/**
- * struct ft_rrb_rx - Data for EVENT_FT_RRB_RX events
- */
- struct ft_rrb_rx {
- const u8 *src;
- const u8 *data;
- size_t data_len;
- } ft_rrb_rx;
-
- /**
* struct tx_status - Data for EVENT_TX_STATUS events
*/
struct tx_status {
@@ -3922,17 +4298,6 @@
} scan_info;
/**
- * struct mlme_rx - Data for EVENT_MLME_RX events
- */
- struct mlme_rx {
- const u8 *buf;
- size_t len;
- int freq;
- int channel;
- int ssi;
- } mlme_rx;
-
- /**
* struct rx_probe_req - Data for EVENT_RX_PROBE_REQ events
*/
struct rx_probe_req {
@@ -4112,7 +4477,7 @@
* survey_results - Survey result data for EVENT_SURVEY
* @freq_filter: Requested frequency survey filter, 0 if request
* was for all survey data
- * @survey_list: Linked list of survey data
+ * @survey_list: Linked list of survey data (struct freq_survey)
*/
struct survey_results {
unsigned int freq_filter;
@@ -4137,6 +4502,31 @@
* This is used as the data with EVENT_AVOID_FREQUENCIES.
*/
struct wpa_freq_range_list freq_range;
+
+ /**
+ * struct mesh_peer
+ *
+ * @peer: Peer address
+ * @ies: Beacon IEs
+ * @ie_len: Length of @ies
+ *
+ * Notification of new candidate mesh peer.
+ */
+ struct mesh_peer {
+ const u8 *peer;
+ const u8 *ies;
+ size_t ie_len;
+ } mesh_peer;
+
+ /**
+ * struct acs_selected_channels - Data for EVENT_ACS_CHANNEL_SELECTED
+ * @pri_channel: Selected primary channel
+ * @sec_channel: Selected secondary channel
+ */
+ struct acs_selected_channels {
+ u8 pri_channel;
+ u8 sec_channel;
+ } acs_selected_channels;
};
/**
@@ -4198,6 +4588,13 @@
/* Convert chan_width to a string for logging and control interfaces */
const char * channel_width_to_string(enum chan_width width);
+int ht_supported(const struct hostapd_hw_modes *mode);
+int vht_supported(const struct hostapd_hw_modes *mode);
+
+struct wowlan_triggers *
+wpa_get_wowlan_triggers(const char *wowlan_triggers,
+ const struct wpa_driver_capa *capa);
+
/* NULL terminated array of linked in driver wrappers */
extern struct wpa_driver_ops *wpa_drivers[];
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index b569a0a..350d505 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -224,10 +224,10 @@
memcpy(iwr.u.name+sizeof(__u32), &arg, sizeof(arg));
if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) {
- perror("ioctl[IEEE80211_IOCTL_SETPARAM]");
- wpa_printf(MSG_DEBUG, "%s: %s: Failed to set parameter (op %d "
- "(%s) arg %d)", __func__, drv->iface, op,
- athr_get_param_name(op), arg);
+ wpa_printf(MSG_INFO,
+ "%s: %s: Failed to set parameter (op %d (%s) arg %d): ioctl[IEEE80211_IOCTL_SETPARAM]: %s",
+ __func__, drv->iface, op, athr_get_param_name(op),
+ arg, strerror(errno));
return -1;
}
return 0;
@@ -290,14 +290,15 @@
}
wpa_printf(MSG_DEBUG, "%s: group key cipher=%d", __func__, v);
if (set80211param(drv, IEEE80211_PARAM_MCASTCIPHER, v)) {
- printf("Unable to set group key cipher to %u\n", v);
+ wpa_printf(MSG_INFO, "Unable to set group key cipher to %u", v);
return -1;
}
if (v == IEEE80211_CIPHER_WEP) {
/* key length is done only for specific ciphers */
v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5);
if (set80211param(drv, IEEE80211_PARAM_MCASTKEYLEN, v)) {
- printf("Unable to set group key length to %u\n", v);
+ wpa_printf(MSG_INFO,
+ "Unable to set group key length to %u", v);
return -1;
}
}
@@ -319,7 +320,8 @@
v |= 1<<IEEE80211_CIPHER_NONE;
wpa_printf(MSG_DEBUG, "%s: pairwise key ciphers=0x%x", __func__, v);
if (set80211param(drv, IEEE80211_PARAM_UCASTCIPHERS, v)) {
- printf("Unable to set pairwise key ciphers to 0x%x\n", v);
+ wpa_printf(MSG_INFO,
+ "Unable to set pairwise key ciphers to 0x%x", v);
return -1;
}
@@ -327,8 +329,9 @@
__func__, params->wpa_key_mgmt);
if (set80211param(drv, IEEE80211_PARAM_KEYMGTALGS,
params->wpa_key_mgmt)) {
- printf("Unable to set key management algorithms to 0x%x\n",
- params->wpa_key_mgmt);
+ wpa_printf(MSG_INFO,
+ "Unable to set key management algorithms to 0x%x",
+ params->wpa_key_mgmt);
return -1;
}
@@ -345,13 +348,14 @@
wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x", __func__, v);
if (set80211param(drv, IEEE80211_PARAM_RSNCAPS, v)) {
- printf("Unable to set RSN capabilities to 0x%x\n", v);
+ wpa_printf(MSG_INFO, "Unable to set RSN capabilities to 0x%x",
+ v);
return -1;
}
wpa_printf(MSG_DEBUG, "%s: enable WPA=0x%x", __func__, params->wpa);
if (set80211param(drv, IEEE80211_PARAM_WPA, params->wpa)) {
- printf("Unable to set WPA to %u\n", params->wpa);
+ wpa_printf(MSG_INFO, "Unable to set WPA to %u", params->wpa);
return -1;
}
return 0;
@@ -518,14 +522,14 @@
#endif /* ATH_GCM_SUPPORT */
#endif /* CONFIG_IEEE80211W */
default:
- printf("%s: unknown/unsupported algorithm %d\n",
- __func__, alg);
+ wpa_printf(MSG_INFO, "%s: unknown/unsupported algorithm %d",
+ __func__, alg);
return -1;
}
if (key_len > sizeof(wk.ik_keydata)) {
- printf("%s: key length %lu too big\n", __func__,
- (unsigned long) key_len);
+ wpa_printf(MSG_INFO, "%s: key length %lu too big", __func__,
+ (unsigned long) key_len);
return -3;
}
@@ -636,7 +640,8 @@
return 0;
}
- printf("Failed to get station stats information element.\n");
+ wpa_printf(MSG_INFO,
+ "Failed to get station stats information element");
return -1;
}
@@ -769,145 +774,6 @@
return ret;
}
-#ifdef CONFIG_WPS
-static void atheros_raw_recv_wps(void *ctx, const u8 *src_addr, const u8 *buf,
- size_t len)
-{
- struct atheros_driver_data *drv = ctx;
- const struct ieee80211_mgmt *mgmt;
- u16 fc;
- union wpa_event_data event;
-
- /* Send Probe Request information to WPS processing */
-
- if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
- return;
- mgmt = (const struct ieee80211_mgmt *) buf;
-
- fc = le_to_host16(mgmt->frame_control);
- if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT ||
- WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_PROBE_REQ)
- return;
-
- os_memset(&event, 0, sizeof(event));
- event.rx_probe_req.sa = mgmt->sa;
- event.rx_probe_req.da = mgmt->da;
- event.rx_probe_req.bssid = mgmt->bssid;
- event.rx_probe_req.ie = mgmt->u.probe_req.variable;
- event.rx_probe_req.ie_len =
- len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
- wpa_supplicant_event(drv->hapd, EVENT_RX_PROBE_REQ, &event);
-}
-#endif /* CONFIG_WPS */
-
-#ifdef CONFIG_IEEE80211R
-static void atheros_raw_recv_11r(void *ctx, const u8 *src_addr, const u8 *buf,
- size_t len)
-{
- struct atheros_driver_data *drv = ctx;
- union wpa_event_data event;
- const struct ieee80211_mgmt *mgmt;
- u16 fc;
- u16 stype;
- int ielen;
- const u8 *iebuf;
-
- /* Do 11R processing for ASSOC/AUTH/FT ACTION frames */
- if (len < IEEE80211_HDRLEN)
- return;
- mgmt = (const struct ieee80211_mgmt *) buf;
-
- fc = le_to_host16(mgmt->frame_control);
-
- if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT)
- return;
- stype = WLAN_FC_GET_STYPE(fc);
-
- wpa_printf(MSG_DEBUG, "%s: subtype 0x%x len %d", __func__, stype,
- (int) len);
-
- if (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) != 0) {
- wpa_printf(MSG_DEBUG, "%s: BSSID does not match - ignore",
- __func__);
- return;
- }
- switch (stype) {
- case WLAN_FC_STYPE_ASSOC_REQ:
- if (len - IEEE80211_HDRLEN < sizeof(mgmt->u.assoc_req))
- break;
- ielen = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req));
- iebuf = mgmt->u.assoc_req.variable;
- drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 0);
- break;
- case WLAN_FC_STYPE_REASSOC_REQ:
- if (len - IEEE80211_HDRLEN < sizeof(mgmt->u.reassoc_req))
- break;
- ielen = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req));
- iebuf = mgmt->u.reassoc_req.variable;
- drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 1);
- break;
- case WLAN_FC_STYPE_ACTION:
- os_memset(&event, 0, sizeof(event));
- event.rx_mgmt.frame = buf;
- event.rx_mgmt.frame_len = len;
- wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event);
- break;
- case WLAN_FC_STYPE_AUTH:
- if (len - IEEE80211_HDRLEN < sizeof(mgmt->u.auth))
- break;
- os_memset(&event, 0, sizeof(event));
- os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN);
- os_memcpy(event.auth.bssid, mgmt->bssid, ETH_ALEN);
- event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg);
- event.auth.status_code =
- le_to_host16(mgmt->u.auth.status_code);
- event.auth.auth_transaction =
- le_to_host16(mgmt->u.auth.auth_transaction);
- event.auth.ies = mgmt->u.auth.variable;
- event.auth.ies_len = len - IEEE80211_HDRLEN -
- sizeof(mgmt->u.auth);
- wpa_supplicant_event(drv->hapd, EVENT_AUTH, &event);
- break;
- default:
- break;
- }
-}
-#endif /* CONFIG_IEEE80211R */
-
-#ifdef CONFIG_HS20
-static void atheros_raw_recv_hs20(void *ctx, const u8 *src_addr, const u8 *buf,
- size_t len)
-{
- struct atheros_driver_data *drv = ctx;
- const struct ieee80211_mgmt *mgmt;
- u16 fc;
- union wpa_event_data event;
-
- /* Send the Action frame for HS20 processing */
-
- if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.action.category) +
- sizeof(mgmt->u.action.u.public_action))
- return;
-
- mgmt = (const struct ieee80211_mgmt *) buf;
-
- fc = le_to_host16(mgmt->frame_control);
- if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT ||
- WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION ||
- mgmt->u.action.category != WLAN_ACTION_PUBLIC)
- return;
-
- wpa_printf(MSG_DEBUG, "%s:Received Public Action frame", __func__);
-
- os_memset(&event, 0, sizeof(event));
- event.rx_mgmt.frame = (const u8 *) mgmt;
- event.rx_mgmt.frame_len = len;
- wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event);
-}
-
-#endif /* CONFIG_HS20 */
-
-
static int atheros_set_qos_map(void *ctx, const u8 *qos_map_set,
u8 qos_map_set_len)
{
@@ -947,9 +813,9 @@
}
if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_DBGREQ, &iwr) < 0) {
- perror("ioctl[IEEE80211_IOCTL_DBGREQ]");
- wpa_printf(MSG_DEBUG, "%s: %s: Failed to set QoS Map",
- __func__, drv->iface);
+ wpa_printf(MSG_ERROR,
+ "%s: %s: Failed to set QoS Map: ioctl[IEEE80211_IOCTL_DBGREQ]: %s",
+ __func__, drv->iface, strerror(errno));
return -1;
}
#endif /* CONFIG_ATHEROS_QOS_MAP */
@@ -957,30 +823,47 @@
return 0;
}
-#if defined(CONFIG_WNM) && !defined(CONFIG_IEEE80211R)
-static void atheros_raw_recv_11v(void *ctx, const u8 *src_addr, const u8 *buf,
- size_t len)
+#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) || defined(CONFIG_WNM) || defined(CONFIG_HS20)
+static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
+ size_t len)
{
struct atheros_driver_data *drv = ctx;
- union wpa_event_data event;
const struct ieee80211_mgmt *mgmt;
- u16 fc;
- u16 stype;
+ union wpa_event_data event;
+ u16 fc, stype;
+ int ielen;
+ const u8 *iebuf;
- /* Do 11R processing for WNM ACTION frames */
if (len < IEEE80211_HDRLEN)
return;
+
mgmt = (const struct ieee80211_mgmt *) buf;
fc = le_to_host16(mgmt->frame_control);
if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT)
return;
+
stype = WLAN_FC_GET_STYPE(fc);
wpa_printf(MSG_DEBUG, "%s: subtype 0x%x len %d", __func__, stype,
(int) len);
+ if (stype == WLAN_FC_STYPE_PROBE_REQ) {
+ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
+ return;
+
+ os_memset(&event, 0, sizeof(event));
+ event.rx_probe_req.sa = mgmt->sa;
+ event.rx_probe_req.da = mgmt->da;
+ event.rx_probe_req.bssid = mgmt->bssid;
+ event.rx_probe_req.ie = mgmt->u.probe_req.variable;
+ event.rx_probe_req.ie_len =
+ len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
+ wpa_supplicant_event(drv->hapd, EVENT_RX_PROBE_REQ, &event);
+ return;
+ }
+
if (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) != 0) {
wpa_printf(MSG_DEBUG, "%s: BSSID does not match - ignore",
__func__);
@@ -988,36 +871,47 @@
}
switch (stype) {
+ case WLAN_FC_STYPE_ASSOC_REQ:
+ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req))
+ break;
+ ielen = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req));
+ iebuf = mgmt->u.assoc_req.variable;
+ drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 0);
+ break;
+ case WLAN_FC_STYPE_REASSOC_REQ:
+ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req))
+ break;
+ ielen = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req));
+ iebuf = mgmt->u.reassoc_req.variable;
+ drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 1);
+ break;
case WLAN_FC_STYPE_ACTION:
os_memset(&event, 0, sizeof(event));
event.rx_mgmt.frame = buf;
event.rx_mgmt.frame_len = len;
wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event);
break;
+ case WLAN_FC_STYPE_AUTH:
+ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth))
+ break;
+ os_memset(&event, 0, sizeof(event));
+ os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN);
+ os_memcpy(event.auth.bssid, mgmt->bssid, ETH_ALEN);
+ event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg);
+ event.auth.status_code =
+ le_to_host16(mgmt->u.auth.status_code);
+ event.auth.auth_transaction =
+ le_to_host16(mgmt->u.auth.auth_transaction);
+ event.auth.ies = mgmt->u.auth.variable;
+ event.auth.ies_len = len - IEEE80211_HDRLEN -
+ sizeof(mgmt->u.auth);
+ wpa_supplicant_event(drv->hapd, EVENT_AUTH, &event);
+ break;
default:
break;
}
}
-#endif /* CONFIG_WNM */
-
-#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) || defined(CONFIG_WNM)
-static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
- size_t len)
-{
-#ifdef CONFIG_WPS
- atheros_raw_recv_wps(ctx, src_addr, buf, len);
-#endif /* CONFIG_WPS */
-#ifdef CONFIG_IEEE80211R
- atheros_raw_recv_11r(ctx, src_addr, buf, len);
-#endif /* CONFIG_IEEE80211R */
-#if defined(CONFIG_WNM) && !defined(CONFIG_IEEE80211R)
- atheros_raw_recv_11v(ctx, src_addr, buf, len);
-#endif /* CONFIG_WNM */
-#ifdef CONFIG_HS20
- atheros_raw_recv_hs20(ctx, src_addr, buf, len);
-#endif /* CONFIG_HS20 */
-}
-#endif /* CONFIG_WPS || CONFIG_IEEE80211R */
+#endif
static int atheros_receive_pkt(struct atheros_driver_data *drv)
{
@@ -1606,8 +1500,9 @@
sizeof(range->enc_capa);
if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
- perror("ioctl[SIOCGIWRANGE]");
- free(range);
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWRANGE]: %s",
+ strerror(errno));
+ os_free(range);
return -1;
} else if (iwr.u.data.length >= minlen &&
range->we_version_compiled >= 18) {
@@ -1667,8 +1562,9 @@
if (len > sizeof(buf)) {
bp = malloc(len);
if (bp == NULL) {
- printf("EAPOL frame discarded, cannot malloc temp "
- "buffer of size %lu!\n", (unsigned long) len);
+ wpa_printf(MSG_INFO,
+ "EAPOL frame discarded, cannot malloc temp buffer of size %lu!",
+ (unsigned long) len);
return -1;
}
}
@@ -1705,14 +1601,16 @@
drv = os_zalloc(sizeof(struct atheros_driver_data));
if (drv == NULL) {
- printf("Could not allocate memory for atheros driver data\n");
+ wpa_printf(MSG_INFO,
+ "Could not allocate memory for atheros driver data");
return NULL;
}
drv->hapd = hapd;
drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
if (drv->ioctl_sock < 0) {
- perror("socket[PF_INET,SOCK_DGRAM]");
+ wpa_printf(MSG_ERROR, "socket[PF_INET,SOCK_DGRAM]: %s",
+ strerror(errno));
goto bad;
}
memcpy(drv->iface, params->ifname, sizeof(drv->iface));
@@ -1720,7 +1618,8 @@
memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name));
if (ioctl(drv->ioctl_sock, SIOCGIFINDEX, &ifr) != 0) {
- perror("ioctl(SIOCGIFINDEX)");
+ wpa_printf(MSG_ERROR, "ioctl(SIOCGIFINDEX): %s",
+ strerror(errno));
goto bad;
}
drv->ifindex = ifr.ifr_ifindex;
@@ -1756,8 +1655,9 @@
iwr.u.mode = IW_MODE_MASTER;
if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) {
- perror("ioctl[SIOCSIWMODE]");
- printf("Could not set interface to master mode!\n");
+ wpa_printf(MSG_ERROR,
+ "Could not set interface to master mode! ioctl[SIOCSIWMODE]: %s",
+ strerror(errno));
goto bad;
}
@@ -1823,8 +1723,8 @@
iwr.u.essid.length = len + 1;
if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
- perror("ioctl[SIOCSIWESSID]");
- printf("len=%d\n", len);
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWESSID,len=%d]: %s",
+ len, strerror(errno));
return -1;
}
return 0;
@@ -1844,7 +1744,8 @@
IW_ESSID_MAX_SIZE : len;
if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
- perror("ioctl[SIOCGIWESSID]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWESSID]: %s",
+ strerror(errno));
ret = -1;
} else
ret = iwr.u.essid.length;
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index ca64d5c..0f1a0f6 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -264,7 +264,8 @@
os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
if (ioctl(drv->sock, SIOCGIFFLAGS, &ifr) < 0) {
- perror("ioctl[SIOCGIFFLAGS]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIFFLAGS]: %s",
+ strerror(errno));
return -1;
}
@@ -279,7 +280,8 @@
}
if (ioctl(drv->sock, SIOCSIFFLAGS, &ifr) < 0) {
- perror("ioctl[SIOCSIFFLAGS]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s",
+ strerror(errno));
return -1;
}
@@ -404,22 +406,24 @@
v = IEEE80211_CIPHER_NONE;
break;
default:
- printf("Unknown group key cipher %u\n",
- params->wpa_group);
+ wpa_printf(MSG_INFO, "Unknown group key cipher %u",
+ params->wpa_group);
return -1;
}
wpa_printf(MSG_DEBUG, "%s: group key cipher=%s (%u)",
__func__, ciphernames[v], v);
if (set80211param(priv, IEEE80211_IOC_MCASTCIPHER, v)) {
- printf("Unable to set group key cipher to %u (%s)\n",
- v, ciphernames[v]);
+ wpa_printf(MSG_INFO,
+ "Unable to set group key cipher to %u (%s)",
+ v, ciphernames[v]);
return -1;
}
if (v == IEEE80211_CIPHER_WEP) {
/* key length is done only for specific ciphers */
v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5);
if (set80211param(priv, IEEE80211_IOC_MCASTKEYLEN, v)) {
- printf("Unable to set group key length to %u\n", v);
+ wpa_printf(MSG_INFO,
+ "Unable to set group key length to %u", v);
return -1;
}
}
@@ -433,7 +437,8 @@
v |= 1<<IEEE80211_CIPHER_NONE;
wpa_printf(MSG_DEBUG, "%s: pairwise key ciphers=0x%x", __func__, v);
if (set80211param(priv, IEEE80211_IOC_UCASTCIPHERS, v)) {
- printf("Unable to set pairwise key ciphers to 0x%x\n", v);
+ wpa_printf(MSG_INFO,
+ "Unable to set pairwise key ciphers to 0x%x", v);
return -1;
}
@@ -441,8 +446,9 @@
__func__, params->wpa_key_mgmt);
if (set80211param(priv, IEEE80211_IOC_KEYMGTALGS,
params->wpa_key_mgmt)) {
- printf("Unable to set key management algorithms to 0x%x\n",
- params->wpa_key_mgmt);
+ wpa_printf(MSG_INFO,
+ "Unable to set key management algorithms to 0x%x",
+ params->wpa_key_mgmt);
return -1;
}
@@ -452,14 +458,15 @@
wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x",
__func__, params->rsn_preauth);
if (set80211param(priv, IEEE80211_IOC_RSNCAPS, v)) {
- printf("Unable to set RSN capabilities to 0x%x\n", v);
+ wpa_printf(MSG_INFO, "Unable to set RSN capabilities to 0x%x",
+ v);
return -1;
}
#endif /* IEEE80211_IOC_APPIE */
wpa_printf(MSG_DEBUG, "%s: enable WPA= 0x%x", __func__, params->wpa);
if (set80211param(priv, IEEE80211_IOC_WPA, params->wpa)) {
- printf("Unable to set WPA to %u\n", params->wpa);
+ wpa_printf(MSG_INFO, "Unable to set WPA to %u", params->wpa);
return -1;
}
return 0;
@@ -507,7 +514,8 @@
memset(&ie, 0, sizeof(ie));
memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN);
if (get80211var(priv, IEEE80211_IOC_WPAIE, &ie, sizeof(ie)) < 0) {
- printf("Failed to get WPA/RSN information element.\n");
+ wpa_printf(MSG_INFO,
+ "Failed to get WPA/RSN information element");
goto no_ie;
}
iebuf = ie.wpa_ie;
@@ -594,7 +602,7 @@
int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET, NET_RT_DUMP, 0};
if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
- wpa_printf(MSG_WARNING, "%s failed: %s\n", __func__,
+ wpa_printf(MSG_WARNING, "%s failed: %s", __func__,
strerror(errno));
len = 2048;
}
@@ -652,7 +660,7 @@
wk.ik_keyix = idx;
if (get80211var(priv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)) < 0) {
- printf("Failed to get encryption.\n");
+ wpa_printf(MSG_INFO, "Failed to get encryption");
return -1;
}
@@ -734,7 +742,7 @@
n = read(sock, drv->event_buf, drv->event_buf_len);
if (n < 0) {
if (errno != EINTR && errno != EAGAIN)
- wpa_printf(MSG_ERROR, "%s read() failed: %s\n",
+ wpa_printf(MSG_ERROR, "%s read() failed: %s",
__func__, strerror(errno));
return;
}
@@ -814,7 +822,8 @@
drv->hapd = hapd;
drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
if (drv->sock < 0) {
- perror("socket[PF_INET,SOCK_DGRAM]");
+ wpa_printf(MSG_ERROR, "socket[PF_INET,SOCK_DGRAM]: %s",
+ strerror(errno));
goto bad;
}
os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname));
@@ -832,7 +841,8 @@
drv->route = socket(PF_ROUTE, SOCK_RAW, 0);
if (drv->route < 0) {
- perror("socket(PF_ROUTE,SOCK_RAW)");
+ wpa_printf(MSG_ERROR, "socket(PF_ROUTE,SOCK_RAW): %s",
+ strerror(errno));
goto bad;
}
eloop_register_read_sock(drv->route, bsd_wireless_event_receive, drv,
@@ -1189,7 +1199,7 @@
n = read(sock, drv->event_buf, drv->event_buf_len);
if (n < 0) {
if (errno != EINTR && errno != EAGAIN)
- wpa_printf(MSG_ERROR, "%s read() failed: %s\n",
+ wpa_printf(MSG_ERROR, "%s read() failed: %s",
__func__, strerror(errno));
return;
}
@@ -1334,7 +1344,12 @@
*pos++ = 1;
*pos++ = sr->isr_erp;
+#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+ os_memcpy(pos, (u8 *)(sr + 1) + sr->isr_ssid_len + sr->isr_meshid_len,
+ sr->isr_ie_len);
+#else
os_memcpy(pos, (u8 *)(sr + 1) + sr->isr_ssid_len, sr->isr_ie_len);
+#endif
pos += sr->isr_ie_len;
result->ie_len = pos - (u8 *)(result + 1);
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index 77e6905..f897c11 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -44,14 +44,12 @@
E2S(ASSOC_REJECT);
E2S(AUTH_TIMED_OUT);
E2S(ASSOC_TIMED_OUT);
- E2S(FT_RRB_RX);
E2S(WPS_BUTTON_PUSHED);
E2S(TX_STATUS);
E2S(RX_FROM_UNKNOWN);
E2S(RX_MGMT);
E2S(REMAIN_ON_CHANNEL);
E2S(CANCEL_REMAIN_ON_CHANNEL);
- E2S(MLME_RX);
E2S(RX_PROBE_REQ);
E2S(NEW_STA);
E2S(EAPOL_RX);
@@ -79,6 +77,8 @@
E2S(SURVEY);
E2S(SCAN_STARTED);
E2S(AVOID_FREQUENCIES);
+ E2S(NEW_PEER_CANDIDATE);
+ E2S(ACS_CHANNEL_SELECTED);
}
return "UNKNOWN";
@@ -105,3 +105,115 @@
return "unknown";
}
}
+
+
+int ht_supported(const struct hostapd_hw_modes *mode)
+{
+ if (!(mode->flags & HOSTAPD_MODE_FLAG_HT_INFO_KNOWN)) {
+ /*
+ * The driver did not indicate whether it supports HT. Assume
+ * it does to avoid connection issues.
+ */
+ return 1;
+ }
+
+ /*
+ * IEEE Std 802.11n-2009 20.1.1:
+ * An HT non-AP STA shall support all EQM rates for one spatial stream.
+ */
+ return mode->mcs_set[0] == 0xff;
+}
+
+
+int vht_supported(const struct hostapd_hw_modes *mode)
+{
+ if (!(mode->flags & HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN)) {
+ /*
+ * The driver did not indicate whether it supports VHT. Assume
+ * it does to avoid connection issues.
+ */
+ return 1;
+ }
+
+ /*
+ * A VHT non-AP STA shall support MCS 0-7 for one spatial stream.
+ * TODO: Verify if this complies with the standard
+ */
+ return (mode->vht_mcs_set[0] & 0x3) != 3;
+}
+
+
+static int wpa_check_wowlan_trigger(const char *start, const char *trigger,
+ int capa_trigger, u8 *param_trigger)
+{
+ if (os_strcmp(start, trigger) != 0)
+ return 0;
+ if (!capa_trigger)
+ return 0;
+
+ *param_trigger = 1;
+ return 1;
+}
+
+
+struct wowlan_triggers *
+wpa_get_wowlan_triggers(const char *wowlan_triggers,
+ const struct wpa_driver_capa *capa)
+{
+ struct wowlan_triggers *triggers;
+ char *start, *end, *buf;
+ int last;
+
+ if (!wowlan_triggers)
+ return NULL;
+
+ buf = os_strdup(wowlan_triggers);
+ if (buf == NULL)
+ return NULL;
+
+ triggers = os_zalloc(sizeof(*triggers));
+ if (triggers == NULL)
+ goto out;
+
+#define CHECK_TRIGGER(trigger) \
+ wpa_check_wowlan_trigger(start, #trigger, \
+ capa->wowlan_triggers.trigger, \
+ &triggers->trigger)
+
+ start = buf;
+ while (*start != '\0') {
+ while (isblank(*start))
+ start++;
+ if (*start == '\0')
+ break;
+ end = start;
+ while (!isblank(*end) && *end != '\0')
+ end++;
+ last = *end == '\0';
+ *end = '\0';
+
+ if (!CHECK_TRIGGER(any) &&
+ !CHECK_TRIGGER(disconnect) &&
+ !CHECK_TRIGGER(magic_pkt) &&
+ !CHECK_TRIGGER(gtk_rekey_failure) &&
+ !CHECK_TRIGGER(eap_identity_req) &&
+ !CHECK_TRIGGER(four_way_handshake) &&
+ !CHECK_TRIGGER(rfkill_release)) {
+ wpa_printf(MSG_DEBUG,
+ "Unknown/unsupported wowlan trigger '%s'",
+ start);
+ os_free(triggers);
+ triggers = NULL;
+ goto out;
+ }
+
+ if (last)
+ break;
+ start = end + 1;
+ }
+#undef CHECK_TRIGGER
+
+out:
+ os_free(buf);
+ return triggers;
+}
diff --git a/src/drivers/driver_hostap.c b/src/drivers/driver_hostap.c
index 16f5563..84b98fb 100644
--- a/src/drivers/driver_hostap.c
+++ b/src/drivers/driver_hostap.c
@@ -214,7 +214,7 @@
len = recv(sock, buf, sizeof(buf), 0);
if (len < 0) {
- perror("recv");
+ wpa_printf(MSG_ERROR, "recv: %s", strerror(errno));
return;
}
@@ -229,19 +229,21 @@
drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (drv->sock < 0) {
- perror("socket[PF_PACKET,SOCK_RAW]");
+ wpa_printf(MSG_ERROR, "socket[PF_PACKET,SOCK_RAW]: %s",
+ strerror(errno));
return -1;
}
if (eloop_register_read_sock(drv->sock, handle_read, drv, NULL)) {
- printf("Could not register read socket\n");
+ wpa_printf(MSG_ERROR, "Could not register read socket");
return -1;
}
memset(&ifr, 0, sizeof(ifr));
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%sap", drv->iface);
if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) {
- perror("ioctl(SIOCGIFINDEX)");
+ wpa_printf(MSG_ERROR, "ioctl(SIOCGIFINDEX): %s",
+ strerror(errno));
return -1;
}
@@ -256,7 +258,7 @@
addr.sll_ifindex);
if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("bind");
+ wpa_printf(MSG_ERROR, "bind: %s", strerror(errno));
return -1;
}
@@ -361,9 +363,9 @@
os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
ifr.ifr_mtu = HOSTAPD_MTU;
if (ioctl(drv->ioctl_sock, SIOCSIFMTU, &ifr) != 0) {
- perror("ioctl[SIOCSIFMTU]");
- printf("Setting MTU failed - trying to survive with "
- "current value\n");
+ wpa_printf(MSG_INFO,
+ "Setting MTU failed - trying to survive with current value: ioctl[SIOCSIFMTU]: %s",
+ strerror(errno));
}
}
@@ -383,7 +385,8 @@
iwr.u.data.length = len;
if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_HOSTAPD, &iwr) < 0) {
- perror("ioctl[PRISM2_IOCTL_HOSTAPD]");
+ wpa_printf(MSG_ERROR, "ioctl[PRISM2_IOCTL_HOSTAPD]: %s",
+ strerror(errno));
return -1;
}
@@ -497,7 +500,8 @@
*i++ = value;
if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_PRISM2_PARAM, &iwr) < 0) {
- perror("ioctl[PRISM2_IOCTL_PRISM2_PARAM]");
+ wpa_printf(MSG_ERROR, "ioctl[PRISM2_IOCTL_PRISM2_PARAM]: %s",
+ strerror(errno));
return -1;
}
@@ -554,8 +558,8 @@
iwr.u.essid.length = len + 1;
if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
- perror("ioctl[SIOCSIWESSID]");
- printf("len=%d\n", len);
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWESSID,len=%d]: %s",
+ len, strerror(errno));
return -1;
}
@@ -919,8 +923,9 @@
sizeof(range->enc_capa);
if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
- perror("ioctl[SIOCGIWRANGE]");
- free(range);
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWRANGE]: %s",
+ strerror(errno));
+ os_free(range);
return -1;
} else if (iwr.u.data.length >= minlen &&
range->we_version_compiled >= 18) {
@@ -975,23 +980,25 @@
drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
if (drv->ioctl_sock < 0) {
- perror("socket[PF_INET,SOCK_DGRAM]");
- free(drv);
+ wpa_printf(MSG_ERROR, "socket[PF_INET,SOCK_DGRAM]: %s",
+ strerror(errno));
+ os_free(drv);
return NULL;
}
if (hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD, 1)) {
- printf("Could not enable hostapd mode for interface %s\n",
- drv->iface);
+ wpa_printf(MSG_ERROR,
+ "Could not enable hostapd mode for interface %s",
+ drv->iface);
close(drv->ioctl_sock);
- free(drv);
+ os_free(drv);
return NULL;
}
if (hostap_init_sockets(drv, params->own_addr) ||
hostap_wireless_event_init(drv)) {
close(drv->ioctl_sock);
- free(drv);
+ os_free(drv);
return NULL;
}
@@ -1060,7 +1067,8 @@
iwr.u.freq.e = 0;
if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) {
- perror("ioctl[SIOCSIWFREQ]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWFREQ]: %s",
+ strerror(errno));
return -1;
}
diff --git a/src/drivers/driver_macsec_qca.c b/src/drivers/driver_macsec_qca.c
index cf24799..3eae2f8 100644
--- a/src/drivers/driver_macsec_qca.c
+++ b/src/drivers/driver_macsec_qca.c
@@ -91,7 +91,7 @@
if (setsockopt(sock, SOL_PACKET,
add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP,
&mreq, sizeof(mreq)) < 0) {
- perror("setsockopt");
+ wpa_printf(MSG_ERROR, "setsockopt: %s", strerror(errno));
return -1;
}
return 0;
@@ -131,14 +131,15 @@
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s < 0) {
- perror("socket");
+ wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
return -1;
}
os_memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
- perror("ioctl[SIOCGIFFLAGS]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIFFLAGS]: %s",
+ strerror(errno));
close(s);
return -1;
}
@@ -155,7 +156,7 @@
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s < 0) {
- perror("socket");
+ wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
return -1;
}
@@ -163,7 +164,8 @@
os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
ifr.ifr_flags = flags & 0xffff;
if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
- perror("ioctl[SIOCSIFFLAGS]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s",
+ strerror(errno));
close(s);
return -1;
}
@@ -180,14 +182,15 @@
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s < 0) {
- perror("socket");
+ wpa_print(MSG_ERROR, "socket: %s", strerror(errno));
return -1;
}
os_memset(&ifmr, 0, sizeof(ifmr));
os_strlcpy(ifmr.ifm_name, ifname, IFNAMSIZ);
if (ioctl(s, SIOCGIFMEDIA, (caddr_t) &ifmr) < 0) {
- perror("ioctl[SIOCGIFMEDIA]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIFMEDIA]: %s",
+ strerror(errno));
close(s);
return -1;
}
@@ -211,7 +214,7 @@
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s < 0) {
- perror("socket");
+ wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
return -1;
}
@@ -245,7 +248,8 @@
#endif /* defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) */
if (ioctl(s, add ? SIOCADDMULTI : SIOCDELMULTI, (caddr_t) &ifr) < 0) {
- perror("ioctl[SIOC{ADD/DEL}MULTI]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOC{ADD/DEL}MULTI]: %s",
+ strerror(errno));
close(s);
return -1;
}
@@ -323,7 +327,7 @@
#ifdef __linux__
drv->pf_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
if (drv->pf_sock < 0)
- perror("socket(PF_PACKET)");
+ wpa_printf(MSG_ERROR, "socket(PF_PACKET): %s", strerror(errno));
#else /* __linux__ */
drv->pf_sock = -1;
#endif /* __linux__ */
diff --git a/src/drivers/driver_madwifi.c b/src/drivers/driver_madwifi.c
deleted file mode 100644
index 1635c1f..0000000
--- a/src/drivers/driver_madwifi.c
+++ /dev/null
@@ -1,1309 +0,0 @@
-/*
- * hostapd - driver interaction with MADWIFI 802.11 driver
- * Copyright (c) 2004, Sam Leffler <sam@errno.com>
- * Copyright (c) 2004, Video54 Technologies
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- *
- * This driver wrapper is only for hostapd AP mode functionality. Station
- * (wpa_supplicant) operations with madwifi are supported by the driver_wext.c
- * wrapper.
- */
-
-#include "includes.h"
-#include <sys/ioctl.h>
-
-#include "common.h"
-#include "driver.h"
-#include "driver_wext.h"
-#include "eloop.h"
-#include "common/ieee802_11_defs.h"
-#include "linux_wext.h"
-
-/*
- * Avoid conflicts with wpa_supplicant definitions by undefining a definition.
- */
-#undef WME_OUI_TYPE
-
-#include <include/compat.h>
-#include <net80211/ieee80211.h>
-#ifdef WME_NUM_AC
-/* Assume this is built against BSD branch of madwifi driver. */
-#define MADWIFI_BSD
-#include <net80211/_ieee80211.h>
-#endif /* WME_NUM_AC */
-#include <net80211/ieee80211_crypto.h>
-#include <net80211/ieee80211_ioctl.h>
-
-#ifdef CONFIG_WPS
-#ifdef IEEE80211_IOCTL_FILTERFRAME
-#include <netpacket/packet.h>
-
-#ifndef ETH_P_80211_RAW
-#define ETH_P_80211_RAW 0x0019
-#endif
-#endif /* IEEE80211_IOCTL_FILTERFRAME */
-#endif /* CONFIG_WPS */
-
-/*
- * Avoid conflicts with hostapd definitions by undefining couple of defines
- * from madwifi header files.
- */
-#undef RSN_VERSION
-#undef WPA_VERSION
-#undef WPA_OUI_TYPE
-#undef WME_OUI_TYPE
-
-
-#ifdef IEEE80211_IOCTL_SETWMMPARAMS
-/* Assume this is built against madwifi-ng */
-#define MADWIFI_NG
-#endif /* IEEE80211_IOCTL_SETWMMPARAMS */
-
-#define WPA_KEY_RSC_LEN 8
-
-#include "priv_netlink.h"
-#include "netlink.h"
-#include "linux_ioctl.h"
-#include "l2_packet/l2_packet.h"
-
-
-struct madwifi_driver_data {
- struct hostapd_data *hapd; /* back pointer */
-
- char iface[IFNAMSIZ + 1];
- int ifindex;
- struct l2_packet_data *sock_xmit; /* raw packet xmit socket */
- struct l2_packet_data *sock_recv; /* raw packet recv socket */
- int ioctl_sock; /* socket for ioctl() use */
- struct netlink_data *netlink;
- int we_version;
- u8 acct_mac[ETH_ALEN];
- struct hostap_sta_driver_data acct_data;
-
- struct l2_packet_data *sock_raw; /* raw 802.11 management frames */
-};
-
-static int madwifi_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
- int reason_code);
-
-static int
-set80211priv(struct madwifi_driver_data *drv, int op, void *data, int len)
-{
- struct iwreq iwr;
- int do_inline = len < IFNAMSIZ;
-
- memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
-#ifdef IEEE80211_IOCTL_FILTERFRAME
- /* FILTERFRAME must be NOT inline, regardless of size. */
- if (op == IEEE80211_IOCTL_FILTERFRAME)
- do_inline = 0;
-#endif /* IEEE80211_IOCTL_FILTERFRAME */
- if (op == IEEE80211_IOCTL_SET_APPIEBUF)
- do_inline = 0;
- if (do_inline) {
- /*
- * Argument data fits inline; put it there.
- */
- memcpy(iwr.u.name, data, len);
- } else {
- /*
- * Argument data too big for inline transfer; setup a
- * parameter block instead; the kernel will transfer
- * the data for the driver.
- */
- iwr.u.data.pointer = data;
- iwr.u.data.length = len;
- }
-
- if (ioctl(drv->ioctl_sock, op, &iwr) < 0) {
-#ifdef MADWIFI_NG
- int first = IEEE80211_IOCTL_SETPARAM;
- static const char *opnames[] = {
- "ioctl[IEEE80211_IOCTL_SETPARAM]",
- "ioctl[IEEE80211_IOCTL_GETPARAM]",
- "ioctl[IEEE80211_IOCTL_SETMODE]",
- "ioctl[IEEE80211_IOCTL_GETMODE]",
- "ioctl[IEEE80211_IOCTL_SETWMMPARAMS]",
- "ioctl[IEEE80211_IOCTL_GETWMMPARAMS]",
- "ioctl[IEEE80211_IOCTL_SETCHANLIST]",
- "ioctl[IEEE80211_IOCTL_GETCHANLIST]",
- "ioctl[IEEE80211_IOCTL_CHANSWITCH]",
- "ioctl[IEEE80211_IOCTL_GET_APPIEBUF]",
- "ioctl[IEEE80211_IOCTL_SET_APPIEBUF]",
- "ioctl[IEEE80211_IOCTL_GETSCANRESULTS]",
- "ioctl[IEEE80211_IOCTL_FILTERFRAME]",
- "ioctl[IEEE80211_IOCTL_GETCHANINFO]",
- "ioctl[IEEE80211_IOCTL_SETOPTIE]",
- "ioctl[IEEE80211_IOCTL_GETOPTIE]",
- "ioctl[IEEE80211_IOCTL_SETMLME]",
- NULL,
- "ioctl[IEEE80211_IOCTL_SETKEY]",
- NULL,
- "ioctl[IEEE80211_IOCTL_DELKEY]",
- NULL,
- "ioctl[IEEE80211_IOCTL_ADDMAC]",
- NULL,
- "ioctl[IEEE80211_IOCTL_DELMAC]",
- NULL,
- "ioctl[IEEE80211_IOCTL_WDSMAC]",
- NULL,
- "ioctl[IEEE80211_IOCTL_WDSDELMAC]",
- NULL,
- "ioctl[IEEE80211_IOCTL_KICKMAC]",
- };
-#else /* MADWIFI_NG */
- int first = IEEE80211_IOCTL_SETPARAM;
- static const char *opnames[] = {
- "ioctl[IEEE80211_IOCTL_SETPARAM]",
- "ioctl[IEEE80211_IOCTL_GETPARAM]",
- "ioctl[IEEE80211_IOCTL_SETKEY]",
- "ioctl[SIOCIWFIRSTPRIV+3]",
- "ioctl[IEEE80211_IOCTL_DELKEY]",
- "ioctl[SIOCIWFIRSTPRIV+5]",
- "ioctl[IEEE80211_IOCTL_SETMLME]",
- "ioctl[SIOCIWFIRSTPRIV+7]",
- "ioctl[IEEE80211_IOCTL_SETOPTIE]",
- "ioctl[IEEE80211_IOCTL_GETOPTIE]",
- "ioctl[IEEE80211_IOCTL_ADDMAC]",
- "ioctl[SIOCIWFIRSTPRIV+11]",
- "ioctl[IEEE80211_IOCTL_DELMAC]",
- "ioctl[SIOCIWFIRSTPRIV+13]",
- "ioctl[IEEE80211_IOCTL_CHANLIST]",
- "ioctl[SIOCIWFIRSTPRIV+15]",
- "ioctl[IEEE80211_IOCTL_GETRSN]",
- "ioctl[SIOCIWFIRSTPRIV+17]",
- "ioctl[IEEE80211_IOCTL_GETKEY]",
- };
-#endif /* MADWIFI_NG */
- int idx = op - first;
- if (first <= op &&
- idx < (int) ARRAY_SIZE(opnames) &&
- opnames[idx])
- perror(opnames[idx]);
- else
- perror("ioctl[unknown???]");
- return -1;
- }
- return 0;
-}
-
-static int
-set80211param(struct madwifi_driver_data *drv, int op, int arg)
-{
- struct iwreq iwr;
-
- memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
- iwr.u.mode = op;
- memcpy(iwr.u.name+sizeof(__u32), &arg, sizeof(arg));
-
- if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) {
- perror("ioctl[IEEE80211_IOCTL_SETPARAM]");
- wpa_printf(MSG_DEBUG, "%s: Failed to set parameter (op %d "
- "arg %d)", __func__, op, arg);
- return -1;
- }
- return 0;
-}
-
-#ifndef CONFIG_NO_STDOUT_DEBUG
-static const char *
-ether_sprintf(const u8 *addr)
-{
- static char buf[sizeof(MACSTR)];
-
- if (addr != NULL)
- snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
- else
- snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0);
- return buf;
-}
-#endif /* CONFIG_NO_STDOUT_DEBUG */
-
-/*
- * Configure WPA parameters.
- */
-static int
-madwifi_configure_wpa(struct madwifi_driver_data *drv,
- struct wpa_bss_params *params)
-{
- int v;
-
- switch (params->wpa_group) {
- case WPA_CIPHER_CCMP:
- v = IEEE80211_CIPHER_AES_CCM;
- break;
- case WPA_CIPHER_TKIP:
- v = IEEE80211_CIPHER_TKIP;
- break;
- case WPA_CIPHER_WEP104:
- v = IEEE80211_CIPHER_WEP;
- break;
- case WPA_CIPHER_WEP40:
- v = IEEE80211_CIPHER_WEP;
- break;
- case WPA_CIPHER_NONE:
- v = IEEE80211_CIPHER_NONE;
- break;
- default:
- wpa_printf(MSG_ERROR, "Unknown group key cipher %u",
- params->wpa_group);
- return -1;
- }
- wpa_printf(MSG_DEBUG, "%s: group key cipher=%d", __func__, v);
- if (set80211param(drv, IEEE80211_PARAM_MCASTCIPHER, v)) {
- printf("Unable to set group key cipher to %u\n", v);
- return -1;
- }
- if (v == IEEE80211_CIPHER_WEP) {
- /* key length is done only for specific ciphers */
- v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5);
- if (set80211param(drv, IEEE80211_PARAM_MCASTKEYLEN, v)) {
- printf("Unable to set group key length to %u\n", v);
- return -1;
- }
- }
-
- v = 0;
- if (params->wpa_pairwise & WPA_CIPHER_CCMP)
- v |= 1<<IEEE80211_CIPHER_AES_CCM;
- if (params->wpa_pairwise & WPA_CIPHER_TKIP)
- v |= 1<<IEEE80211_CIPHER_TKIP;
- if (params->wpa_pairwise & WPA_CIPHER_NONE)
- v |= 1<<IEEE80211_CIPHER_NONE;
- wpa_printf(MSG_DEBUG, "%s: pairwise key ciphers=0x%x", __func__, v);
- if (set80211param(drv, IEEE80211_PARAM_UCASTCIPHERS, v)) {
- printf("Unable to set pairwise key ciphers to 0x%x\n", v);
- return -1;
- }
-
- wpa_printf(MSG_DEBUG, "%s: key management algorithms=0x%x",
- __func__, params->wpa_key_mgmt);
- if (set80211param(drv, IEEE80211_PARAM_KEYMGTALGS,
- params->wpa_key_mgmt)) {
- printf("Unable to set key management algorithms to 0x%x\n",
- params->wpa_key_mgmt);
- return -1;
- }
-
- v = 0;
- if (params->rsn_preauth)
- v |= BIT(0);
- wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x",
- __func__, params->rsn_preauth);
- if (set80211param(drv, IEEE80211_PARAM_RSNCAPS, v)) {
- printf("Unable to set RSN capabilities to 0x%x\n", v);
- return -1;
- }
-
- wpa_printf(MSG_DEBUG, "%s: enable WPA=0x%x", __func__, params->wpa);
- if (set80211param(drv, IEEE80211_PARAM_WPA, params->wpa)) {
- printf("Unable to set WPA to %u\n", params->wpa);
- return -1;
- }
- return 0;
-}
-
-static int
-madwifi_set_ieee8021x(void *priv, struct wpa_bss_params *params)
-{
- struct madwifi_driver_data *drv = priv;
-
- wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, params->enabled);
-
- if (!params->enabled) {
- /* XXX restore state */
- return set80211param(priv, IEEE80211_PARAM_AUTHMODE,
- IEEE80211_AUTH_AUTO);
- }
- if (!params->wpa && !params->ieee802_1x) {
- wpa_printf(MSG_WARNING, "No 802.1X or WPA enabled!");
- return -1;
- }
- if (params->wpa && madwifi_configure_wpa(drv, params) != 0) {
- wpa_printf(MSG_WARNING, "Error configuring WPA state!");
- return -1;
- }
- if (set80211param(priv, IEEE80211_PARAM_AUTHMODE,
- (params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) {
- wpa_printf(MSG_WARNING, "Error enabling WPA/802.1X!");
- return -1;
- }
-
- return 0;
-}
-
-static int
-madwifi_set_privacy(void *priv, int enabled)
-{
- struct madwifi_driver_data *drv = priv;
-
- wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
-
- return set80211param(drv, IEEE80211_PARAM_PRIVACY, enabled);
-}
-
-static int
-madwifi_set_sta_authorized(void *priv, const u8 *addr, int authorized)
-{
- struct madwifi_driver_data *drv = priv;
- struct ieee80211req_mlme mlme;
- int ret;
-
- wpa_printf(MSG_DEBUG, "%s: addr=%s authorized=%d",
- __func__, ether_sprintf(addr), authorized);
-
- if (authorized)
- mlme.im_op = IEEE80211_MLME_AUTHORIZE;
- else
- mlme.im_op = IEEE80211_MLME_UNAUTHORIZE;
- mlme.im_reason = 0;
- memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
- ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
- if (ret < 0) {
- wpa_printf(MSG_DEBUG, "%s: Failed to %sauthorize STA " MACSTR,
- __func__, authorized ? "" : "un", MAC2STR(addr));
- }
-
- return ret;
-}
-
-static int
-madwifi_sta_set_flags(void *priv, const u8 *addr,
- int total_flags, int flags_or, int flags_and)
-{
- /* For now, only support setting Authorized flag */
- if (flags_or & WPA_STA_AUTHORIZED)
- return madwifi_set_sta_authorized(priv, addr, 1);
- if (!(flags_and & WPA_STA_AUTHORIZED))
- return madwifi_set_sta_authorized(priv, addr, 0);
- return 0;
-}
-
-static int
-madwifi_del_key(void *priv, const u8 *addr, int key_idx)
-{
- struct madwifi_driver_data *drv = priv;
- struct ieee80211req_del_key wk;
- int ret;
-
- wpa_printf(MSG_DEBUG, "%s: addr=%s key_idx=%d",
- __func__, ether_sprintf(addr), key_idx);
-
- memset(&wk, 0, sizeof(wk));
- if (addr != NULL) {
- memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
- wk.idk_keyix = (u8) IEEE80211_KEYIX_NONE;
- } else {
- wk.idk_keyix = key_idx;
- }
-
- ret = set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk));
- if (ret < 0) {
- wpa_printf(MSG_DEBUG, "%s: Failed to delete key (addr %s"
- " key_idx %d)", __func__, ether_sprintf(addr),
- key_idx);
- }
-
- return ret;
-}
-
-static int
-wpa_driver_madwifi_set_key(const char *ifname, void *priv, enum wpa_alg alg,
- const u8 *addr, int key_idx, int set_tx,
- const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len)
-{
- struct madwifi_driver_data *drv = priv;
- struct ieee80211req_key wk;
- u_int8_t cipher;
- int ret;
-
- if (alg == WPA_ALG_NONE)
- return madwifi_del_key(drv, addr, key_idx);
-
- wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%s key_idx=%d",
- __func__, alg, ether_sprintf(addr), key_idx);
-
- if (alg == WPA_ALG_WEP)
- cipher = IEEE80211_CIPHER_WEP;
- else if (alg == WPA_ALG_TKIP)
- cipher = IEEE80211_CIPHER_TKIP;
- else if (alg == WPA_ALG_CCMP)
- cipher = IEEE80211_CIPHER_AES_CCM;
- else {
- printf("%s: unknown/unsupported algorithm %d\n",
- __func__, alg);
- return -1;
- }
-
- if (key_len > sizeof(wk.ik_keydata)) {
- printf("%s: key length %lu too big\n", __func__,
- (unsigned long) key_len);
- return -3;
- }
-
- memset(&wk, 0, sizeof(wk));
- wk.ik_type = cipher;
- wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT;
- if (addr == NULL || is_broadcast_ether_addr(addr)) {
- memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
- wk.ik_keyix = key_idx;
- wk.ik_flags |= IEEE80211_KEY_DEFAULT;
- } else {
- memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
- wk.ik_keyix = IEEE80211_KEYIX_NONE;
- }
- wk.ik_keylen = key_len;
- memcpy(wk.ik_keydata, key, key_len);
-
- ret = set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk));
- if (ret < 0) {
- wpa_printf(MSG_DEBUG, "%s: Failed to set key (addr %s"
- " key_idx %d alg %d key_len %lu set_tx %d)",
- __func__, ether_sprintf(wk.ik_macaddr), key_idx,
- alg, (unsigned long) key_len, set_tx);
- }
-
- return ret;
-}
-
-
-static int
-madwifi_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx,
- u8 *seq)
-{
- struct madwifi_driver_data *drv = priv;
- struct ieee80211req_key wk;
-
- wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d",
- __func__, ether_sprintf(addr), idx);
-
- memset(&wk, 0, sizeof(wk));
- if (addr == NULL)
- memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
- else
- memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
- wk.ik_keyix = idx;
-
- if (set80211priv(drv, IEEE80211_IOCTL_GETKEY, &wk, sizeof(wk))) {
- wpa_printf(MSG_DEBUG, "%s: Failed to get encryption data "
- "(addr " MACSTR " key_idx %d)",
- __func__, MAC2STR(wk.ik_macaddr), idx);
- return -1;
- }
-
-#ifdef WORDS_BIGENDIAN
- {
- /*
- * wk.ik_keytsc is in host byte order (big endian), need to
- * swap it to match with the byte order used in WPA.
- */
- int i;
- u8 tmp[WPA_KEY_RSC_LEN];
- memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
- for (i = 0; i < WPA_KEY_RSC_LEN; i++) {
- seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1];
- }
- }
-#else /* WORDS_BIGENDIAN */
- memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
-#endif /* WORDS_BIGENDIAN */
- return 0;
-}
-
-
-static int
-madwifi_flush(void *priv)
-{
-#ifdef MADWIFI_BSD
- u8 allsta[IEEE80211_ADDR_LEN];
- memset(allsta, 0xff, IEEE80211_ADDR_LEN);
- return madwifi_sta_deauth(priv, NULL, allsta,
- IEEE80211_REASON_AUTH_LEAVE);
-#else /* MADWIFI_BSD */
- return 0; /* XXX */
-#endif /* MADWIFI_BSD */
-}
-
-
-static int
-madwifi_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data,
- const u8 *addr)
-{
- struct madwifi_driver_data *drv = priv;
-
-#ifdef MADWIFI_BSD
- struct ieee80211req_sta_stats stats;
-
- memset(data, 0, sizeof(*data));
-
- /*
- * Fetch statistics for station from the system.
- */
- memset(&stats, 0, sizeof(stats));
- memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN);
- if (set80211priv(drv,
-#ifdef MADWIFI_NG
- IEEE80211_IOCTL_STA_STATS,
-#else /* MADWIFI_NG */
- IEEE80211_IOCTL_GETSTASTATS,
-#endif /* MADWIFI_NG */
- &stats, sizeof(stats))) {
- wpa_printf(MSG_DEBUG, "%s: Failed to fetch STA stats (addr "
- MACSTR ")", __func__, MAC2STR(addr));
- if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) {
- memcpy(data, &drv->acct_data, sizeof(*data));
- return 0;
- }
-
- printf("Failed to get station stats information element.\n");
- return -1;
- }
-
- data->rx_packets = stats.is_stats.ns_rx_data;
- data->rx_bytes = stats.is_stats.ns_rx_bytes;
- data->tx_packets = stats.is_stats.ns_tx_data;
- data->tx_bytes = stats.is_stats.ns_tx_bytes;
- return 0;
-
-#else /* MADWIFI_BSD */
-
- char buf[1024], line[128], *pos;
- FILE *f;
- unsigned long val;
-
- memset(data, 0, sizeof(*data));
- snprintf(buf, sizeof(buf), "/proc/net/madwifi/%s/" MACSTR,
- drv->iface, MAC2STR(addr));
-
- f = fopen(buf, "r");
- if (!f) {
- if (memcmp(addr, drv->acct_mac, ETH_ALEN) != 0)
- return -1;
- memcpy(data, &drv->acct_data, sizeof(*data));
- return 0;
- }
- /* Need to read proc file with in one piece, so use large enough
- * buffer. */
- setbuffer(f, buf, sizeof(buf));
-
- while (fgets(line, sizeof(line), f)) {
- pos = strchr(line, '=');
- if (!pos)
- continue;
- *pos++ = '\0';
- val = strtoul(pos, NULL, 10);
- if (strcmp(line, "rx_packets") == 0)
- data->rx_packets = val;
- else if (strcmp(line, "tx_packets") == 0)
- data->tx_packets = val;
- else if (strcmp(line, "rx_bytes") == 0)
- data->rx_bytes = val;
- else if (strcmp(line, "tx_bytes") == 0)
- data->tx_bytes = val;
- }
-
- fclose(f);
-
- return 0;
-#endif /* MADWIFI_BSD */
-}
-
-
-static int
-madwifi_sta_clear_stats(void *priv, const u8 *addr)
-{
-#if defined(MADWIFI_BSD) && defined(IEEE80211_MLME_CLEAR_STATS)
- struct madwifi_driver_data *drv = priv;
- struct ieee80211req_mlme mlme;
- int ret;
-
- wpa_printf(MSG_DEBUG, "%s: addr=%s", __func__, ether_sprintf(addr));
-
- mlme.im_op = IEEE80211_MLME_CLEAR_STATS;
- memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
- ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme,
- sizeof(mlme));
- if (ret < 0) {
- wpa_printf(MSG_DEBUG, "%s: Failed to clear STA stats (addr "
- MACSTR ")", __func__, MAC2STR(addr));
- }
-
- return ret;
-#else /* MADWIFI_BSD && IEEE80211_MLME_CLEAR_STATS */
- return 0; /* FIX */
-#endif /* MADWIFI_BSD && IEEE80211_MLME_CLEAR_STATS */
-}
-
-
-static int
-madwifi_set_opt_ie(void *priv, const u8 *ie, size_t ie_len)
-{
- /*
- * Do nothing; we setup parameters at startup that define the
- * contents of the beacon information element.
- */
- return 0;
-}
-
-static int
-madwifi_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
- int reason_code)
-{
- struct madwifi_driver_data *drv = priv;
- struct ieee80211req_mlme mlme;
- int ret;
-
- wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d",
- __func__, ether_sprintf(addr), reason_code);
-
- mlme.im_op = IEEE80211_MLME_DEAUTH;
- mlme.im_reason = reason_code;
- memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
- ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
- if (ret < 0) {
- wpa_printf(MSG_DEBUG, "%s: Failed to deauth STA (addr " MACSTR
- " reason %d)",
- __func__, MAC2STR(addr), reason_code);
- }
-
- return ret;
-}
-
-static int
-madwifi_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
- int reason_code)
-{
- struct madwifi_driver_data *drv = priv;
- struct ieee80211req_mlme mlme;
- int ret;
-
- wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d",
- __func__, ether_sprintf(addr), reason_code);
-
- mlme.im_op = IEEE80211_MLME_DISASSOC;
- mlme.im_reason = reason_code;
- memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
- ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
- if (ret < 0) {
- wpa_printf(MSG_DEBUG, "%s: Failed to disassoc STA (addr "
- MACSTR " reason %d)",
- __func__, MAC2STR(addr), reason_code);
- }
-
- return ret;
-}
-
-#ifdef CONFIG_WPS
-#ifdef IEEE80211_IOCTL_FILTERFRAME
-static void madwifi_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
- size_t len)
-{
- struct madwifi_driver_data *drv = ctx;
- const struct ieee80211_mgmt *mgmt;
- u16 fc;
- union wpa_event_data event;
-
- /* Send Probe Request information to WPS processing */
-
- if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
- return;
- mgmt = (const struct ieee80211_mgmt *) buf;
-
- fc = le_to_host16(mgmt->frame_control);
- if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT ||
- WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_PROBE_REQ)
- return;
-
- os_memset(&event, 0, sizeof(event));
- event.rx_probe_req.sa = mgmt->sa;
- event.rx_probe_req.da = mgmt->da;
- event.rx_probe_req.bssid = mgmt->bssid;
- event.rx_probe_req.ie = mgmt->u.probe_req.variable;
- event.rx_probe_req.ie_len =
- len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
- wpa_supplicant_event(drv->hapd, EVENT_RX_PROBE_REQ, &event);
-}
-#endif /* IEEE80211_IOCTL_FILTERFRAME */
-#endif /* CONFIG_WPS */
-
-static int madwifi_receive_probe_req(struct madwifi_driver_data *drv)
-{
- int ret = 0;
-#ifdef CONFIG_WPS
-#ifdef IEEE80211_IOCTL_FILTERFRAME
- struct ieee80211req_set_filter filt;
-
- wpa_printf(MSG_DEBUG, "%s Enter", __func__);
- filt.app_filterype = IEEE80211_FILTER_TYPE_PROBE_REQ;
-
- ret = set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt,
- sizeof(struct ieee80211req_set_filter));
- if (ret)
- return ret;
-
- drv->sock_raw = l2_packet_init(drv->iface, NULL, ETH_P_80211_RAW,
- madwifi_raw_receive, drv, 1);
- if (drv->sock_raw == NULL)
- return -1;
-#endif /* IEEE80211_IOCTL_FILTERFRAME */
-#endif /* CONFIG_WPS */
- return ret;
-}
-
-#ifdef CONFIG_WPS
-static int
-madwifi_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype)
-{
- struct madwifi_driver_data *drv = priv;
- u8 buf[256];
- struct ieee80211req_getset_appiebuf *beac_ie;
-
- wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__,
- (unsigned long) len);
-
- beac_ie = (struct ieee80211req_getset_appiebuf *) buf;
- beac_ie->app_frmtype = frametype;
- beac_ie->app_buflen = len;
- memcpy(&(beac_ie->app_buf[0]), ie, len);
-
- return set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, beac_ie,
- sizeof(struct ieee80211req_getset_appiebuf) + len);
-}
-
-static int
-madwifi_set_ap_wps_ie(void *priv, const struct wpabuf *beacon,
- const struct wpabuf *proberesp,
- const struct wpabuf *assocresp)
-{
- if (madwifi_set_wps_ie(priv, beacon ? wpabuf_head(beacon) : NULL,
- beacon ? wpabuf_len(beacon) : 0,
- IEEE80211_APPIE_FRAME_BEACON) < 0)
- return -1;
- return madwifi_set_wps_ie(priv,
- proberesp ? wpabuf_head(proberesp) : NULL,
- proberesp ? wpabuf_len(proberesp) : 0,
- IEEE80211_APPIE_FRAME_PROBE_RESP);
-}
-#else /* CONFIG_WPS */
-#define madwifi_set_ap_wps_ie NULL
-#endif /* CONFIG_WPS */
-
-static int madwifi_set_freq(void *priv, struct hostapd_freq_params *freq)
-{
- struct madwifi_driver_data *drv = priv;
- struct iwreq iwr;
-
- os_memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
- iwr.u.freq.m = freq->channel;
- iwr.u.freq.e = 0;
-
- if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) {
- perror("ioctl[SIOCSIWFREQ]");
- return -1;
- }
-
- return 0;
-}
-
-static void
-madwifi_new_sta(struct madwifi_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
-{
- struct hostapd_data *hapd = drv->hapd;
- struct ieee80211req_wpaie ie;
- int ielen = 0;
- u8 *iebuf = NULL;
-
- /*
- * Fetch negotiated WPA/RSN parameters from the system.
- */
- memset(&ie, 0, sizeof(ie));
- memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN);
- if (set80211priv(drv, IEEE80211_IOCTL_GETWPAIE, &ie, sizeof(ie))) {
- wpa_printf(MSG_DEBUG, "%s: Failed to get WPA/RSN IE",
- __func__);
- goto no_ie;
- }
- wpa_hexdump(MSG_MSGDUMP, "madwifi req WPA IE",
- ie.wpa_ie, IEEE80211_MAX_OPT_IE);
- iebuf = ie.wpa_ie;
- /* madwifi seems to return some random data if WPA/RSN IE is not set.
- * Assume the IE was not included if the IE type is unknown. */
- if (iebuf[0] != WLAN_EID_VENDOR_SPECIFIC)
- iebuf[1] = 0;
-#ifdef MADWIFI_NG
- wpa_hexdump(MSG_MSGDUMP, "madwifi req RSN IE",
- ie.rsn_ie, IEEE80211_MAX_OPT_IE);
- if (iebuf[1] == 0 && ie.rsn_ie[1] > 0) {
- /* madwifi-ng svn #1453 added rsn_ie. Use it, if wpa_ie was not
- * set. This is needed for WPA2. */
- iebuf = ie.rsn_ie;
- if (iebuf[0] != WLAN_EID_RSN)
- iebuf[1] = 0;
- }
-#endif /* MADWIFI_NG */
-
- ielen = iebuf[1];
- if (ielen == 0)
- iebuf = NULL;
- else
- ielen += 2;
-
-no_ie:
- drv_event_assoc(hapd, addr, iebuf, ielen, 0);
-
- if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) {
- /* Cached accounting data is not valid anymore. */
- memset(drv->acct_mac, 0, ETH_ALEN);
- memset(&drv->acct_data, 0, sizeof(drv->acct_data));
- }
-}
-
-static void
-madwifi_wireless_event_wireless_custom(struct madwifi_driver_data *drv,
- char *custom)
-{
- wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom);
-
- if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
- char *pos;
- u8 addr[ETH_ALEN];
- pos = strstr(custom, "addr=");
- if (pos == NULL) {
- wpa_printf(MSG_DEBUG,
- "MLME-MICHAELMICFAILURE.indication "
- "without sender address ignored");
- return;
- }
- pos += 5;
- if (hwaddr_aton(pos, addr) == 0) {
- union wpa_event_data data;
- os_memset(&data, 0, sizeof(data));
- data.michael_mic_failure.unicast = 1;
- data.michael_mic_failure.src = addr;
- wpa_supplicant_event(drv->hapd,
- EVENT_MICHAEL_MIC_FAILURE, &data);
- } else {
- wpa_printf(MSG_DEBUG,
- "MLME-MICHAELMICFAILURE.indication "
- "with invalid MAC address");
- }
- } else if (strncmp(custom, "STA-TRAFFIC-STAT", 16) == 0) {
- char *key, *value;
- u32 val;
- key = custom;
- while ((key = strchr(key, '\n')) != NULL) {
- key++;
- value = strchr(key, '=');
- if (value == NULL)
- continue;
- *value++ = '\0';
- val = strtoul(value, NULL, 10);
- if (strcmp(key, "mac") == 0)
- hwaddr_aton(value, drv->acct_mac);
- else if (strcmp(key, "rx_packets") == 0)
- drv->acct_data.rx_packets = val;
- else if (strcmp(key, "tx_packets") == 0)
- drv->acct_data.tx_packets = val;
- else if (strcmp(key, "rx_bytes") == 0)
- drv->acct_data.rx_bytes = val;
- else if (strcmp(key, "tx_bytes") == 0)
- drv->acct_data.tx_bytes = val;
- key = value;
- }
- }
-}
-
-static void
-madwifi_wireless_event_wireless(struct madwifi_driver_data *drv,
- char *data, int len)
-{
- struct iw_event iwe_buf, *iwe = &iwe_buf;
- char *pos, *end, *custom, *buf;
-
- pos = data;
- end = data + len;
-
- while (pos + IW_EV_LCP_LEN <= end) {
- /* Event data may be unaligned, so make a local, aligned copy
- * before processing. */
- memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
- wpa_printf(MSG_MSGDUMP, "Wireless event: cmd=0x%x len=%d",
- iwe->cmd, iwe->len);
- if (iwe->len <= IW_EV_LCP_LEN)
- return;
-
- custom = pos + IW_EV_POINT_LEN;
- if (drv->we_version > 18 &&
- (iwe->cmd == IWEVMICHAELMICFAILURE ||
- iwe->cmd == IWEVCUSTOM)) {
- /* WE-19 removed the pointer from struct iw_point */
- char *dpos = (char *) &iwe_buf.u.data.length;
- int dlen = dpos - (char *) &iwe_buf;
- memcpy(dpos, pos + IW_EV_LCP_LEN,
- sizeof(struct iw_event) - dlen);
- } else {
- memcpy(&iwe_buf, pos, sizeof(struct iw_event));
- custom += IW_EV_POINT_OFF;
- }
-
- switch (iwe->cmd) {
- case IWEVEXPIRED:
- drv_event_disassoc(drv->hapd,
- (u8 *) iwe->u.addr.sa_data);
- break;
- case IWEVREGISTERED:
- madwifi_new_sta(drv, (u8 *) iwe->u.addr.sa_data);
- break;
- case IWEVCUSTOM:
- if (custom + iwe->u.data.length > end)
- return;
- buf = malloc(iwe->u.data.length + 1);
- if (buf == NULL)
- return; /* XXX */
- memcpy(buf, custom, iwe->u.data.length);
- buf[iwe->u.data.length] = '\0';
- madwifi_wireless_event_wireless_custom(drv, buf);
- free(buf);
- break;
- }
-
- pos += iwe->len;
- }
-}
-
-
-static void
-madwifi_wireless_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi,
- u8 *buf, size_t len)
-{
- struct madwifi_driver_data *drv = ctx;
- int attrlen, rta_len;
- struct rtattr *attr;
-
- if (ifi->ifi_index != drv->ifindex)
- return;
-
- attrlen = len;
- attr = (struct rtattr *) buf;
-
- rta_len = RTA_ALIGN(sizeof(struct rtattr));
- while (RTA_OK(attr, attrlen)) {
- if (attr->rta_type == IFLA_WIRELESS) {
- madwifi_wireless_event_wireless(
- drv, ((char *) attr) + rta_len,
- attr->rta_len - rta_len);
- }
- attr = RTA_NEXT(attr, attrlen);
- }
-}
-
-
-static int
-madwifi_get_we_version(struct madwifi_driver_data *drv)
-{
- struct iw_range *range;
- struct iwreq iwr;
- int minlen;
- size_t buflen;
-
- drv->we_version = 0;
-
- /*
- * Use larger buffer than struct iw_range in order to allow the
- * structure to grow in the future.
- */
- buflen = sizeof(struct iw_range) + 500;
- range = os_zalloc(buflen);
- if (range == NULL)
- return -1;
-
- memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
- iwr.u.data.pointer = (caddr_t) range;
- iwr.u.data.length = buflen;
-
- minlen = ((char *) &range->enc_capa) - (char *) range +
- sizeof(range->enc_capa);
-
- if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
- perror("ioctl[SIOCGIWRANGE]");
- free(range);
- return -1;
- } else if (iwr.u.data.length >= minlen &&
- range->we_version_compiled >= 18) {
- wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d "
- "WE(source)=%d enc_capa=0x%x",
- range->we_version_compiled,
- range->we_version_source,
- range->enc_capa);
- drv->we_version = range->we_version_compiled;
- }
-
- free(range);
- return 0;
-}
-
-
-static int
-madwifi_wireless_event_init(struct madwifi_driver_data *drv)
-{
- struct netlink_config *cfg;
-
- madwifi_get_we_version(drv);
-
- cfg = os_zalloc(sizeof(*cfg));
- if (cfg == NULL)
- return -1;
- cfg->ctx = drv;
- cfg->newlink_cb = madwifi_wireless_event_rtm_newlink;
- drv->netlink = netlink_init(cfg);
- if (drv->netlink == NULL) {
- os_free(cfg);
- return -1;
- }
-
- return 0;
-}
-
-
-static int
-madwifi_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len,
- int encrypt, const u8 *own_addr, u32 flags)
-{
- struct madwifi_driver_data *drv = priv;
- unsigned char buf[3000];
- unsigned char *bp = buf;
- struct l2_ethhdr *eth;
- size_t len;
- int status;
-
- /*
- * Prepend the Ethernet header. If the caller left us
- * space at the front we could just insert it but since
- * we don't know we copy to a local buffer. Given the frequency
- * and size of frames this probably doesn't matter.
- */
- len = data_len + sizeof(struct l2_ethhdr);
- if (len > sizeof(buf)) {
- bp = malloc(len);
- if (bp == NULL) {
- printf("EAPOL frame discarded, cannot malloc temp "
- "buffer of size %lu!\n", (unsigned long) len);
- return -1;
- }
- }
- eth = (struct l2_ethhdr *) bp;
- memcpy(eth->h_dest, addr, ETH_ALEN);
- memcpy(eth->h_source, own_addr, ETH_ALEN);
- eth->h_proto = host_to_be16(ETH_P_EAPOL);
- memcpy(eth+1, data, data_len);
-
- wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", bp, len);
-
- status = l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, bp, len);
-
- if (bp != buf)
- free(bp);
- return status;
-}
-
-static void
-handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
-{
- struct madwifi_driver_data *drv = ctx;
- drv_event_eapol_rx(drv->hapd, src_addr, buf + sizeof(struct l2_ethhdr),
- len - sizeof(struct l2_ethhdr));
-}
-
-static void *
-madwifi_init(struct hostapd_data *hapd, struct wpa_init_params *params)
-{
- struct madwifi_driver_data *drv;
- struct ifreq ifr;
- struct iwreq iwr;
- char brname[IFNAMSIZ];
-
- drv = os_zalloc(sizeof(struct madwifi_driver_data));
- if (drv == NULL) {
- printf("Could not allocate memory for madwifi driver data\n");
- return NULL;
- }
-
- drv->hapd = hapd;
- drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
- if (drv->ioctl_sock < 0) {
- perror("socket[PF_INET,SOCK_DGRAM]");
- goto bad;
- }
- memcpy(drv->iface, params->ifname, sizeof(drv->iface));
-
- memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name));
- if (ioctl(drv->ioctl_sock, SIOCGIFINDEX, &ifr) != 0) {
- perror("ioctl(SIOCGIFINDEX)");
- goto bad;
- }
- drv->ifindex = ifr.ifr_ifindex;
-
- drv->sock_xmit = l2_packet_init(drv->iface, NULL, ETH_P_EAPOL,
- handle_read, drv, 1);
- if (drv->sock_xmit == NULL)
- goto bad;
- if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr))
- goto bad;
- if (params->bridge[0]) {
- wpa_printf(MSG_DEBUG, "Configure bridge %s for EAPOL traffic.",
- params->bridge[0]);
- drv->sock_recv = l2_packet_init(params->bridge[0], NULL,
- ETH_P_EAPOL, handle_read, drv,
- 1);
- if (drv->sock_recv == NULL)
- goto bad;
- } else if (linux_br_get(brname, drv->iface) == 0) {
- wpa_printf(MSG_DEBUG, "Interface in bridge %s; configure for "
- "EAPOL receive", brname);
- drv->sock_recv = l2_packet_init(brname, NULL, ETH_P_EAPOL,
- handle_read, drv, 1);
- if (drv->sock_recv == NULL)
- goto bad;
- } else
- drv->sock_recv = drv->sock_xmit;
-
- memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
-
- iwr.u.mode = IW_MODE_MASTER;
-
- if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) {
- perror("ioctl[SIOCSIWMODE]");
- printf("Could not set interface to master mode!\n");
- goto bad;
- }
-
- /* mark down during setup */
- linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0);
- madwifi_set_privacy(drv, 0); /* default to no privacy */
-
- madwifi_receive_probe_req(drv);
-
- if (madwifi_wireless_event_init(drv))
- goto bad;
-
- return drv;
-bad:
- if (drv->sock_xmit != NULL)
- l2_packet_deinit(drv->sock_xmit);
- if (drv->ioctl_sock >= 0)
- close(drv->ioctl_sock);
- if (drv != NULL)
- free(drv);
- return NULL;
-}
-
-
-static void
-madwifi_deinit(void *priv)
-{
- struct madwifi_driver_data *drv = priv;
-
- netlink_deinit(drv->netlink);
- (void) linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0);
- if (drv->ioctl_sock >= 0)
- close(drv->ioctl_sock);
- if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit)
- l2_packet_deinit(drv->sock_recv);
- if (drv->sock_xmit != NULL)
- l2_packet_deinit(drv->sock_xmit);
- if (drv->sock_raw)
- l2_packet_deinit(drv->sock_raw);
- free(drv);
-}
-
-static int
-madwifi_set_ssid(void *priv, const u8 *buf, int len)
-{
- struct madwifi_driver_data *drv = priv;
- struct iwreq iwr;
-
- memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
- iwr.u.essid.flags = 1; /* SSID active */
- iwr.u.essid.pointer = (caddr_t) buf;
- iwr.u.essid.length = len + 1;
-
- if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
- perror("ioctl[SIOCSIWESSID]");
- printf("len=%d\n", len);
- return -1;
- }
- return 0;
-}
-
-static int
-madwifi_get_ssid(void *priv, u8 *buf, int len)
-{
- struct madwifi_driver_data *drv = priv;
- struct iwreq iwr;
- int ret = 0;
-
- memset(&iwr, 0, sizeof(iwr));
- os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
- iwr.u.essid.pointer = (caddr_t) buf;
- iwr.u.essid.length = len;
-
- if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
- perror("ioctl[SIOCGIWESSID]");
- ret = -1;
- } else
- ret = iwr.u.essid.length;
-
- return ret;
-}
-
-static int
-madwifi_set_countermeasures(void *priv, int enabled)
-{
- struct madwifi_driver_data *drv = priv;
- wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
- return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled);
-}
-
-static int
-madwifi_commit(void *priv)
-{
- struct madwifi_driver_data *drv = priv;
- return linux_set_iface_flags(drv->ioctl_sock, drv->iface, 1);
-}
-
-
-const struct wpa_driver_ops wpa_driver_madwifi_ops = {
- .name = "madwifi",
- .desc = "MADWIFI 802.11 support (Atheros, etc.)",
- .set_key = wpa_driver_madwifi_set_key,
- .hapd_init = madwifi_init,
- .hapd_deinit = madwifi_deinit,
- .set_ieee8021x = madwifi_set_ieee8021x,
- .set_privacy = madwifi_set_privacy,
- .get_seqnum = madwifi_get_seqnum,
- .flush = madwifi_flush,
- .set_generic_elem = madwifi_set_opt_ie,
- .sta_set_flags = madwifi_sta_set_flags,
- .read_sta_data = madwifi_read_sta_driver_data,
- .hapd_send_eapol = madwifi_send_eapol,
- .sta_disassoc = madwifi_sta_disassoc,
- .sta_deauth = madwifi_sta_deauth,
- .hapd_set_ssid = madwifi_set_ssid,
- .hapd_get_ssid = madwifi_get_ssid,
- .hapd_set_countermeasures = madwifi_set_countermeasures,
- .sta_clear_stats = madwifi_sta_clear_stats,
- .commit = madwifi_commit,
- .set_ap_wps_ie = madwifi_set_ap_wps_ie,
- .set_freq = madwifi_set_freq,
-};
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 4c8f29f..d681ea6 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -1,6 +1,6 @@
/*
* Driver interaction with Linux nl80211/cfg80211
- * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
* Copyright (c) 2003-2004, Instant802 Networks, Inc.
* Copyright (c) 2005-2006, Devicescape Software, Inc.
* Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
@@ -11,67 +11,35 @@
*/
#include "includes.h"
-#include <sys/ioctl.h>
#include <sys/types.h>
-#include <sys/stat.h>
#include <fcntl.h>
#include <net/if.h>
#include <netlink/genl/genl.h>
-#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h>
#ifdef CONFIG_LIBNL3_ROUTE
#include <netlink/route/neighbour.h>
#endif /* CONFIG_LIBNL3_ROUTE */
#include <linux/rtnetlink.h>
#include <netpacket/packet.h>
-#include <linux/filter.h>
#include <linux/errqueue.h>
-#include "nl80211_copy.h"
#include "common.h"
#include "eloop.h"
-#include "utils/list.h"
#include "common/qca-vendor.h"
#include "common/qca-vendor-attr.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "l2_packet/l2_packet.h"
#include "netlink.h"
+#include "linux_defines.h"
#include "linux_ioctl.h"
#include "radiotap.h"
#include "radiotap_iter.h"
#include "rfkill.h"
-#include "driver.h"
+#include "driver_nl80211.h"
-#ifndef SO_WIFI_STATUS
-# if defined(__sparc__)
-# define SO_WIFI_STATUS 0x0025
-# elif defined(__parisc__)
-# define SO_WIFI_STATUS 0x4022
-# else
-# define SO_WIFI_STATUS 41
-# endif
-# define SCM_WIFI_STATUS SO_WIFI_STATUS
-#endif
-
-#ifndef SO_EE_ORIGIN_TXSTATUS
-#define SO_EE_ORIGIN_TXSTATUS 4
-#endif
-
-#ifndef PACKET_TX_TIMESTAMP
-#define PACKET_TX_TIMESTAMP 16
-#endif
-
-#ifdef ANDROID
-#include "android_drv.h"
-#endif /* ANDROID */
-#ifdef CONFIG_LIBNL20
-/* libnl 2.0 compatibility code */
-#define nl_handle nl_sock
-#define nl80211_handle_alloc nl_socket_alloc_cb
-#define nl80211_handle_destroy nl_socket_free
-#else
+#ifndef CONFIG_LIBNL20
/*
* libnl 1.1 has a bug, it tries to allocate socket numbers densely
* but when you free a socket again it will mess up its bitmap and
@@ -116,12 +84,10 @@
#ifdef ANDROID
/* system/core/libnl_2 does not include nl_socket_set_nonblocking() */
-static int android_nl_socket_set_nonblocking(struct nl_handle *handle)
-{
- return fcntl(nl_socket_get_fd(handle), F_SETFL, O_NONBLOCK);
-}
#undef nl_socket_set_nonblocking
#define nl_socket_set_nonblocking(h) android_nl_socket_set_nonblocking(h)
+
+#define genl_ctrl_resolve android_genl_ctrl_resolve
#endif /* ANDROID */
@@ -166,6 +132,22 @@
eloop_sock_handler handler,
void *eloop_data)
{
+#ifdef CONFIG_LIBNL20
+ /*
+ * libnl uses a pretty small buffer (32 kB that gets converted to 64 kB)
+ * by default. It is possible to hit that limit in some cases where
+ * operations are blocked, e.g., with a burst of Deauthentication frames
+ * to hostapd and STA entry deletion. Try to increase the buffer to make
+ * this less likely to occur.
+ */
+ if (nl_socket_set_buffer_size(*handle, 262144, 0) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Could not set nl_socket RX buffer size: %s",
+ strerror(errno));
+ /* continue anyway with the default (smaller) buffer */
+ }
+#endif /* CONFIG_LIBNL20 */
+
nl_socket_set_nonblocking(*handle);
eloop_register_read_sock(nl_socket_get_fd(*handle), handler,
eloop_data, *handle);
@@ -181,374 +163,41 @@
}
-#ifndef IFF_LOWER_UP
-#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */
-#endif
-#ifndef IFF_DORMANT
-#define IFF_DORMANT 0x20000 /* driver signals dormant */
-#endif
-
-#ifndef IF_OPER_DORMANT
-#define IF_OPER_DORMANT 5
-#endif
-#ifndef IF_OPER_UP
-#define IF_OPER_UP 6
-#endif
-
-struct nl80211_global {
- struct dl_list interfaces;
- int if_add_ifindex;
- u64 if_add_wdevid;
- int if_add_wdevid_set;
- struct netlink_data *netlink;
- struct nl_cb *nl_cb;
- struct nl_handle *nl;
- int nl80211_id;
- int ioctl_sock; /* socket for ioctl() use */
-
- struct nl_handle *nl_event;
-};
-
-struct nl80211_wiphy_data {
- struct dl_list list;
- struct dl_list bsss;
- struct dl_list drvs;
-
- struct nl_handle *nl_beacons;
- struct nl_cb *nl_cb;
-
- int wiphy_idx;
-};
-
static void nl80211_global_deinit(void *priv);
-struct i802_bss {
- struct wpa_driver_nl80211_data *drv;
- struct i802_bss *next;
- int ifindex;
- u64 wdev_id;
- char ifname[IFNAMSIZ + 1];
- char brname[IFNAMSIZ];
- unsigned int beacon_set:1;
- unsigned int added_if_into_bridge:1;
- unsigned int added_bridge:1;
- unsigned int in_deinit:1;
- unsigned int wdev_id_set:1;
- unsigned int added_if:1;
- unsigned int static_ap:1;
-
- u8 addr[ETH_ALEN];
-
- int freq;
- int bandwidth;
- int if_dynamic;
-
- void *ctx;
- struct nl_handle *nl_preq, *nl_mgmt;
- struct nl_cb *nl_cb;
-
- struct nl80211_wiphy_data *wiphy_data;
- struct dl_list wiphy_list;
-};
-
-struct wpa_driver_nl80211_data {
- struct nl80211_global *global;
- struct dl_list list;
- struct dl_list wiphy_list;
- char phyname[32];
- u8 perm_addr[ETH_ALEN];
- void *ctx;
- int ifindex;
- int if_removed;
- int if_disabled;
- int ignore_if_down_event;
- struct rfkill_data *rfkill;
- struct wpa_driver_capa capa;
- u8 *extended_capa, *extended_capa_mask;
- unsigned int extended_capa_len;
- int has_capability;
-
- int operstate;
-
- int scan_complete_events;
- enum scan_states {
- NO_SCAN, SCAN_REQUESTED, SCAN_STARTED, SCAN_COMPLETED,
- SCAN_ABORTED, SCHED_SCAN_STARTED, SCHED_SCAN_STOPPED,
- SCHED_SCAN_RESULTS
- } scan_state;
-
- struct nl_cb *nl_cb;
-
- u8 auth_bssid[ETH_ALEN];
- u8 auth_attempt_bssid[ETH_ALEN];
- u8 bssid[ETH_ALEN];
- u8 prev_bssid[ETH_ALEN];
- int associated;
- u8 ssid[32];
- size_t ssid_len;
- enum nl80211_iftype nlmode;
- enum nl80211_iftype ap_scan_as_station;
- unsigned int assoc_freq;
-
- int monitor_sock;
- int monitor_ifidx;
- int monitor_refcount;
-
- unsigned int disabled_11b_rates:1;
- unsigned int pending_remain_on_chan:1;
- unsigned int in_interface_list:1;
- unsigned int device_ap_sme:1;
- unsigned int poll_command_supported:1;
- unsigned int data_tx_status:1;
- unsigned int scan_for_auth:1;
- unsigned int retry_auth:1;
- unsigned int use_monitor:1;
- unsigned int ignore_next_local_disconnect:1;
- unsigned int ignore_next_local_deauth:1;
- unsigned int allow_p2p_device:1;
- unsigned int hostapd:1;
- unsigned int start_mode_ap:1;
- unsigned int start_iface_up:1;
- unsigned int test_use_roc_tx:1;
- unsigned int ignore_deauth_event:1;
- unsigned int roaming_vendor_cmd_avail:1;
- unsigned int dfs_vendor_cmd_avail:1;
- unsigned int have_low_prio_scan:1;
- unsigned int force_connect_cmd:1;
- unsigned int addr_changed:1;
-
- u64 remain_on_chan_cookie;
- u64 send_action_cookie;
-
- unsigned int last_mgmt_freq;
-
- struct wpa_driver_scan_filter *filter_ssids;
- size_t num_filter_ssids;
-
- struct i802_bss *first_bss;
-
- int eapol_tx_sock;
-
- int eapol_sock; /* socket for EAPOL frames */
-
- struct nl_handle *rtnl_sk; /* nl_sock for NETLINK_ROUTE */
-
- int default_if_indices[16];
- int *if_indices;
- int num_if_indices;
-
- /* From failed authentication command */
- int auth_freq;
- u8 auth_bssid_[ETH_ALEN];
- u8 auth_ssid[32];
- size_t auth_ssid_len;
- int auth_alg;
- u8 *auth_ie;
- size_t auth_ie_len;
- u8 auth_wep_key[4][16];
- size_t auth_wep_key_len[4];
- int auth_wep_tx_keyidx;
- int auth_local_state_change;
- int auth_p2p;
-};
-
-
static void wpa_driver_nl80211_deinit(struct i802_bss *bss);
-static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx,
- void *timeout_ctx);
-static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
- enum nl80211_iftype nlmode);
static int wpa_driver_nl80211_set_mode_ibss(struct i802_bss *bss,
struct hostapd_freq_params *freq);
static int
wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
- const u8 *set_addr, int first);
-static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
- const u8 *addr, int cmd, u16 reason_code,
- int local_state_change);
-static void nl80211_remove_monitor_interface(
- struct wpa_driver_nl80211_data *drv);
+ const u8 *set_addr, int first,
+ const char *driver_params);
static int nl80211_send_frame_cmd(struct i802_bss *bss,
unsigned int freq, unsigned int wait,
const u8 *buf, size_t buf_len, u64 *cookie,
int no_cck, int no_ack, int offchanok);
-static int nl80211_register_frame(struct i802_bss *bss,
- struct nl_handle *hl_handle,
- u16 type, const u8 *match, size_t match_len);
static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss,
int report);
-#ifdef ANDROID
-static int android_pno_start(struct i802_bss *bss,
- struct wpa_driver_scan_params *params);
-static int android_pno_stop(struct i802_bss *bss);
-extern int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf,
- size_t buf_len);
-#endif /* ANDROID */
-#ifdef ANDROID_P2P
-#ifdef ANDROID_P2P_STUB
-int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration) {
- return 0;
-}
-int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len) {
- return 0;
-}
-int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow) {
- return -1;
-}
-int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
- const struct wpabuf *proberesp,
- const struct wpabuf *assocresp) {
- return 0;
-}
-#else /* ANDROID_P2P_STUB */
-int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration);
-int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len);
-int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow);
-int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
- const struct wpabuf *proberesp,
- const struct wpabuf *assocresp);
-#endif /* ANDROID_P2P_STUB */
-#endif /* ANDROID_P2P */
static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
-static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
- enum wpa_driver_if_type type,
- const char *ifname);
static int nl80211_set_channel(struct i802_bss *bss,
struct hostapd_freq_params *freq, int set_chan);
static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
int ifindex, int disabled);
-static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv);
-static int wpa_driver_nl80211_authenticate_retry(
- struct wpa_driver_nl80211_data *drv);
+static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv,
+ int reset_mode);
-static int i802_set_freq(void *priv, struct hostapd_freq_params *freq);
static int i802_set_iface_flags(struct i802_bss *bss, int up);
-
-
-static const char * nl80211_command_to_string(enum nl80211_commands cmd)
-{
-#define C2S(x) case x: return #x;
- switch (cmd) {
- C2S(NL80211_CMD_UNSPEC)
- C2S(NL80211_CMD_GET_WIPHY)
- C2S(NL80211_CMD_SET_WIPHY)
- C2S(NL80211_CMD_NEW_WIPHY)
- C2S(NL80211_CMD_DEL_WIPHY)
- C2S(NL80211_CMD_GET_INTERFACE)
- C2S(NL80211_CMD_SET_INTERFACE)
- C2S(NL80211_CMD_NEW_INTERFACE)
- C2S(NL80211_CMD_DEL_INTERFACE)
- C2S(NL80211_CMD_GET_KEY)
- C2S(NL80211_CMD_SET_KEY)
- C2S(NL80211_CMD_NEW_KEY)
- C2S(NL80211_CMD_DEL_KEY)
- C2S(NL80211_CMD_GET_BEACON)
- C2S(NL80211_CMD_SET_BEACON)
- C2S(NL80211_CMD_START_AP)
- C2S(NL80211_CMD_STOP_AP)
- C2S(NL80211_CMD_GET_STATION)
- C2S(NL80211_CMD_SET_STATION)
- C2S(NL80211_CMD_NEW_STATION)
- C2S(NL80211_CMD_DEL_STATION)
- C2S(NL80211_CMD_GET_MPATH)
- C2S(NL80211_CMD_SET_MPATH)
- C2S(NL80211_CMD_NEW_MPATH)
- C2S(NL80211_CMD_DEL_MPATH)
- C2S(NL80211_CMD_SET_BSS)
- C2S(NL80211_CMD_SET_REG)
- C2S(NL80211_CMD_REQ_SET_REG)
- C2S(NL80211_CMD_GET_MESH_CONFIG)
- C2S(NL80211_CMD_SET_MESH_CONFIG)
- C2S(NL80211_CMD_SET_MGMT_EXTRA_IE)
- C2S(NL80211_CMD_GET_REG)
- C2S(NL80211_CMD_GET_SCAN)
- C2S(NL80211_CMD_TRIGGER_SCAN)
- C2S(NL80211_CMD_NEW_SCAN_RESULTS)
- C2S(NL80211_CMD_SCAN_ABORTED)
- C2S(NL80211_CMD_REG_CHANGE)
- C2S(NL80211_CMD_AUTHENTICATE)
- C2S(NL80211_CMD_ASSOCIATE)
- C2S(NL80211_CMD_DEAUTHENTICATE)
- C2S(NL80211_CMD_DISASSOCIATE)
- C2S(NL80211_CMD_MICHAEL_MIC_FAILURE)
- C2S(NL80211_CMD_REG_BEACON_HINT)
- C2S(NL80211_CMD_JOIN_IBSS)
- C2S(NL80211_CMD_LEAVE_IBSS)
- C2S(NL80211_CMD_TESTMODE)
- C2S(NL80211_CMD_CONNECT)
- C2S(NL80211_CMD_ROAM)
- C2S(NL80211_CMD_DISCONNECT)
- C2S(NL80211_CMD_SET_WIPHY_NETNS)
- C2S(NL80211_CMD_GET_SURVEY)
- C2S(NL80211_CMD_NEW_SURVEY_RESULTS)
- C2S(NL80211_CMD_SET_PMKSA)
- C2S(NL80211_CMD_DEL_PMKSA)
- C2S(NL80211_CMD_FLUSH_PMKSA)
- C2S(NL80211_CMD_REMAIN_ON_CHANNEL)
- C2S(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL)
- C2S(NL80211_CMD_SET_TX_BITRATE_MASK)
- C2S(NL80211_CMD_REGISTER_FRAME)
- C2S(NL80211_CMD_FRAME)
- C2S(NL80211_CMD_FRAME_TX_STATUS)
- C2S(NL80211_CMD_SET_POWER_SAVE)
- C2S(NL80211_CMD_GET_POWER_SAVE)
- C2S(NL80211_CMD_SET_CQM)
- C2S(NL80211_CMD_NOTIFY_CQM)
- C2S(NL80211_CMD_SET_CHANNEL)
- C2S(NL80211_CMD_SET_WDS_PEER)
- C2S(NL80211_CMD_FRAME_WAIT_CANCEL)
- C2S(NL80211_CMD_JOIN_MESH)
- C2S(NL80211_CMD_LEAVE_MESH)
- C2S(NL80211_CMD_UNPROT_DEAUTHENTICATE)
- C2S(NL80211_CMD_UNPROT_DISASSOCIATE)
- C2S(NL80211_CMD_NEW_PEER_CANDIDATE)
- C2S(NL80211_CMD_GET_WOWLAN)
- C2S(NL80211_CMD_SET_WOWLAN)
- C2S(NL80211_CMD_START_SCHED_SCAN)
- C2S(NL80211_CMD_STOP_SCHED_SCAN)
- C2S(NL80211_CMD_SCHED_SCAN_RESULTS)
- C2S(NL80211_CMD_SCHED_SCAN_STOPPED)
- C2S(NL80211_CMD_SET_REKEY_OFFLOAD)
- C2S(NL80211_CMD_PMKSA_CANDIDATE)
- C2S(NL80211_CMD_TDLS_OPER)
- C2S(NL80211_CMD_TDLS_MGMT)
- C2S(NL80211_CMD_UNEXPECTED_FRAME)
- C2S(NL80211_CMD_PROBE_CLIENT)
- C2S(NL80211_CMD_REGISTER_BEACONS)
- C2S(NL80211_CMD_UNEXPECTED_4ADDR_FRAME)
- C2S(NL80211_CMD_SET_NOACK_MAP)
- C2S(NL80211_CMD_CH_SWITCH_NOTIFY)
- C2S(NL80211_CMD_START_P2P_DEVICE)
- C2S(NL80211_CMD_STOP_P2P_DEVICE)
- C2S(NL80211_CMD_CONN_FAILED)
- C2S(NL80211_CMD_SET_MCAST_RATE)
- C2S(NL80211_CMD_SET_MAC_ACL)
- C2S(NL80211_CMD_RADAR_DETECT)
- C2S(NL80211_CMD_GET_PROTOCOL_FEATURES)
- C2S(NL80211_CMD_UPDATE_FT_IES)
- C2S(NL80211_CMD_FT_EVENT)
- C2S(NL80211_CMD_CRIT_PROTOCOL_START)
- C2S(NL80211_CMD_CRIT_PROTOCOL_STOP)
- C2S(NL80211_CMD_GET_COALESCE)
- C2S(NL80211_CMD_SET_COALESCE)
- C2S(NL80211_CMD_CHANNEL_SWITCH)
- C2S(NL80211_CMD_VENDOR)
- C2S(NL80211_CMD_SET_QOS_MAP)
- default:
- return "NL80211_CMD_UNKNOWN";
- }
-#undef C2S
-}
+static int nl80211_set_param(void *priv, const char *param);
/* Converts nl80211_chan_width to a common format */
-static enum chan_width convert2width(int width)
+enum chan_width convert2width(int width)
{
switch (width) {
case NL80211_CHAN_WIDTH_20_NOHT:
@@ -568,14 +217,14 @@
}
-static int is_ap_interface(enum nl80211_iftype nlmode)
+int is_ap_interface(enum nl80211_iftype nlmode)
{
return nlmode == NL80211_IFTYPE_AP ||
nlmode == NL80211_IFTYPE_P2P_GO;
}
-static int is_sta_interface(enum nl80211_iftype nlmode)
+int is_sta_interface(enum nl80211_iftype nlmode)
{
return nlmode == NL80211_IFTYPE_STATION ||
nlmode == NL80211_IFTYPE_P2P_CLIENT;
@@ -589,8 +238,8 @@
}
-static struct i802_bss * get_bss_ifindex(struct wpa_driver_nl80211_data *drv,
- int ifindex)
+struct i802_bss * get_bss_ifindex(struct wpa_driver_nl80211_data *drv,
+ int ifindex)
{
struct i802_bss *bss;
@@ -603,7 +252,13 @@
}
-static void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv)
+static int is_mesh_interface(enum nl80211_iftype nlmode)
+{
+ return nlmode == NL80211_IFTYPE_MESH_POINT;
+}
+
+
+void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv)
{
if (drv->associated)
os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN);
@@ -612,17 +267,6 @@
}
-struct nl80211_bss_info_arg {
- struct wpa_driver_nl80211_data *drv;
- struct wpa_scan_results *res;
- unsigned int assoc_freq;
- unsigned int ibss_freq;
- u8 assoc_bssid[ETH_ALEN];
-};
-
-static int bss_info_handler(struct nl_msg *msg, void *arg);
-
-
/* nl80211 code */
static int ack_handler(struct nl_msg *msg, void *arg)
{
@@ -653,6 +297,28 @@
}
+static void nl80211_nlmsg_clear(struct nl_msg *msg)
+{
+ /*
+ * Clear nlmsg data, e.g., to make sure key material is not left in
+ * heap memory for unnecessarily long time.
+ */
+ if (msg) {
+ struct nlmsghdr *hdr = nlmsg_hdr(msg);
+ void *data = nlmsg_data(hdr);
+ /*
+ * This would use nlmsg_datalen() or the older nlmsg_len() if
+ * only libnl were to maintain a stable API.. Neither will work
+ * with all released versions, so just calculate the length
+ * here.
+ */
+ int len = hdr->nlmsg_len - NLMSG_HDRLEN;
+
+ os_memset(data, 0, len);
+ }
+}
+
+
static int send_and_recv(struct nl80211_global *global,
struct nl_handle *nl_handle, struct nl_msg *msg,
int (*valid_handler)(struct nl_msg *, void *),
@@ -661,6 +327,9 @@
struct nl_cb *cb;
int err = -ENOMEM;
+ if (!msg)
+ return -ENOMEM;
+
cb = nl_cb_clone(global->nl_cb);
if (!cb)
goto out;
@@ -689,25 +358,17 @@
}
out:
nl_cb_put(cb);
+ if (!valid_handler && valid_data == (void *) -1)
+ nl80211_nlmsg_clear(msg);
nlmsg_free(msg);
return err;
}
-static int send_and_recv_msgs_global(struct nl80211_global *global,
- struct nl_msg *msg,
- int (*valid_handler)(struct nl_msg *, void *),
- void *valid_data)
-{
- return send_and_recv(global, global->nl, msg, valid_handler,
- valid_data);
-}
-
-
-static int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
- struct nl_msg *msg,
- int (*valid_handler)(struct nl_msg *, void *),
- void *valid_data)
+int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
+ struct nl_msg *msg,
+ int (*valid_handler)(struct nl_msg *, void *),
+ void *valid_data)
{
return send_and_recv(drv->global, drv->global->nl, msg,
valid_handler, valid_data);
@@ -720,19 +381,6 @@
};
-static int nl80211_set_iface_id(struct nl_msg *msg, struct i802_bss *bss)
-{
- if (bss->wdev_id_set)
- NLA_PUT_U64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
- else
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
- return 0;
-
-nla_put_failure:
- return -1;
-}
-
-
static int family_handler(struct nl_msg *msg, void *arg)
{
struct family_data *res = arg;
@@ -768,35 +416,93 @@
const char *family, const char *group)
{
struct nl_msg *msg;
- int ret = -1;
+ int ret;
struct family_data res = { group, -ENOENT };
msg = nlmsg_alloc();
if (!msg)
return -ENOMEM;
- genlmsg_put(msg, 0, 0, genl_ctrl_resolve(global->nl, "nlctrl"),
- 0, 0, CTRL_CMD_GETFAMILY, 0);
- NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);
+ if (!genlmsg_put(msg, 0, 0, genl_ctrl_resolve(global->nl, "nlctrl"),
+ 0, 0, CTRL_CMD_GETFAMILY, 0) ||
+ nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, family)) {
+ nlmsg_free(msg);
+ return -1;
+ }
- ret = send_and_recv_msgs_global(global, msg, family_handler, &res);
- msg = NULL;
+ ret = send_and_recv(global, global->nl, msg, family_handler, &res);
if (ret == 0)
ret = res.id;
-
-nla_put_failure:
- nlmsg_free(msg);
return ret;
}
-static void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
- struct nl_msg *msg, int flags, uint8_t cmd)
+void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
+ struct nl_msg *msg, int flags, uint8_t cmd)
{
return genlmsg_put(msg, 0, 0, drv->global->nl80211_id,
0, flags, cmd, 0);
}
+static int nl80211_set_iface_id(struct nl_msg *msg, struct i802_bss *bss)
+{
+ if (bss->wdev_id_set)
+ return nla_put_u64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
+ return nla_put_u32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+}
+
+
+struct nl_msg * nl80211_cmd_msg(struct i802_bss *bss, int flags, uint8_t cmd)
+{
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return NULL;
+
+ if (!nl80211_cmd(bss->drv, msg, flags, cmd) ||
+ nl80211_set_iface_id(msg, bss) < 0) {
+ nlmsg_free(msg);
+ return NULL;
+ }
+
+ return msg;
+}
+
+
+static struct nl_msg *
+nl80211_ifindex_msg(struct wpa_driver_nl80211_data *drv, int ifindex,
+ int flags, uint8_t cmd)
+{
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return NULL;
+
+ if (!nl80211_cmd(drv, msg, flags, cmd) ||
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifindex)) {
+ nlmsg_free(msg);
+ return NULL;
+ }
+
+ return msg;
+}
+
+
+struct nl_msg * nl80211_drv_msg(struct wpa_driver_nl80211_data *drv, int flags,
+ uint8_t cmd)
+{
+ return nl80211_ifindex_msg(drv, drv->ifindex, flags, cmd);
+}
+
+
+struct nl_msg * nl80211_bss_msg(struct i802_bss *bss, int flags, uint8_t cmd)
+{
+ return nl80211_ifindex_msg(bss->drv, bss->ifindex, flags, cmd);
+}
+
+
struct wiphy_idx_data {
int wiphy_idx;
enum nl80211_iftype nlmode;
@@ -827,7 +533,7 @@
}
-static int nl80211_get_wiphy_index(struct i802_bss *bss)
+int nl80211_get_wiphy_index(struct i802_bss *bss)
{
struct nl_msg *msg;
struct wiphy_idx_data data = {
@@ -835,20 +541,11 @@
.macaddr = NULL,
};
- msg = nlmsg_alloc();
- if (!msg)
- return NL80211_IFTYPE_UNSPECIFIED;
-
- nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
-
- if (nl80211_set_iface_id(msg, bss) < 0)
- goto nla_put_failure;
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
+ return -1;
if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0)
return data.wiphy_idx;
- msg = NULL;
-nla_put_failure:
- nlmsg_free(msg);
return -1;
}
@@ -861,20 +558,11 @@
.macaddr = NULL,
};
- msg = nlmsg_alloc();
- if (!msg)
- return -1;
-
- nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
-
- if (nl80211_set_iface_id(msg, bss) < 0)
- goto nla_put_failure;
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
+ return NL80211_IFTYPE_UNSPECIFIED;
if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0)
return data.nlmode;
- msg = NULL;
-nla_put_failure:
- nlmsg_free(msg);
return NL80211_IFTYPE_UNSPECIFIED;
}
@@ -886,19 +574,10 @@
.macaddr = bss->addr,
};
- msg = nlmsg_alloc();
- if (!msg)
- return NL80211_IFTYPE_UNSPECIFIED;
-
- nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
- if (nl80211_set_iface_id(msg, bss) < 0)
- goto nla_put_failure;
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
+ return -1;
return send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data);
-
-nla_put_failure:
- nlmsg_free(msg);
- return NL80211_IFTYPE_UNSPECIFIED;
}
@@ -906,27 +585,24 @@
struct nl80211_wiphy_data *w)
{
struct nl_msg *msg;
- int ret = -1;
+ int ret;
msg = nlmsg_alloc();
if (!msg)
return -1;
- nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_BEACONS);
-
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, w->wiphy_idx);
+ if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_BEACONS) ||
+ nla_put_u32(msg, NL80211_ATTR_WIPHY, w->wiphy_idx)) {
+ nlmsg_free(msg);
+ return -1;
+ }
ret = send_and_recv(drv->global, w->nl_beacons, msg, NULL, NULL);
- msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Register beacons command "
"failed: ret=%d (%s)",
ret, strerror(-ret));
- goto nla_put_failure;
}
- ret = 0;
-nla_put_failure:
- nlmsg_free(msg);
return ret;
}
@@ -1104,7 +780,7 @@
static void wpa_driver_nl80211_event_newlink(
- struct wpa_driver_nl80211_data *drv, char *ifname)
+ struct wpa_driver_nl80211_data *drv, const char *ifname)
{
union wpa_event_data event;
@@ -1130,7 +806,7 @@
static void wpa_driver_nl80211_event_dellink(
- struct wpa_driver_nl80211_data *drv, char *ifname)
+ struct wpa_driver_nl80211_data *drv, const char *ifname)
{
union wpa_event_data event;
@@ -1190,7 +866,7 @@
if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) {
wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
"interface");
- wpa_driver_nl80211_finish_drv_init(drv, NULL, 0);
+ wpa_driver_nl80211_finish_drv_init(drv, NULL, 0, NULL);
return 1;
}
@@ -1281,6 +957,7 @@
drv->first_bss->ifname) > 0) {
wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
"event since interface %s is up", namebuf);
+ drv->ignore_if_down_event = 0;
return;
}
wpa_printf(MSG_DEBUG, "nl80211: Interface down");
@@ -1368,11 +1045,25 @@
wpa_driver_nl80211_event_newlink(drv, ifname);
if (ifi->ifi_family == AF_BRIDGE && brid) {
+ struct i802_bss *bss;
+
/* device has been added to bridge */
- if_indextoname(brid, namebuf);
+ if (!if_indextoname(brid, namebuf)) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Could not find bridge ifname for ifindex %u",
+ brid);
+ return;
+ }
wpa_printf(MSG_DEBUG, "nl80211: Add ifindex %u for bridge %s",
brid, namebuf);
add_ifidx(drv, brid);
+
+ for (bss = drv->first_bss; bss; bss = bss->next) {
+ if (os_strcmp(ifname, bss->ifname) == 0) {
+ os_strlcpy(bss->brname, namebuf, IFNAMSIZ);
+ break;
+ }
+ }
}
}
@@ -1442,73 +1133,31 @@
if (ifi->ifi_family == AF_BRIDGE && brid) {
/* device has been removed from bridge */
char namebuf[IFNAMSIZ];
- if_indextoname(brid, namebuf);
- wpa_printf(MSG_DEBUG, "nl80211: Remove ifindex %u for bridge "
- "%s", brid, namebuf);
+
+ if (!if_indextoname(brid, namebuf)) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Could not find bridge ifname for ifindex %u",
+ brid);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Remove ifindex %u for bridge %s",
+ brid, namebuf);
+ }
del_ifidx(drv, brid);
}
}
-static void mlme_event_auth(struct wpa_driver_nl80211_data *drv,
- const u8 *frame, size_t len)
-{
- const struct ieee80211_mgmt *mgmt;
- union wpa_event_data event;
-
- if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
- drv->force_connect_cmd) {
- /*
- * Avoid reporting two association events that would confuse
- * the core code.
- */
- wpa_printf(MSG_DEBUG,
- "nl80211: Ignore auth event when using driver SME");
- return;
- }
-
- wpa_printf(MSG_DEBUG, "nl80211: Authenticate event");
- mgmt = (const struct ieee80211_mgmt *) frame;
- if (len < 24 + sizeof(mgmt->u.auth)) {
- wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
- "frame");
- return;
- }
-
- os_memcpy(drv->auth_bssid, mgmt->sa, ETH_ALEN);
- os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN);
- os_memset(&event, 0, sizeof(event));
- os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN);
- event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg);
- event.auth.auth_transaction =
- le_to_host16(mgmt->u.auth.auth_transaction);
- event.auth.status_code = le_to_host16(mgmt->u.auth.status_code);
- if (len > 24 + sizeof(mgmt->u.auth)) {
- event.auth.ies = mgmt->u.auth.variable;
- event.auth.ies_len = len - 24 - sizeof(mgmt->u.auth);
- }
-
- wpa_supplicant_event(drv->ctx, EVENT_AUTH, &event);
-}
-
-
-static unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv)
+unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv)
{
struct nl_msg *msg;
int ret;
struct nl80211_bss_info_arg arg;
+ msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
os_memset(&arg, 0, sizeof(arg));
- msg = nlmsg_alloc();
- if (!msg)
- goto nla_put_failure;
-
- nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
arg.drv = drv;
ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
- msg = NULL;
if (ret == 0) {
unsigned int freq = drv->nlmode == NL80211_IFTYPE_ADHOC ?
arg.ibss_freq : arg.assoc_freq;
@@ -1520,804 +1169,10 @@
}
wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
"(%s)", ret, strerror(-ret));
-nla_put_failure:
- nlmsg_free(msg);
return drv->assoc_freq;
}
-static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
- const u8 *frame, size_t len)
-{
- const struct ieee80211_mgmt *mgmt;
- union wpa_event_data event;
- u16 status;
-
- if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
- drv->force_connect_cmd) {
- /*
- * Avoid reporting two association events that would confuse
- * the core code.
- */
- wpa_printf(MSG_DEBUG,
- "nl80211: Ignore assoc event when using driver SME");
- return;
- }
-
- wpa_printf(MSG_DEBUG, "nl80211: Associate event");
- mgmt = (const struct ieee80211_mgmt *) frame;
- if (len < 24 + sizeof(mgmt->u.assoc_resp)) {
- wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
- "frame");
- return;
- }
-
- status = le_to_host16(mgmt->u.assoc_resp.status_code);
- if (status != WLAN_STATUS_SUCCESS) {
- os_memset(&event, 0, sizeof(event));
- event.assoc_reject.bssid = mgmt->bssid;
- if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
- event.assoc_reject.resp_ies =
- (u8 *) mgmt->u.assoc_resp.variable;
- event.assoc_reject.resp_ies_len =
- len - 24 - sizeof(mgmt->u.assoc_resp);
- }
- event.assoc_reject.status_code = status;
-
- wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
- return;
- }
-
- drv->associated = 1;
- os_memcpy(drv->bssid, mgmt->sa, ETH_ALEN);
- os_memcpy(drv->prev_bssid, mgmt->sa, ETH_ALEN);
-
- os_memset(&event, 0, sizeof(event));
- if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
- event.assoc_info.resp_ies = (u8 *) mgmt->u.assoc_resp.variable;
- event.assoc_info.resp_ies_len =
- len - 24 - sizeof(mgmt->u.assoc_resp);
- }
-
- event.assoc_info.freq = drv->assoc_freq;
-
- wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
-}
-
-
-static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
- enum nl80211_commands cmd, struct nlattr *status,
- struct nlattr *addr, struct nlattr *req_ie,
- struct nlattr *resp_ie)
-{
- union wpa_event_data event;
- u16 status_code;
-
- if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
- /*
- * Avoid reporting two association events that would confuse
- * the core code.
- */
- wpa_printf(MSG_DEBUG, "nl80211: Ignore connect event (cmd=%d) "
- "when using userspace SME", cmd);
- return;
- }
-
- status_code = status ? nla_get_u16(status) : WLAN_STATUS_SUCCESS;
-
- if (cmd == NL80211_CMD_CONNECT) {
- wpa_printf(MSG_DEBUG,
- "nl80211: Connect event (status=%u ignore_next_local_disconnect=%d)",
- status_code, drv->ignore_next_local_disconnect);
- } else if (cmd == NL80211_CMD_ROAM) {
- wpa_printf(MSG_DEBUG, "nl80211: Roam event");
- }
-
- os_memset(&event, 0, sizeof(event));
- if (cmd == NL80211_CMD_CONNECT && status_code != WLAN_STATUS_SUCCESS) {
- if (addr)
- event.assoc_reject.bssid = nla_data(addr);
- if (drv->ignore_next_local_disconnect) {
- drv->ignore_next_local_disconnect = 0;
- if (!event.assoc_reject.bssid ||
- (os_memcmp(event.assoc_reject.bssid,
- drv->auth_attempt_bssid,
- ETH_ALEN) != 0)) {
- /*
- * Ignore the event that came without a BSSID or
- * for the old connection since this is likely
- * not relevant to the new Connect command.
- */
- wpa_printf(MSG_DEBUG,
- "nl80211: Ignore connection failure event triggered during reassociation");
- return;
- }
- }
- if (resp_ie) {
- event.assoc_reject.resp_ies = nla_data(resp_ie);
- event.assoc_reject.resp_ies_len = nla_len(resp_ie);
- }
- event.assoc_reject.status_code = status_code;
- wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
- return;
- }
-
- drv->associated = 1;
- if (addr) {
- os_memcpy(drv->bssid, nla_data(addr), ETH_ALEN);
- os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN);
- }
-
- if (req_ie) {
- event.assoc_info.req_ies = nla_data(req_ie);
- event.assoc_info.req_ies_len = nla_len(req_ie);
- }
- if (resp_ie) {
- event.assoc_info.resp_ies = nla_data(resp_ie);
- event.assoc_info.resp_ies_len = nla_len(resp_ie);
- }
-
- event.assoc_info.freq = nl80211_get_assoc_freq(drv);
-
- wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
-}
-
-
-static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv,
- struct nlattr *reason, struct nlattr *addr,
- struct nlattr *by_ap)
-{
- union wpa_event_data data;
- unsigned int locally_generated = by_ap == NULL;
-
- if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
- /*
- * Avoid reporting two disassociation events that could
- * confuse the core code.
- */
- wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
- "event when using userspace SME");
- return;
- }
-
- if (drv->ignore_next_local_disconnect) {
- drv->ignore_next_local_disconnect = 0;
- if (locally_generated) {
- wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
- "event triggered during reassociation");
- return;
- }
- wpa_printf(MSG_WARNING, "nl80211: Was expecting local "
- "disconnect but got another disconnect "
- "event first");
- }
-
- wpa_printf(MSG_DEBUG, "nl80211: Disconnect event");
- nl80211_mark_disconnected(drv);
- os_memset(&data, 0, sizeof(data));
- if (reason)
- data.deauth_info.reason_code = nla_get_u16(reason);
- data.deauth_info.locally_generated = by_ap == NULL;
- wpa_supplicant_event(drv->ctx, EVENT_DEAUTH, &data);
-}
-
-
-static int calculate_chan_offset(int width, int freq, int cf1, int cf2)
-{
- int freq1 = 0;
-
- switch (convert2width(width)) {
- case CHAN_WIDTH_20_NOHT:
- case CHAN_WIDTH_20:
- return 0;
- case CHAN_WIDTH_40:
- freq1 = cf1 - 10;
- break;
- case CHAN_WIDTH_80:
- freq1 = cf1 - 30;
- break;
- case CHAN_WIDTH_160:
- freq1 = cf1 - 70;
- break;
- case CHAN_WIDTH_UNKNOWN:
- case CHAN_WIDTH_80P80:
- /* FIXME: implement this */
- return 0;
- }
-
- return (abs(freq - freq1) / 20) % 2 == 0 ? 1 : -1;
-}
-
-
-static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
- struct nlattr *ifindex, struct nlattr *freq,
- struct nlattr *type, struct nlattr *bw,
- struct nlattr *cf1, struct nlattr *cf2)
-{
- struct i802_bss *bss;
- union wpa_event_data data;
- int ht_enabled = 1;
- int chan_offset = 0;
- int ifidx;
-
- wpa_printf(MSG_DEBUG, "nl80211: Channel switch event");
-
- if (!freq)
- return;
-
- ifidx = nla_get_u32(ifindex);
- bss = get_bss_ifindex(drv, ifidx);
- if (bss == NULL) {
- wpa_printf(MSG_WARNING, "nl80211: Unknown ifindex (%d) for channel switch, ignoring",
- ifidx);
- return;
- }
-
- if (type) {
- switch (nla_get_u32(type)) {
- case NL80211_CHAN_NO_HT:
- ht_enabled = 0;
- break;
- case NL80211_CHAN_HT20:
- break;
- case NL80211_CHAN_HT40PLUS:
- chan_offset = 1;
- break;
- case NL80211_CHAN_HT40MINUS:
- chan_offset = -1;
- break;
- }
- } else if (bw && cf1) {
- /* This can happen for example with VHT80 ch switch */
- chan_offset = calculate_chan_offset(nla_get_u32(bw),
- nla_get_u32(freq),
- nla_get_u32(cf1),
- cf2 ? nla_get_u32(cf2) : 0);
- } else {
- wpa_printf(MSG_WARNING, "nl80211: Unknown secondary channel information - following channel definition calculations may fail");
- }
-
- os_memset(&data, 0, sizeof(data));
- data.ch_switch.freq = nla_get_u32(freq);
- data.ch_switch.ht_enabled = ht_enabled;
- data.ch_switch.ch_offset = chan_offset;
- if (bw)
- data.ch_switch.ch_width = convert2width(nla_get_u32(bw));
- if (cf1)
- data.ch_switch.cf1 = nla_get_u32(cf1);
- if (cf2)
- data.ch_switch.cf2 = nla_get_u32(cf2);
-
- bss->freq = data.ch_switch.freq;
-
- wpa_supplicant_event(bss->ctx, EVENT_CH_SWITCH, &data);
-}
-
-
-static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv,
- enum nl80211_commands cmd, struct nlattr *addr)
-{
- union wpa_event_data event;
- enum wpa_event_type ev;
-
- if (nla_len(addr) != ETH_ALEN)
- return;
-
- wpa_printf(MSG_DEBUG, "nl80211: MLME event %d; timeout with " MACSTR,
- cmd, MAC2STR((u8 *) nla_data(addr)));
-
- if (cmd == NL80211_CMD_AUTHENTICATE)
- ev = EVENT_AUTH_TIMED_OUT;
- else if (cmd == NL80211_CMD_ASSOCIATE)
- ev = EVENT_ASSOC_TIMED_OUT;
- else
- return;
-
- os_memset(&event, 0, sizeof(event));
- os_memcpy(event.timeout_event.addr, nla_data(addr), ETH_ALEN);
- wpa_supplicant_event(drv->ctx, ev, &event);
-}
-
-
-static void mlme_event_mgmt(struct i802_bss *bss,
- struct nlattr *freq, struct nlattr *sig,
- const u8 *frame, size_t len)
-{
- struct wpa_driver_nl80211_data *drv = bss->drv;
- const struct ieee80211_mgmt *mgmt;
- union wpa_event_data event;
- u16 fc, stype;
- int ssi_signal = 0;
- int rx_freq = 0;
-
- wpa_printf(MSG_MSGDUMP, "nl80211: Frame event");
- mgmt = (const struct ieee80211_mgmt *) frame;
- if (len < 24) {
- wpa_printf(MSG_DEBUG, "nl80211: Too short management frame");
- return;
- }
-
- fc = le_to_host16(mgmt->frame_control);
- stype = WLAN_FC_GET_STYPE(fc);
-
- if (sig)
- ssi_signal = (s32) nla_get_u32(sig);
-
- os_memset(&event, 0, sizeof(event));
- if (freq) {
- event.rx_mgmt.freq = nla_get_u32(freq);
- rx_freq = drv->last_mgmt_freq = event.rx_mgmt.freq;
- }
- wpa_printf(MSG_DEBUG,
- "nl80211: RX frame sa=" MACSTR
- " freq=%d ssi_signal=%d stype=%u (%s) len=%u",
- MAC2STR(mgmt->sa), rx_freq, ssi_signal, stype, fc2str(fc),
- (unsigned int) len);
- event.rx_mgmt.frame = frame;
- event.rx_mgmt.frame_len = len;
- event.rx_mgmt.ssi_signal = ssi_signal;
- event.rx_mgmt.drv_priv = bss;
- wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
-}
-
-
-static void mlme_event_mgmt_tx_status(struct wpa_driver_nl80211_data *drv,
- struct nlattr *cookie, const u8 *frame,
- size_t len, struct nlattr *ack)
-{
- union wpa_event_data event;
- const struct ieee80211_hdr *hdr;
- u16 fc;
-
- wpa_printf(MSG_DEBUG, "nl80211: Frame TX status event");
- if (!is_ap_interface(drv->nlmode)) {
- u64 cookie_val;
-
- if (!cookie)
- return;
-
- cookie_val = nla_get_u64(cookie);
- wpa_printf(MSG_DEBUG, "nl80211: Action TX status:"
- " cookie=0%llx%s (ack=%d)",
- (long long unsigned int) cookie_val,
- cookie_val == drv->send_action_cookie ?
- " (match)" : " (unknown)", ack != NULL);
- if (cookie_val != drv->send_action_cookie)
- return;
- }
-
- hdr = (const struct ieee80211_hdr *) frame;
- fc = le_to_host16(hdr->frame_control);
-
- os_memset(&event, 0, sizeof(event));
- event.tx_status.type = WLAN_FC_GET_TYPE(fc);
- event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
- event.tx_status.dst = hdr->addr1;
- event.tx_status.data = frame;
- event.tx_status.data_len = len;
- event.tx_status.ack = ack != NULL;
- wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event);
-}
-
-
-static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
- enum wpa_event_type type,
- const u8 *frame, size_t len)
-{
- const struct ieee80211_mgmt *mgmt;
- union wpa_event_data event;
- const u8 *bssid = NULL;
- u16 reason_code = 0;
-
- if (type == EVENT_DEAUTH)
- wpa_printf(MSG_DEBUG, "nl80211: Deauthenticate event");
- else
- wpa_printf(MSG_DEBUG, "nl80211: Disassociate event");
-
- mgmt = (const struct ieee80211_mgmt *) frame;
- if (len >= 24) {
- bssid = mgmt->bssid;
-
- if ((drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
- !drv->associated &&
- os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0 &&
- os_memcmp(bssid, drv->auth_attempt_bssid, ETH_ALEN) != 0 &&
- os_memcmp(bssid, drv->prev_bssid, ETH_ALEN) == 0) {
- /*
- * Avoid issues with some roaming cases where
- * disconnection event for the old AP may show up after
- * we have started connection with the new AP.
- */
- wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth/disassoc event from old AP " MACSTR " when already authenticating with " MACSTR,
- MAC2STR(bssid),
- MAC2STR(drv->auth_attempt_bssid));
- return;
- }
-
- if (drv->associated != 0 &&
- os_memcmp(bssid, drv->bssid, ETH_ALEN) != 0 &&
- os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0) {
- /*
- * We have presumably received this deauth as a
- * response to a clear_state_mismatch() outgoing
- * deauth. Don't let it take us offline!
- */
- wpa_printf(MSG_DEBUG, "nl80211: Deauth received "
- "from Unknown BSSID " MACSTR " -- ignoring",
- MAC2STR(bssid));
- return;
- }
- }
-
- nl80211_mark_disconnected(drv);
- os_memset(&event, 0, sizeof(event));
-
- /* Note: Same offset for Reason Code in both frame subtypes */
- if (len >= 24 + sizeof(mgmt->u.deauth))
- reason_code = le_to_host16(mgmt->u.deauth.reason_code);
-
- if (type == EVENT_DISASSOC) {
- event.disassoc_info.locally_generated =
- !os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN);
- event.disassoc_info.addr = bssid;
- event.disassoc_info.reason_code = reason_code;
- if (frame + len > mgmt->u.disassoc.variable) {
- event.disassoc_info.ie = mgmt->u.disassoc.variable;
- event.disassoc_info.ie_len = frame + len -
- mgmt->u.disassoc.variable;
- }
- } else {
- if (drv->ignore_deauth_event) {
- wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth event due to previous forced deauth-during-auth");
- drv->ignore_deauth_event = 0;
- return;
- }
- event.deauth_info.locally_generated =
- !os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN);
- if (drv->ignore_next_local_deauth) {
- drv->ignore_next_local_deauth = 0;
- if (event.deauth_info.locally_generated) {
- wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth event triggered due to own deauth request");
- return;
- }
- wpa_printf(MSG_WARNING, "nl80211: Was expecting local deauth but got another disconnect event first");
- }
- event.deauth_info.addr = bssid;
- event.deauth_info.reason_code = reason_code;
- if (frame + len > mgmt->u.deauth.variable) {
- event.deauth_info.ie = mgmt->u.deauth.variable;
- event.deauth_info.ie_len = frame + len -
- mgmt->u.deauth.variable;
- }
- }
-
- wpa_supplicant_event(drv->ctx, type, &event);
-}
-
-
-static void mlme_event_unprot_disconnect(struct wpa_driver_nl80211_data *drv,
- enum wpa_event_type type,
- const u8 *frame, size_t len)
-{
- const struct ieee80211_mgmt *mgmt;
- union wpa_event_data event;
- u16 reason_code = 0;
-
- if (type == EVENT_UNPROT_DEAUTH)
- wpa_printf(MSG_DEBUG, "nl80211: Unprot Deauthenticate event");
- else
- wpa_printf(MSG_DEBUG, "nl80211: Unprot Disassociate event");
-
- if (len < 24)
- return;
-
- mgmt = (const struct ieee80211_mgmt *) frame;
-
- os_memset(&event, 0, sizeof(event));
- /* Note: Same offset for Reason Code in both frame subtypes */
- if (len >= 24 + sizeof(mgmt->u.deauth))
- reason_code = le_to_host16(mgmt->u.deauth.reason_code);
-
- if (type == EVENT_UNPROT_DISASSOC) {
- event.unprot_disassoc.sa = mgmt->sa;
- event.unprot_disassoc.da = mgmt->da;
- event.unprot_disassoc.reason_code = reason_code;
- } else {
- event.unprot_deauth.sa = mgmt->sa;
- event.unprot_deauth.da = mgmt->da;
- event.unprot_deauth.reason_code = reason_code;
- }
-
- wpa_supplicant_event(drv->ctx, type, &event);
-}
-
-
-static void mlme_event(struct i802_bss *bss,
- enum nl80211_commands cmd, struct nlattr *frame,
- struct nlattr *addr, struct nlattr *timed_out,
- struct nlattr *freq, struct nlattr *ack,
- struct nlattr *cookie, struct nlattr *sig)
-{
- struct wpa_driver_nl80211_data *drv = bss->drv;
- const u8 *data;
- size_t len;
-
- if (timed_out && addr) {
- mlme_timeout_event(drv, cmd, addr);
- return;
- }
-
- if (frame == NULL) {
- wpa_printf(MSG_DEBUG,
- "nl80211: MLME event %d (%s) without frame data",
- cmd, nl80211_command_to_string(cmd));
- return;
- }
-
- data = nla_data(frame);
- len = nla_len(frame);
- if (len < 4 + 2 * ETH_ALEN) {
- wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s("
- MACSTR ") - too short",
- cmd, nl80211_command_to_string(cmd), bss->ifname,
- MAC2STR(bss->addr));
- return;
- }
- wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s(" MACSTR
- ") A1=" MACSTR " A2=" MACSTR, cmd,
- nl80211_command_to_string(cmd), bss->ifname,
- MAC2STR(bss->addr), MAC2STR(data + 4),
- MAC2STR(data + 4 + ETH_ALEN));
- if (cmd != NL80211_CMD_FRAME_TX_STATUS && !(data[4] & 0x01) &&
- os_memcmp(bss->addr, data + 4, ETH_ALEN) != 0 &&
- os_memcmp(bss->addr, data + 4 + ETH_ALEN, ETH_ALEN) != 0) {
- wpa_printf(MSG_MSGDUMP, "nl80211: %s: Ignore MLME frame event "
- "for foreign address", bss->ifname);
- return;
- }
- wpa_hexdump(MSG_MSGDUMP, "nl80211: MLME event frame",
- nla_data(frame), nla_len(frame));
-
- switch (cmd) {
- case NL80211_CMD_AUTHENTICATE:
- mlme_event_auth(drv, nla_data(frame), nla_len(frame));
- break;
- case NL80211_CMD_ASSOCIATE:
- mlme_event_assoc(drv, nla_data(frame), nla_len(frame));
- break;
- case NL80211_CMD_DEAUTHENTICATE:
- mlme_event_deauth_disassoc(drv, EVENT_DEAUTH,
- nla_data(frame), nla_len(frame));
- break;
- case NL80211_CMD_DISASSOCIATE:
- mlme_event_deauth_disassoc(drv, EVENT_DISASSOC,
- nla_data(frame), nla_len(frame));
- break;
- case NL80211_CMD_FRAME:
- mlme_event_mgmt(bss, freq, sig, nla_data(frame),
- nla_len(frame));
- break;
- case NL80211_CMD_FRAME_TX_STATUS:
- mlme_event_mgmt_tx_status(drv, cookie, nla_data(frame),
- nla_len(frame), ack);
- break;
- case NL80211_CMD_UNPROT_DEAUTHENTICATE:
- mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DEAUTH,
- nla_data(frame), nla_len(frame));
- break;
- case NL80211_CMD_UNPROT_DISASSOCIATE:
- mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DISASSOC,
- nla_data(frame), nla_len(frame));
- break;
- default:
- break;
- }
-}
-
-
-static void mlme_event_michael_mic_failure(struct i802_bss *bss,
- struct nlattr *tb[])
-{
- union wpa_event_data data;
-
- wpa_printf(MSG_DEBUG, "nl80211: MLME event Michael MIC failure");
- os_memset(&data, 0, sizeof(data));
- if (tb[NL80211_ATTR_MAC]) {
- wpa_hexdump(MSG_DEBUG, "nl80211: Source MAC address",
- nla_data(tb[NL80211_ATTR_MAC]),
- nla_len(tb[NL80211_ATTR_MAC]));
- data.michael_mic_failure.src = nla_data(tb[NL80211_ATTR_MAC]);
- }
- if (tb[NL80211_ATTR_KEY_SEQ]) {
- wpa_hexdump(MSG_DEBUG, "nl80211: TSC",
- nla_data(tb[NL80211_ATTR_KEY_SEQ]),
- nla_len(tb[NL80211_ATTR_KEY_SEQ]));
- }
- if (tb[NL80211_ATTR_KEY_TYPE]) {
- enum nl80211_key_type key_type =
- nla_get_u32(tb[NL80211_ATTR_KEY_TYPE]);
- wpa_printf(MSG_DEBUG, "nl80211: Key Type %d", key_type);
- if (key_type == NL80211_KEYTYPE_PAIRWISE)
- data.michael_mic_failure.unicast = 1;
- } else
- data.michael_mic_failure.unicast = 1;
-
- if (tb[NL80211_ATTR_KEY_IDX]) {
- u8 key_id = nla_get_u8(tb[NL80211_ATTR_KEY_IDX]);
- wpa_printf(MSG_DEBUG, "nl80211: Key Id %d", key_id);
- }
-
- wpa_supplicant_event(bss->ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
-}
-
-
-static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv,
- struct nlattr *tb[])
-{
- unsigned int freq;
-
- if (tb[NL80211_ATTR_MAC] == NULL) {
- wpa_printf(MSG_DEBUG, "nl80211: No address in IBSS joined "
- "event");
- return;
- }
- os_memcpy(drv->bssid, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
-
- drv->associated = 1;
- wpa_printf(MSG_DEBUG, "nl80211: IBSS " MACSTR " joined",
- MAC2STR(drv->bssid));
-
- freq = nl80211_get_assoc_freq(drv);
- if (freq) {
- wpa_printf(MSG_DEBUG, "nl80211: IBSS on frequency %u MHz",
- freq);
- drv->first_bss->freq = freq;
- }
-
- wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
-}
-
-
-static void mlme_event_remain_on_channel(struct wpa_driver_nl80211_data *drv,
- int cancel_event, struct nlattr *tb[])
-{
- unsigned int freq, chan_type, duration;
- union wpa_event_data data;
- u64 cookie;
-
- if (tb[NL80211_ATTR_WIPHY_FREQ])
- freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
- else
- freq = 0;
-
- if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE])
- chan_type = nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
- else
- chan_type = 0;
-
- if (tb[NL80211_ATTR_DURATION])
- duration = nla_get_u32(tb[NL80211_ATTR_DURATION]);
- else
- duration = 0;
-
- if (tb[NL80211_ATTR_COOKIE])
- cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
- else
- cookie = 0;
-
- wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel event (cancel=%d "
- "freq=%u channel_type=%u duration=%u cookie=0x%llx (%s))",
- cancel_event, freq, chan_type, duration,
- (long long unsigned int) cookie,
- cookie == drv->remain_on_chan_cookie ? "match" : "unknown");
-
- if (cookie != drv->remain_on_chan_cookie)
- return; /* not for us */
-
- if (cancel_event)
- drv->pending_remain_on_chan = 0;
-
- os_memset(&data, 0, sizeof(data));
- data.remain_on_channel.freq = freq;
- data.remain_on_channel.duration = duration;
- wpa_supplicant_event(drv->ctx, cancel_event ?
- EVENT_CANCEL_REMAIN_ON_CHANNEL :
- EVENT_REMAIN_ON_CHANNEL, &data);
-}
-
-
-static void mlme_event_ft_event(struct wpa_driver_nl80211_data *drv,
- struct nlattr *tb[])
-{
- union wpa_event_data data;
-
- os_memset(&data, 0, sizeof(data));
-
- if (tb[NL80211_ATTR_IE]) {
- data.ft_ies.ies = nla_data(tb[NL80211_ATTR_IE]);
- data.ft_ies.ies_len = nla_len(tb[NL80211_ATTR_IE]);
- }
-
- if (tb[NL80211_ATTR_IE_RIC]) {
- data.ft_ies.ric_ies = nla_data(tb[NL80211_ATTR_IE_RIC]);
- data.ft_ies.ric_ies_len = nla_len(tb[NL80211_ATTR_IE_RIC]);
- }
-
- if (tb[NL80211_ATTR_MAC])
- os_memcpy(data.ft_ies.target_ap,
- nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
-
- wpa_printf(MSG_DEBUG, "nl80211: FT event target_ap " MACSTR,
- MAC2STR(data.ft_ies.target_ap));
-
- wpa_supplicant_event(drv->ctx, EVENT_FT_RESPONSE, &data);
-}
-
-
-static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
- struct nlattr *tb[])
-{
- union wpa_event_data event;
- struct nlattr *nl;
- int rem;
- struct scan_info *info;
-#define MAX_REPORT_FREQS 50
- int freqs[MAX_REPORT_FREQS];
- int num_freqs = 0;
-
- if (drv->scan_for_auth) {
- drv->scan_for_auth = 0;
- wpa_printf(MSG_DEBUG, "nl80211: Scan results for missing "
- "cfg80211 BSS entry");
- wpa_driver_nl80211_authenticate_retry(drv);
- return;
- }
-
- os_memset(&event, 0, sizeof(event));
- info = &event.scan_info;
- info->aborted = aborted;
-
- if (tb[NL80211_ATTR_SCAN_SSIDS]) {
- nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_SSIDS], rem) {
- struct wpa_driver_scan_ssid *s =
- &info->ssids[info->num_ssids];
- s->ssid = nla_data(nl);
- s->ssid_len = nla_len(nl);
- wpa_printf(MSG_DEBUG, "nl80211: Scan probed for SSID '%s'",
- wpa_ssid_txt(s->ssid, s->ssid_len));
- info->num_ssids++;
- if (info->num_ssids == WPAS_MAX_SCAN_SSIDS)
- break;
- }
- }
- if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) {
- char msg[200], *pos, *end;
- int res;
-
- pos = msg;
- end = pos + sizeof(msg);
- *pos = '\0';
-
- nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem)
- {
- freqs[num_freqs] = nla_get_u32(nl);
- res = os_snprintf(pos, end - pos, " %d",
- freqs[num_freqs]);
- if (res > 0 && end - pos > res)
- pos += res;
- num_freqs++;
- if (num_freqs == MAX_REPORT_FREQS - 1)
- break;
- }
- info->freqs = freqs;
- info->num_freqs = num_freqs;
- wpa_printf(MSG_DEBUG, "nl80211: Scan included frequencies:%s",
- msg);
- }
- wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event);
-}
-
-
static int get_link_signal(struct nl_msg *msg, void *arg)
{
struct nlattr *tb[NL80211_ATTR_MAX + 1];
@@ -2372,27 +1227,21 @@
}
-static int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv,
- struct wpa_signal_info *sig)
+int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv,
+ struct wpa_signal_info *sig)
{
struct nl_msg *msg;
sig->current_signal = -9999;
sig->current_txrate = 0;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_STATION);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid);
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_STATION)) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
return send_and_recv_msgs(drv, msg, get_link_signal, sig);
- nla_put_failure:
- nlmsg_free(msg);
- return -ENOBUFS;
}
@@ -2440,946 +1289,16 @@
}
-static int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv,
- struct wpa_signal_info *sig_change)
+int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv,
+ struct wpa_signal_info *sig_change)
{
struct nl_msg *msg;
sig_change->current_noise = 9999;
sig_change->frequency = drv->assoc_freq;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
+ msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
return send_and_recv_msgs(drv, msg, get_link_noise, sig_change);
- nla_put_failure:
- nlmsg_free(msg);
- return -ENOBUFS;
-}
-
-
-static int get_noise_for_scan_results(struct nl_msg *msg, void *arg)
-{
- struct nlattr *tb[NL80211_ATTR_MAX + 1];
- struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
- struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
- static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
- [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
- [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
- };
- struct wpa_scan_results *scan_results = arg;
- struct wpa_scan_res *scan_res;
- size_t i;
-
- nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
- genlmsg_attrlen(gnlh, 0), NULL);
-
- if (!tb[NL80211_ATTR_SURVEY_INFO]) {
- wpa_printf(MSG_DEBUG, "nl80211: Survey data missing");
- return NL_SKIP;
- }
-
- if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
- tb[NL80211_ATTR_SURVEY_INFO],
- survey_policy)) {
- wpa_printf(MSG_DEBUG, "nl80211: Failed to parse nested "
- "attributes");
- return NL_SKIP;
- }
-
- if (!sinfo[NL80211_SURVEY_INFO_NOISE])
- return NL_SKIP;
-
- if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
- return NL_SKIP;
-
- for (i = 0; i < scan_results->num; ++i) {
- scan_res = scan_results->res[i];
- if (!scan_res)
- continue;
- if ((int) nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
- scan_res->freq)
- continue;
- if (!(scan_res->flags & WPA_SCAN_NOISE_INVALID))
- continue;
- scan_res->noise = (s8)
- nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
- scan_res->flags &= ~WPA_SCAN_NOISE_INVALID;
- }
-
- return NL_SKIP;
-}
-
-
-static int nl80211_get_noise_for_scan_results(
- struct wpa_driver_nl80211_data *drv,
- struct wpa_scan_results *scan_res)
-{
- struct nl_msg *msg;
-
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
- return send_and_recv_msgs(drv, msg, get_noise_for_scan_results,
- scan_res);
- nla_put_failure:
- nlmsg_free(msg);
- return -ENOBUFS;
-}
-
-
-static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
- struct nlattr *tb[])
-{
- static struct nla_policy cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
- [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
- [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U8 },
- [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
- [NL80211_ATTR_CQM_PKT_LOSS_EVENT] = { .type = NLA_U32 },
- };
- struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1];
- enum nl80211_cqm_rssi_threshold_event event;
- union wpa_event_data ed;
- struct wpa_signal_info sig;
- int res;
-
- if (tb[NL80211_ATTR_CQM] == NULL ||
- nla_parse_nested(cqm, NL80211_ATTR_CQM_MAX, tb[NL80211_ATTR_CQM],
- cqm_policy)) {
- wpa_printf(MSG_DEBUG, "nl80211: Ignore invalid CQM event");
- return;
- }
-
- os_memset(&ed, 0, sizeof(ed));
-
- if (cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]) {
- if (!tb[NL80211_ATTR_MAC])
- return;
- os_memcpy(ed.low_ack.addr, nla_data(tb[NL80211_ATTR_MAC]),
- ETH_ALEN);
- wpa_supplicant_event(drv->ctx, EVENT_STATION_LOW_ACK, &ed);
- return;
- }
-
- if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] == NULL)
- return;
- event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]);
-
- if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH) {
- wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
- "event: RSSI high");
- ed.signal_change.above_threshold = 1;
- } else if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW) {
- wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
- "event: RSSI low");
- ed.signal_change.above_threshold = 0;
- } else
- return;
-
- res = nl80211_get_link_signal(drv, &sig);
- if (res == 0) {
- ed.signal_change.current_signal = sig.current_signal;
- ed.signal_change.current_txrate = sig.current_txrate;
- wpa_printf(MSG_DEBUG, "nl80211: Signal: %d dBm txrate: %d",
- sig.current_signal, sig.current_txrate);
- }
-
- res = nl80211_get_link_noise(drv, &sig);
- if (res == 0) {
- ed.signal_change.current_noise = sig.current_noise;
- wpa_printf(MSG_DEBUG, "nl80211: Noise: %d dBm",
- sig.current_noise);
- }
-
- wpa_supplicant_event(drv->ctx, EVENT_SIGNAL_CHANGE, &ed);
-}
-
-
-static void nl80211_new_station_event(struct wpa_driver_nl80211_data *drv,
- struct nlattr **tb)
-{
- u8 *addr;
- union wpa_event_data data;
-
- if (tb[NL80211_ATTR_MAC] == NULL)
- return;
- addr = nla_data(tb[NL80211_ATTR_MAC]);
- wpa_printf(MSG_DEBUG, "nl80211: New station " MACSTR, MAC2STR(addr));
-
- if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
- u8 *ies = NULL;
- size_t ies_len = 0;
- if (tb[NL80211_ATTR_IE]) {
- ies = nla_data(tb[NL80211_ATTR_IE]);
- ies_len = nla_len(tb[NL80211_ATTR_IE]);
- }
- wpa_hexdump(MSG_DEBUG, "nl80211: Assoc Req IEs", ies, ies_len);
- drv_event_assoc(drv->ctx, addr, ies, ies_len, 0);
- return;
- }
-
- if (drv->nlmode != NL80211_IFTYPE_ADHOC)
- return;
-
- os_memset(&data, 0, sizeof(data));
- os_memcpy(data.ibss_rsn_start.peer, addr, ETH_ALEN);
- wpa_supplicant_event(drv->ctx, EVENT_IBSS_RSN_START, &data);
-}
-
-
-static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv,
- struct nlattr **tb)
-{
- u8 *addr;
- union wpa_event_data data;
-
- if (tb[NL80211_ATTR_MAC] == NULL)
- return;
- addr = nla_data(tb[NL80211_ATTR_MAC]);
- wpa_printf(MSG_DEBUG, "nl80211: Delete station " MACSTR,
- MAC2STR(addr));
-
- if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
- drv_event_disassoc(drv->ctx, addr);
- return;
- }
-
- if (drv->nlmode != NL80211_IFTYPE_ADHOC)
- return;
-
- os_memset(&data, 0, sizeof(data));
- os_memcpy(data.ibss_peer_lost.peer, addr, ETH_ALEN);
- wpa_supplicant_event(drv->ctx, EVENT_IBSS_PEER_LOST, &data);
-}
-
-
-static void nl80211_rekey_offload_event(struct wpa_driver_nl80211_data *drv,
- struct nlattr **tb)
-{
- struct nlattr *rekey_info[NUM_NL80211_REKEY_DATA];
- static struct nla_policy rekey_policy[NUM_NL80211_REKEY_DATA] = {
- [NL80211_REKEY_DATA_KEK] = {
- .minlen = NL80211_KEK_LEN,
- .maxlen = NL80211_KEK_LEN,
- },
- [NL80211_REKEY_DATA_KCK] = {
- .minlen = NL80211_KCK_LEN,
- .maxlen = NL80211_KCK_LEN,
- },
- [NL80211_REKEY_DATA_REPLAY_CTR] = {
- .minlen = NL80211_REPLAY_CTR_LEN,
- .maxlen = NL80211_REPLAY_CTR_LEN,
- },
- };
- union wpa_event_data data;
-
- if (!tb[NL80211_ATTR_MAC])
- return;
- if (!tb[NL80211_ATTR_REKEY_DATA])
- return;
- if (nla_parse_nested(rekey_info, MAX_NL80211_REKEY_DATA,
- tb[NL80211_ATTR_REKEY_DATA], rekey_policy))
- return;
- if (!rekey_info[NL80211_REKEY_DATA_REPLAY_CTR])
- return;
-
- os_memset(&data, 0, sizeof(data));
- data.driver_gtk_rekey.bssid = nla_data(tb[NL80211_ATTR_MAC]);
- wpa_printf(MSG_DEBUG, "nl80211: Rekey offload event for BSSID " MACSTR,
- MAC2STR(data.driver_gtk_rekey.bssid));
- data.driver_gtk_rekey.replay_ctr =
- nla_data(rekey_info[NL80211_REKEY_DATA_REPLAY_CTR]);
- wpa_hexdump(MSG_DEBUG, "nl80211: Rekey offload - Replay Counter",
- data.driver_gtk_rekey.replay_ctr, NL80211_REPLAY_CTR_LEN);
- wpa_supplicant_event(drv->ctx, EVENT_DRIVER_GTK_REKEY, &data);
-}
-
-
-static void nl80211_pmksa_candidate_event(struct wpa_driver_nl80211_data *drv,
- struct nlattr **tb)
-{
- struct nlattr *cand[NUM_NL80211_PMKSA_CANDIDATE];
- static struct nla_policy cand_policy[NUM_NL80211_PMKSA_CANDIDATE] = {
- [NL80211_PMKSA_CANDIDATE_INDEX] = { .type = NLA_U32 },
- [NL80211_PMKSA_CANDIDATE_BSSID] = {
- .minlen = ETH_ALEN,
- .maxlen = ETH_ALEN,
- },
- [NL80211_PMKSA_CANDIDATE_PREAUTH] = { .type = NLA_FLAG },
- };
- union wpa_event_data data;
-
- wpa_printf(MSG_DEBUG, "nl80211: PMKSA candidate event");
-
- if (!tb[NL80211_ATTR_PMKSA_CANDIDATE])
- return;
- if (nla_parse_nested(cand, MAX_NL80211_PMKSA_CANDIDATE,
- tb[NL80211_ATTR_PMKSA_CANDIDATE], cand_policy))
- return;
- if (!cand[NL80211_PMKSA_CANDIDATE_INDEX] ||
- !cand[NL80211_PMKSA_CANDIDATE_BSSID])
- return;
-
- os_memset(&data, 0, sizeof(data));
- os_memcpy(data.pmkid_candidate.bssid,
- nla_data(cand[NL80211_PMKSA_CANDIDATE_BSSID]), ETH_ALEN);
- data.pmkid_candidate.index =
- nla_get_u32(cand[NL80211_PMKSA_CANDIDATE_INDEX]);
- data.pmkid_candidate.preauth =
- cand[NL80211_PMKSA_CANDIDATE_PREAUTH] != NULL;
- wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data);
-}
-
-
-static void nl80211_client_probe_event(struct wpa_driver_nl80211_data *drv,
- struct nlattr **tb)
-{
- union wpa_event_data data;
-
- wpa_printf(MSG_DEBUG, "nl80211: Probe client event");
-
- if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_ACK])
- return;
-
- os_memset(&data, 0, sizeof(data));
- os_memcpy(data.client_poll.addr,
- nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
-
- wpa_supplicant_event(drv->ctx, EVENT_DRIVER_CLIENT_POLL_OK, &data);
-}
-
-
-static void nl80211_tdls_oper_event(struct wpa_driver_nl80211_data *drv,
- struct nlattr **tb)
-{
- union wpa_event_data data;
-
- wpa_printf(MSG_DEBUG, "nl80211: TDLS operation event");
-
- if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_TDLS_OPERATION])
- return;
-
- os_memset(&data, 0, sizeof(data));
- os_memcpy(data.tdls.peer, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
- switch (nla_get_u8(tb[NL80211_ATTR_TDLS_OPERATION])) {
- case NL80211_TDLS_SETUP:
- wpa_printf(MSG_DEBUG, "nl80211: TDLS setup request for peer "
- MACSTR, MAC2STR(data.tdls.peer));
- data.tdls.oper = TDLS_REQUEST_SETUP;
- break;
- case NL80211_TDLS_TEARDOWN:
- wpa_printf(MSG_DEBUG, "nl80211: TDLS teardown request for peer "
- MACSTR, MAC2STR(data.tdls.peer));
- data.tdls.oper = TDLS_REQUEST_TEARDOWN;
- break;
- default:
- wpa_printf(MSG_DEBUG, "nl80211: Unsupported TDLS operatione "
- "event");
- return;
- }
- if (tb[NL80211_ATTR_REASON_CODE]) {
- data.tdls.reason_code =
- nla_get_u16(tb[NL80211_ATTR_REASON_CODE]);
- }
-
- wpa_supplicant_event(drv->ctx, EVENT_TDLS, &data);
-}
-
-
-static void nl80211_stop_ap(struct wpa_driver_nl80211_data *drv,
- struct nlattr **tb)
-{
- wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_UNAVAILABLE, NULL);
-}
-
-
-static void nl80211_connect_failed_event(struct wpa_driver_nl80211_data *drv,
- struct nlattr **tb)
-{
- union wpa_event_data data;
- u32 reason;
-
- wpa_printf(MSG_DEBUG, "nl80211: Connect failed event");
-
- if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_CONN_FAILED_REASON])
- return;
-
- os_memset(&data, 0, sizeof(data));
- os_memcpy(data.connect_failed_reason.addr,
- nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
-
- reason = nla_get_u32(tb[NL80211_ATTR_CONN_FAILED_REASON]);
- switch (reason) {
- case NL80211_CONN_FAIL_MAX_CLIENTS:
- wpa_printf(MSG_DEBUG, "nl80211: Max client reached");
- data.connect_failed_reason.code = MAX_CLIENT_REACHED;
- break;
- case NL80211_CONN_FAIL_BLOCKED_CLIENT:
- wpa_printf(MSG_DEBUG, "nl80211: Blocked client " MACSTR
- " tried to connect",
- MAC2STR(data.connect_failed_reason.addr));
- data.connect_failed_reason.code = BLOCKED_CLIENT;
- break;
- default:
- wpa_printf(MSG_DEBUG, "nl8021l: Unknown connect failed reason "
- "%u", reason);
- return;
- }
-
- wpa_supplicant_event(drv->ctx, EVENT_CONNECT_FAILED_REASON, &data);
-}
-
-
-static void nl80211_radar_event(struct wpa_driver_nl80211_data *drv,
- struct nlattr **tb)
-{
- union wpa_event_data data;
- enum nl80211_radar_event event_type;
-
- if (!tb[NL80211_ATTR_WIPHY_FREQ] || !tb[NL80211_ATTR_RADAR_EVENT])
- return;
-
- os_memset(&data, 0, sizeof(data));
- data.dfs_event.freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
- event_type = nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT]);
-
- /* Check HT params */
- if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
- data.dfs_event.ht_enabled = 1;
- data.dfs_event.chan_offset = 0;
-
- switch (nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE])) {
- case NL80211_CHAN_NO_HT:
- data.dfs_event.ht_enabled = 0;
- break;
- case NL80211_CHAN_HT20:
- break;
- case NL80211_CHAN_HT40PLUS:
- data.dfs_event.chan_offset = 1;
- break;
- case NL80211_CHAN_HT40MINUS:
- data.dfs_event.chan_offset = -1;
- break;
- }
- }
-
- /* Get VHT params */
- if (tb[NL80211_ATTR_CHANNEL_WIDTH])
- data.dfs_event.chan_width =
- convert2width(nla_get_u32(
- tb[NL80211_ATTR_CHANNEL_WIDTH]));
- if (tb[NL80211_ATTR_CENTER_FREQ1])
- data.dfs_event.cf1 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
- if (tb[NL80211_ATTR_CENTER_FREQ2])
- data.dfs_event.cf2 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
-
- wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz, ht: %d, offset: %d, width: %d, cf1: %dMHz, cf2: %dMHz",
- data.dfs_event.freq, data.dfs_event.ht_enabled,
- data.dfs_event.chan_offset, data.dfs_event.chan_width,
- data.dfs_event.cf1, data.dfs_event.cf2);
-
- switch (event_type) {
- case NL80211_RADAR_DETECTED:
- wpa_supplicant_event(drv->ctx, EVENT_DFS_RADAR_DETECTED, &data);
- break;
- case NL80211_RADAR_CAC_FINISHED:
- wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_FINISHED, &data);
- break;
- case NL80211_RADAR_CAC_ABORTED:
- wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_ABORTED, &data);
- break;
- case NL80211_RADAR_NOP_FINISHED:
- wpa_supplicant_event(drv->ctx, EVENT_DFS_NOP_FINISHED, &data);
- break;
- default:
- wpa_printf(MSG_DEBUG, "nl80211: Unknown radar event %d "
- "received", event_type);
- break;
- }
-}
-
-
-static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb,
- int wds)
-{
- struct wpa_driver_nl80211_data *drv = bss->drv;
- union wpa_event_data event;
-
- if (!tb[NL80211_ATTR_MAC])
- return;
-
- os_memset(&event, 0, sizeof(event));
- event.rx_from_unknown.bssid = bss->addr;
- event.rx_from_unknown.addr = nla_data(tb[NL80211_ATTR_MAC]);
- event.rx_from_unknown.wds = wds;
-
- wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
-}
-
-
-static void qca_nl80211_avoid_freq(struct wpa_driver_nl80211_data *drv,
- const u8 *data, size_t len)
-{
- u32 i, count;
- union wpa_event_data event;
- struct wpa_freq_range *range = NULL;
- const struct qca_avoid_freq_list *freq_range;
-
- freq_range = (const struct qca_avoid_freq_list *) data;
- if (len < sizeof(freq_range->count))
- return;
-
- count = freq_range->count;
- if (len < sizeof(freq_range->count) +
- count * sizeof(struct qca_avoid_freq_range)) {
- wpa_printf(MSG_DEBUG, "nl80211: Ignored too short avoid frequency list (len=%u)",
- (unsigned int) len);
- return;
- }
-
- if (count > 0) {
- range = os_calloc(count, sizeof(struct wpa_freq_range));
- if (range == NULL)
- return;
- }
-
- os_memset(&event, 0, sizeof(event));
- for (i = 0; i < count; i++) {
- unsigned int idx = event.freq_range.num;
- range[idx].min = freq_range->range[i].start_freq;
- range[idx].max = freq_range->range[i].end_freq;
- wpa_printf(MSG_DEBUG, "nl80211: Avoid frequency range: %u-%u",
- range[idx].min, range[idx].max);
- if (range[idx].min > range[idx].max) {
- wpa_printf(MSG_DEBUG, "nl80211: Ignore invalid frequency range");
- continue;
- }
- event.freq_range.num++;
- }
- event.freq_range.range = range;
-
- wpa_supplicant_event(drv->ctx, EVENT_AVOID_FREQUENCIES, &event);
-
- os_free(range);
-}
-
-
-static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv,
- u32 subcmd, u8 *data, size_t len)
-{
- switch (subcmd) {
- case QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY:
- qca_nl80211_avoid_freq(drv, data, len);
- break;
- default:
- wpa_printf(MSG_DEBUG,
- "nl80211: Ignore unsupported QCA vendor event %u",
- subcmd);
- break;
- }
-}
-
-
-static void nl80211_vendor_event(struct wpa_driver_nl80211_data *drv,
- struct nlattr **tb)
-{
- u32 vendor_id, subcmd, wiphy = 0;
- int wiphy_idx;
- u8 *data = NULL;
- size_t len = 0;
-
- if (!tb[NL80211_ATTR_VENDOR_ID] ||
- !tb[NL80211_ATTR_VENDOR_SUBCMD])
- return;
-
- vendor_id = nla_get_u32(tb[NL80211_ATTR_VENDOR_ID]);
- subcmd = nla_get_u32(tb[NL80211_ATTR_VENDOR_SUBCMD]);
-
- if (tb[NL80211_ATTR_WIPHY])
- wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
-
- wpa_printf(MSG_DEBUG, "nl80211: Vendor event: wiphy=%u vendor_id=0x%x subcmd=%u",
- wiphy, vendor_id, subcmd);
-
- if (tb[NL80211_ATTR_VENDOR_DATA]) {
- data = nla_data(tb[NL80211_ATTR_VENDOR_DATA]);
- len = nla_len(tb[NL80211_ATTR_VENDOR_DATA]);
- wpa_hexdump(MSG_MSGDUMP, "nl80211: Vendor data", data, len);
- }
-
- wiphy_idx = nl80211_get_wiphy_index(drv->first_bss);
- if (wiphy_idx >= 0 && wiphy_idx != (int) wiphy) {
- wpa_printf(MSG_DEBUG, "nl80211: Ignore vendor event for foreign wiphy %u (own: %d)",
- wiphy, wiphy_idx);
- return;
- }
-
- switch (vendor_id) {
- case OUI_QCA:
- nl80211_vendor_event_qca(drv, subcmd, data, len);
- break;
- default:
- wpa_printf(MSG_DEBUG, "nl80211: Ignore unsupported vendor event");
- break;
- }
-}
-
-
-static void nl80211_reg_change_event(struct wpa_driver_nl80211_data *drv,
- struct nlattr *tb[])
-{
- union wpa_event_data data;
- enum nl80211_reg_initiator init;
-
- wpa_printf(MSG_DEBUG, "nl80211: Regulatory domain change");
-
- if (tb[NL80211_ATTR_REG_INITIATOR] == NULL)
- return;
-
- os_memset(&data, 0, sizeof(data));
- init = nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR]);
- wpa_printf(MSG_DEBUG, " * initiator=%d", init);
- switch (init) {
- case NL80211_REGDOM_SET_BY_CORE:
- data.channel_list_changed.initiator = REGDOM_SET_BY_CORE;
- break;
- case NL80211_REGDOM_SET_BY_USER:
- data.channel_list_changed.initiator = REGDOM_SET_BY_USER;
- break;
- case NL80211_REGDOM_SET_BY_DRIVER:
- data.channel_list_changed.initiator = REGDOM_SET_BY_DRIVER;
- break;
- case NL80211_REGDOM_SET_BY_COUNTRY_IE:
- data.channel_list_changed.initiator = REGDOM_SET_BY_COUNTRY_IE;
- break;
- }
-
- if (tb[NL80211_ATTR_REG_TYPE]) {
- enum nl80211_reg_type type;
- type = nla_get_u8(tb[NL80211_ATTR_REG_TYPE]);
- wpa_printf(MSG_DEBUG, " * type=%d", type);
- switch (type) {
- case NL80211_REGDOM_TYPE_COUNTRY:
- data.channel_list_changed.type = REGDOM_TYPE_COUNTRY;
- break;
- case NL80211_REGDOM_TYPE_WORLD:
- data.channel_list_changed.type = REGDOM_TYPE_WORLD;
- break;
- case NL80211_REGDOM_TYPE_CUSTOM_WORLD:
- data.channel_list_changed.type =
- REGDOM_TYPE_CUSTOM_WORLD;
- break;
- case NL80211_REGDOM_TYPE_INTERSECTION:
- data.channel_list_changed.type =
- REGDOM_TYPE_INTERSECTION;
- break;
- }
- }
-
- if (tb[NL80211_ATTR_REG_ALPHA2]) {
- os_strlcpy(data.channel_list_changed.alpha2,
- nla_get_string(tb[NL80211_ATTR_REG_ALPHA2]),
- sizeof(data.channel_list_changed.alpha2));
- wpa_printf(MSG_DEBUG, " * alpha2=%s",
- data.channel_list_changed.alpha2);
- }
-
- wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED, &data);
-}
-
-
-static void do_process_drv_event(struct i802_bss *bss, int cmd,
- struct nlattr **tb)
-{
- struct wpa_driver_nl80211_data *drv = bss->drv;
- union wpa_event_data data;
-
- wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s",
- cmd, nl80211_command_to_string(cmd), bss->ifname);
-
- if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
- (cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
- cmd == NL80211_CMD_SCAN_ABORTED)) {
- wpa_driver_nl80211_set_mode(drv->first_bss,
- drv->ap_scan_as_station);
- drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
- }
-
- switch (cmd) {
- case NL80211_CMD_TRIGGER_SCAN:
- wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan trigger");
- drv->scan_state = SCAN_STARTED;
- if (drv->scan_for_auth) {
- /*
- * Cannot indicate EVENT_SCAN_STARTED here since we skip
- * EVENT_SCAN_RESULTS in scan_for_auth case and the
- * upper layer implementation could get confused about
- * scanning state.
- */
- wpa_printf(MSG_DEBUG, "nl80211: Do not indicate scan-start event due to internal scan_for_auth");
- break;
- }
- wpa_supplicant_event(drv->ctx, EVENT_SCAN_STARTED, NULL);
- break;
- case NL80211_CMD_START_SCHED_SCAN:
- wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan started");
- drv->scan_state = SCHED_SCAN_STARTED;
- break;
- case NL80211_CMD_SCHED_SCAN_STOPPED:
- wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan stopped");
- drv->scan_state = SCHED_SCAN_STOPPED;
- wpa_supplicant_event(drv->ctx, EVENT_SCHED_SCAN_STOPPED, NULL);
- break;
- case NL80211_CMD_NEW_SCAN_RESULTS:
- wpa_dbg(drv->ctx, MSG_DEBUG,
- "nl80211: New scan results available");
- drv->scan_state = SCAN_COMPLETED;
- drv->scan_complete_events = 1;
- eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
- drv->ctx);
- send_scan_event(drv, 0, tb);
- break;
- case NL80211_CMD_SCHED_SCAN_RESULTS:
- wpa_dbg(drv->ctx, MSG_DEBUG,
- "nl80211: New sched scan results available");
- drv->scan_state = SCHED_SCAN_RESULTS;
- send_scan_event(drv, 0, tb);
- break;
- case NL80211_CMD_SCAN_ABORTED:
- wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan aborted");
- drv->scan_state = SCAN_ABORTED;
- /*
- * Need to indicate that scan results are available in order
- * not to make wpa_supplicant stop its scanning.
- */
- eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
- drv->ctx);
- send_scan_event(drv, 1, tb);
- break;
- case NL80211_CMD_AUTHENTICATE:
- case NL80211_CMD_ASSOCIATE:
- case NL80211_CMD_DEAUTHENTICATE:
- case NL80211_CMD_DISASSOCIATE:
- case NL80211_CMD_FRAME_TX_STATUS:
- case NL80211_CMD_UNPROT_DEAUTHENTICATE:
- case NL80211_CMD_UNPROT_DISASSOCIATE:
- mlme_event(bss, cmd, tb[NL80211_ATTR_FRAME],
- tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
- tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
- tb[NL80211_ATTR_COOKIE],
- tb[NL80211_ATTR_RX_SIGNAL_DBM]);
- break;
- case NL80211_CMD_CONNECT:
- case NL80211_CMD_ROAM:
- mlme_event_connect(drv, cmd,
- tb[NL80211_ATTR_STATUS_CODE],
- tb[NL80211_ATTR_MAC],
- tb[NL80211_ATTR_REQ_IE],
- tb[NL80211_ATTR_RESP_IE]);
- break;
- case NL80211_CMD_CH_SWITCH_NOTIFY:
- mlme_event_ch_switch(drv,
- tb[NL80211_ATTR_IFINDEX],
- tb[NL80211_ATTR_WIPHY_FREQ],
- tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE],
- tb[NL80211_ATTR_CHANNEL_WIDTH],
- tb[NL80211_ATTR_CENTER_FREQ1],
- tb[NL80211_ATTR_CENTER_FREQ2]);
- break;
- case NL80211_CMD_DISCONNECT:
- mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
- tb[NL80211_ATTR_MAC],
- tb[NL80211_ATTR_DISCONNECTED_BY_AP]);
- break;
- case NL80211_CMD_MICHAEL_MIC_FAILURE:
- mlme_event_michael_mic_failure(bss, tb);
- break;
- case NL80211_CMD_JOIN_IBSS:
- mlme_event_join_ibss(drv, tb);
- break;
- case NL80211_CMD_REMAIN_ON_CHANNEL:
- mlme_event_remain_on_channel(drv, 0, tb);
- break;
- case NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL:
- mlme_event_remain_on_channel(drv, 1, tb);
- break;
- case NL80211_CMD_NOTIFY_CQM:
- nl80211_cqm_event(drv, tb);
- break;
- case NL80211_CMD_REG_CHANGE:
- nl80211_reg_change_event(drv, tb);
- break;
- case NL80211_CMD_REG_BEACON_HINT:
- wpa_printf(MSG_DEBUG, "nl80211: Regulatory beacon hint");
- os_memset(&data, 0, sizeof(data));
- data.channel_list_changed.initiator = REGDOM_BEACON_HINT;
- wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED,
- &data);
- break;
- case NL80211_CMD_NEW_STATION:
- nl80211_new_station_event(drv, tb);
- break;
- case NL80211_CMD_DEL_STATION:
- nl80211_del_station_event(drv, tb);
- break;
- case NL80211_CMD_SET_REKEY_OFFLOAD:
- nl80211_rekey_offload_event(drv, tb);
- break;
- case NL80211_CMD_PMKSA_CANDIDATE:
- nl80211_pmksa_candidate_event(drv, tb);
- break;
- case NL80211_CMD_PROBE_CLIENT:
- nl80211_client_probe_event(drv, tb);
- break;
- case NL80211_CMD_TDLS_OPER:
- nl80211_tdls_oper_event(drv, tb);
- break;
- case NL80211_CMD_CONN_FAILED:
- nl80211_connect_failed_event(drv, tb);
- break;
- case NL80211_CMD_FT_EVENT:
- mlme_event_ft_event(drv, tb);
- break;
- case NL80211_CMD_RADAR_DETECT:
- nl80211_radar_event(drv, tb);
- break;
- case NL80211_CMD_STOP_AP:
- nl80211_stop_ap(drv, tb);
- break;
- case NL80211_CMD_VENDOR:
- nl80211_vendor_event(drv, tb);
- break;
- default:
- wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
- "(cmd=%d)", cmd);
- break;
- }
-}
-
-
-static int process_drv_event(struct nl_msg *msg, void *arg)
-{
- struct wpa_driver_nl80211_data *drv = arg;
- struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
- struct nlattr *tb[NL80211_ATTR_MAX + 1];
- struct i802_bss *bss;
- int ifidx = -1;
-
- nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
- genlmsg_attrlen(gnlh, 0), NULL);
-
- if (tb[NL80211_ATTR_IFINDEX]) {
- ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
-
- for (bss = drv->first_bss; bss; bss = bss->next)
- if (ifidx == -1 || ifidx == bss->ifindex) {
- do_process_drv_event(bss, gnlh->cmd, tb);
- return NL_SKIP;
- }
- wpa_printf(MSG_DEBUG,
- "nl80211: Ignored event (cmd=%d) for foreign interface (ifindex %d)",
- gnlh->cmd, ifidx);
- } else if (tb[NL80211_ATTR_WDEV]) {
- u64 wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
- wpa_printf(MSG_DEBUG, "nl80211: Process event on P2P device");
- for (bss = drv->first_bss; bss; bss = bss->next) {
- if (bss->wdev_id_set && wdev_id == bss->wdev_id) {
- do_process_drv_event(bss, gnlh->cmd, tb);
- return NL_SKIP;
- }
- }
- wpa_printf(MSG_DEBUG,
- "nl80211: Ignored event (cmd=%d) for foreign interface (wdev 0x%llx)",
- gnlh->cmd, (long long unsigned int) wdev_id);
- }
-
- return NL_SKIP;
-}
-
-
-static int process_global_event(struct nl_msg *msg, void *arg)
-{
- struct nl80211_global *global = arg;
- struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
- struct nlattr *tb[NL80211_ATTR_MAX + 1];
- struct wpa_driver_nl80211_data *drv, *tmp;
- int ifidx = -1;
- struct i802_bss *bss;
- u64 wdev_id = 0;
- int wdev_id_set = 0;
-
- nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
- genlmsg_attrlen(gnlh, 0), NULL);
-
- if (tb[NL80211_ATTR_IFINDEX])
- ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
- else if (tb[NL80211_ATTR_WDEV]) {
- wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
- wdev_id_set = 1;
- }
-
- dl_list_for_each_safe(drv, tmp, &global->interfaces,
- struct wpa_driver_nl80211_data, list) {
- for (bss = drv->first_bss; bss; bss = bss->next) {
- if ((ifidx == -1 && !wdev_id_set) ||
- ifidx == bss->ifindex ||
- (wdev_id_set && bss->wdev_id_set &&
- wdev_id == bss->wdev_id)) {
- do_process_drv_event(bss, gnlh->cmd, tb);
- return NL_SKIP;
- }
- }
- }
-
- return NL_SKIP;
-}
-
-
-static int process_bss_event(struct nl_msg *msg, void *arg)
-{
- struct i802_bss *bss = arg;
- struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
- struct nlattr *tb[NL80211_ATTR_MAX + 1];
-
- nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
- genlmsg_attrlen(gnlh, 0), NULL);
-
- wpa_printf(MSG_DEBUG, "nl80211: BSS Event %d (%s) received for %s",
- gnlh->cmd, nl80211_command_to_string(gnlh->cmd),
- bss->ifname);
-
- switch (gnlh->cmd) {
- case NL80211_CMD_FRAME:
- case NL80211_CMD_FRAME_TX_STATUS:
- mlme_event(bss, gnlh->cmd, tb[NL80211_ATTR_FRAME],
- tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
- tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
- tb[NL80211_ATTR_COOKIE],
- tb[NL80211_ATTR_RX_SIGNAL_DBM]);
- break;
- case NL80211_CMD_UNEXPECTED_FRAME:
- nl80211_spurious_frame(bss, tb, 0);
- break;
- case NL80211_CMD_UNEXPECTED_4ADDR_FRAME:
- nl80211_spurious_frame(bss, tb, 1);
- break;
- default:
- wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
- "(cmd=%d)", gnlh->cmd);
- break;
- }
-
- return NL_SKIP;
}
@@ -3423,15 +1342,14 @@
alpha2[1] = alpha2_arg[1];
alpha2[2] = '\0';
- nl80211_cmd(drv, msg, 0, NL80211_CMD_REQ_SET_REG);
-
- NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, alpha2);
+ if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_REQ_SET_REG) ||
+ nla_put_string(msg, NL80211_ATTR_REG_ALPHA2, alpha2)) {
+ nlmsg_free(msg);
+ return -EINVAL;
+ }
if (send_and_recv_msgs(drv, msg, NULL, NULL))
return -EINVAL;
return 0;
-nla_put_failure:
- nlmsg_free(msg);
- return -EINVAL;
}
@@ -3473,709 +1391,6 @@
}
-static int protocol_feature_handler(struct nl_msg *msg, void *arg)
-{
- u32 *feat = arg;
- struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
- struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
-
- nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
- genlmsg_attrlen(gnlh, 0), NULL);
-
- if (tb_msg[NL80211_ATTR_PROTOCOL_FEATURES])
- *feat = nla_get_u32(tb_msg[NL80211_ATTR_PROTOCOL_FEATURES]);
-
- return NL_SKIP;
-}
-
-
-static u32 get_nl80211_protocol_features(struct wpa_driver_nl80211_data *drv)
-{
- u32 feat = 0;
- struct nl_msg *msg;
-
- msg = nlmsg_alloc();
- if (!msg)
- goto nla_put_failure;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_PROTOCOL_FEATURES);
- if (send_and_recv_msgs(drv, msg, protocol_feature_handler, &feat) == 0)
- return feat;
-
- msg = NULL;
-nla_put_failure:
- nlmsg_free(msg);
- return 0;
-}
-
-
-struct wiphy_info_data {
- struct wpa_driver_nl80211_data *drv;
- struct wpa_driver_capa *capa;
-
- unsigned int num_multichan_concurrent;
-
- unsigned int error:1;
- unsigned int device_ap_sme:1;
- unsigned int poll_command_supported:1;
- unsigned int data_tx_status:1;
- unsigned int monitor_supported:1;
- unsigned int auth_supported:1;
- unsigned int connect_supported:1;
- unsigned int p2p_go_supported:1;
- unsigned int p2p_client_supported:1;
- unsigned int p2p_concurrent:1;
- unsigned int channel_switch_supported:1;
- unsigned int set_qos_map_supported:1;
- unsigned int have_low_prio_scan:1;
-};
-
-
-static unsigned int probe_resp_offload_support(int supp_protocols)
-{
- unsigned int prot = 0;
-
- if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS)
- prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS;
- if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2)
- prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2;
- if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P)
- prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P;
- if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U)
- prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING;
-
- return prot;
-}
-
-
-static void wiphy_info_supported_iftypes(struct wiphy_info_data *info,
- struct nlattr *tb)
-{
- struct nlattr *nl_mode;
- int i;
-
- if (tb == NULL)
- return;
-
- nla_for_each_nested(nl_mode, tb, i) {
- switch (nla_type(nl_mode)) {
- case NL80211_IFTYPE_AP:
- info->capa->flags |= WPA_DRIVER_FLAGS_AP;
- break;
- case NL80211_IFTYPE_ADHOC:
- info->capa->flags |= WPA_DRIVER_FLAGS_IBSS;
- break;
- case NL80211_IFTYPE_P2P_DEVICE:
- info->capa->flags |=
- WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE;
- break;
- case NL80211_IFTYPE_P2P_GO:
- info->p2p_go_supported = 1;
- break;
- case NL80211_IFTYPE_P2P_CLIENT:
- info->p2p_client_supported = 1;
- break;
- case NL80211_IFTYPE_MONITOR:
- info->monitor_supported = 1;
- break;
- }
- }
-}
-
-
-static int wiphy_info_iface_comb_process(struct wiphy_info_data *info,
- struct nlattr *nl_combi)
-{
- struct nlattr *tb_comb[NUM_NL80211_IFACE_COMB];
- struct nlattr *tb_limit[NUM_NL80211_IFACE_LIMIT];
- struct nlattr *nl_limit, *nl_mode;
- int err, rem_limit, rem_mode;
- int combination_has_p2p = 0, combination_has_mgd = 0;
- static struct nla_policy
- iface_combination_policy[NUM_NL80211_IFACE_COMB] = {
- [NL80211_IFACE_COMB_LIMITS] = { .type = NLA_NESTED },
- [NL80211_IFACE_COMB_MAXNUM] = { .type = NLA_U32 },
- [NL80211_IFACE_COMB_STA_AP_BI_MATCH] = { .type = NLA_FLAG },
- [NL80211_IFACE_COMB_NUM_CHANNELS] = { .type = NLA_U32 },
- [NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS] = { .type = NLA_U32 },
- },
- iface_limit_policy[NUM_NL80211_IFACE_LIMIT] = {
- [NL80211_IFACE_LIMIT_TYPES] = { .type = NLA_NESTED },
- [NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 },
- };
-
- err = nla_parse_nested(tb_comb, MAX_NL80211_IFACE_COMB,
- nl_combi, iface_combination_policy);
- if (err || !tb_comb[NL80211_IFACE_COMB_LIMITS] ||
- !tb_comb[NL80211_IFACE_COMB_MAXNUM] ||
- !tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS])
- return 0; /* broken combination */
-
- if (tb_comb[NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS])
- info->capa->flags |= WPA_DRIVER_FLAGS_RADAR;
-
- nla_for_each_nested(nl_limit, tb_comb[NL80211_IFACE_COMB_LIMITS],
- rem_limit) {
- err = nla_parse_nested(tb_limit, MAX_NL80211_IFACE_LIMIT,
- nl_limit, iface_limit_policy);
- if (err || !tb_limit[NL80211_IFACE_LIMIT_TYPES])
- return 0; /* broken combination */
-
- nla_for_each_nested(nl_mode,
- tb_limit[NL80211_IFACE_LIMIT_TYPES],
- rem_mode) {
- int ift = nla_type(nl_mode);
- if (ift == NL80211_IFTYPE_P2P_GO ||
- ift == NL80211_IFTYPE_P2P_CLIENT)
- combination_has_p2p = 1;
- if (ift == NL80211_IFTYPE_STATION)
- combination_has_mgd = 1;
- }
- if (combination_has_p2p && combination_has_mgd)
- break;
- }
-
- if (combination_has_p2p && combination_has_mgd) {
- unsigned int num_channels =
- nla_get_u32(tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]);
-
- info->p2p_concurrent = 1;
- if (info->num_multichan_concurrent < num_channels)
- info->num_multichan_concurrent = num_channels;
- }
-
- return 0;
-}
-
-
-static void wiphy_info_iface_comb(struct wiphy_info_data *info,
- struct nlattr *tb)
-{
- struct nlattr *nl_combi;
- int rem_combi;
-
- if (tb == NULL)
- return;
-
- nla_for_each_nested(nl_combi, tb, rem_combi) {
- if (wiphy_info_iface_comb_process(info, nl_combi) > 0)
- break;
- }
-}
-
-
-static void wiphy_info_supp_cmds(struct wiphy_info_data *info,
- struct nlattr *tb)
-{
- struct nlattr *nl_cmd;
- int i;
-
- if (tb == NULL)
- return;
-
- nla_for_each_nested(nl_cmd, tb, i) {
- switch (nla_get_u32(nl_cmd)) {
- case NL80211_CMD_AUTHENTICATE:
- info->auth_supported = 1;
- break;
- case NL80211_CMD_CONNECT:
- info->connect_supported = 1;
- break;
- case NL80211_CMD_START_SCHED_SCAN:
- info->capa->sched_scan_supported = 1;
- break;
- case NL80211_CMD_PROBE_CLIENT:
- info->poll_command_supported = 1;
- break;
- case NL80211_CMD_CHANNEL_SWITCH:
- info->channel_switch_supported = 1;
- break;
- case NL80211_CMD_SET_QOS_MAP:
- info->set_qos_map_supported = 1;
- break;
- }
- }
-}
-
-
-static void wiphy_info_cipher_suites(struct wiphy_info_data *info,
- struct nlattr *tb)
-{
- int i, num;
- u32 *ciphers;
-
- if (tb == NULL)
- return;
-
- num = nla_len(tb) / sizeof(u32);
- ciphers = nla_data(tb);
- for (i = 0; i < num; i++) {
- u32 c = ciphers[i];
-
- wpa_printf(MSG_DEBUG, "nl80211: Supported cipher %02x-%02x-%02x:%d",
- c >> 24, (c >> 16) & 0xff,
- (c >> 8) & 0xff, c & 0xff);
- switch (c) {
- case WLAN_CIPHER_SUITE_CCMP_256:
- info->capa->enc |= WPA_DRIVER_CAPA_ENC_CCMP_256;
- break;
- case WLAN_CIPHER_SUITE_GCMP_256:
- info->capa->enc |= WPA_DRIVER_CAPA_ENC_GCMP_256;
- break;
- case WLAN_CIPHER_SUITE_CCMP:
- info->capa->enc |= WPA_DRIVER_CAPA_ENC_CCMP;
- break;
- case WLAN_CIPHER_SUITE_GCMP:
- info->capa->enc |= WPA_DRIVER_CAPA_ENC_GCMP;
- break;
- case WLAN_CIPHER_SUITE_TKIP:
- info->capa->enc |= WPA_DRIVER_CAPA_ENC_TKIP;
- break;
- case WLAN_CIPHER_SUITE_WEP104:
- info->capa->enc |= WPA_DRIVER_CAPA_ENC_WEP104;
- break;
- case WLAN_CIPHER_SUITE_WEP40:
- info->capa->enc |= WPA_DRIVER_CAPA_ENC_WEP40;
- break;
- case WLAN_CIPHER_SUITE_AES_CMAC:
- info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP;
- break;
- case WLAN_CIPHER_SUITE_BIP_GMAC_128:
- info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_GMAC_128;
- break;
- case WLAN_CIPHER_SUITE_BIP_GMAC_256:
- info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_GMAC_256;
- break;
- case WLAN_CIPHER_SUITE_BIP_CMAC_256:
- info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_CMAC_256;
- break;
- case WLAN_CIPHER_SUITE_NO_GROUP_ADDR:
- info->capa->enc |= WPA_DRIVER_CAPA_ENC_GTK_NOT_USED;
- break;
- }
- }
-}
-
-
-static void wiphy_info_max_roc(struct wpa_driver_capa *capa,
- struct nlattr *tb)
-{
- if (tb)
- capa->max_remain_on_chan = nla_get_u32(tb);
-}
-
-
-static void wiphy_info_tdls(struct wpa_driver_capa *capa, struct nlattr *tdls,
- struct nlattr *ext_setup)
-{
- if (tdls == NULL)
- return;
-
- wpa_printf(MSG_DEBUG, "nl80211: TDLS supported");
- capa->flags |= WPA_DRIVER_FLAGS_TDLS_SUPPORT;
-
- if (ext_setup) {
- wpa_printf(MSG_DEBUG, "nl80211: TDLS external setup");
- capa->flags |= WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP;
- }
-}
-
-
-static void wiphy_info_feature_flags(struct wiphy_info_data *info,
- struct nlattr *tb)
-{
- u32 flags;
- struct wpa_driver_capa *capa = info->capa;
-
- if (tb == NULL)
- return;
-
- flags = nla_get_u32(tb);
-
- if (flags & NL80211_FEATURE_SK_TX_STATUS)
- info->data_tx_status = 1;
-
- if (flags & NL80211_FEATURE_INACTIVITY_TIMER)
- capa->flags |= WPA_DRIVER_FLAGS_INACTIVITY_TIMER;
-
- if (flags & NL80211_FEATURE_SAE)
- capa->flags |= WPA_DRIVER_FLAGS_SAE;
-
- if (flags & NL80211_FEATURE_NEED_OBSS_SCAN)
- capa->flags |= WPA_DRIVER_FLAGS_OBSS_SCAN;
-
- if (flags & NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE)
- capa->flags |= WPA_DRIVER_FLAGS_HT_2040_COEX;
-
- if (flags & NL80211_FEATURE_LOW_PRIORITY_SCAN)
- info->have_low_prio_scan = 1;
-}
-
-
-static void wiphy_info_probe_resp_offload(struct wpa_driver_capa *capa,
- struct nlattr *tb)
-{
- u32 protocols;
-
- if (tb == NULL)
- return;
-
- protocols = nla_get_u32(tb);
- wpa_printf(MSG_DEBUG, "nl80211: Supports Probe Response offload in AP "
- "mode");
- capa->flags |= WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD;
- capa->probe_resp_offloads = probe_resp_offload_support(protocols);
-}
-
-
-static void wiphy_info_wowlan_triggers(struct wpa_driver_capa *capa,
- struct nlattr *tb)
-{
- struct nlattr *triggers[MAX_NL80211_WOWLAN_TRIG + 1];
-
- if (tb == NULL)
- return;
-
- if (nla_parse_nested(triggers, MAX_NL80211_WOWLAN_TRIG,
- tb, NULL))
- return;
-
- if (triggers[NL80211_WOWLAN_TRIG_ANY])
- capa->wowlan_triggers.any = 1;
- if (triggers[NL80211_WOWLAN_TRIG_DISCONNECT])
- capa->wowlan_triggers.disconnect = 1;
- if (triggers[NL80211_WOWLAN_TRIG_MAGIC_PKT])
- capa->wowlan_triggers.magic_pkt = 1;
- if (triggers[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE])
- capa->wowlan_triggers.gtk_rekey_failure = 1;
- if (triggers[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST])
- capa->wowlan_triggers.eap_identity_req = 1;
- if (triggers[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE])
- capa->wowlan_triggers.four_way_handshake = 1;
- if (triggers[NL80211_WOWLAN_TRIG_RFKILL_RELEASE])
- capa->wowlan_triggers.rfkill_release = 1;
-}
-
-
-static int wiphy_info_handler(struct nl_msg *msg, void *arg)
-{
- struct nlattr *tb[NL80211_ATTR_MAX + 1];
- struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
- struct wiphy_info_data *info = arg;
- struct wpa_driver_capa *capa = info->capa;
- struct wpa_driver_nl80211_data *drv = info->drv;
-
- nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
- genlmsg_attrlen(gnlh, 0), NULL);
-
- if (tb[NL80211_ATTR_WIPHY_NAME])
- os_strlcpy(drv->phyname,
- nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]),
- sizeof(drv->phyname));
- if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS])
- capa->max_scan_ssids =
- nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]);
-
- if (tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS])
- capa->max_sched_scan_ssids =
- nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]);
-
- if (tb[NL80211_ATTR_MAX_MATCH_SETS])
- capa->max_match_sets =
- nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]);
-
- if (tb[NL80211_ATTR_MAC_ACL_MAX])
- capa->max_acl_mac_addrs =
- nla_get_u8(tb[NL80211_ATTR_MAC_ACL_MAX]);
-
- wiphy_info_supported_iftypes(info, tb[NL80211_ATTR_SUPPORTED_IFTYPES]);
- wiphy_info_iface_comb(info, tb[NL80211_ATTR_INTERFACE_COMBINATIONS]);
- wiphy_info_supp_cmds(info, tb[NL80211_ATTR_SUPPORTED_COMMANDS]);
- wiphy_info_cipher_suites(info, tb[NL80211_ATTR_CIPHER_SUITES]);
-
- if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) {
- wpa_printf(MSG_DEBUG, "nl80211: Using driver-based "
- "off-channel TX");
- capa->flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_TX;
- }
-
- if (tb[NL80211_ATTR_ROAM_SUPPORT]) {
- wpa_printf(MSG_DEBUG, "nl80211: Using driver-based roaming");
- capa->flags |= WPA_DRIVER_FLAGS_BSS_SELECTION;
- }
-
- wiphy_info_max_roc(capa,
- tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]);
-
- if (tb[NL80211_ATTR_SUPPORT_AP_UAPSD])
- capa->flags |= WPA_DRIVER_FLAGS_AP_UAPSD;
-
- wiphy_info_tdls(capa, tb[NL80211_ATTR_TDLS_SUPPORT],
- tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]);
-
- if (tb[NL80211_ATTR_DEVICE_AP_SME])
- info->device_ap_sme = 1;
-
- wiphy_info_feature_flags(info, tb[NL80211_ATTR_FEATURE_FLAGS]);
- wiphy_info_probe_resp_offload(capa,
- tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
-
- if (tb[NL80211_ATTR_EXT_CAPA] && tb[NL80211_ATTR_EXT_CAPA_MASK] &&
- drv->extended_capa == NULL) {
- drv->extended_capa =
- os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA]));
- if (drv->extended_capa) {
- os_memcpy(drv->extended_capa,
- nla_data(tb[NL80211_ATTR_EXT_CAPA]),
- nla_len(tb[NL80211_ATTR_EXT_CAPA]));
- drv->extended_capa_len =
- nla_len(tb[NL80211_ATTR_EXT_CAPA]);
- }
- drv->extended_capa_mask =
- os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA]));
- if (drv->extended_capa_mask) {
- os_memcpy(drv->extended_capa_mask,
- nla_data(tb[NL80211_ATTR_EXT_CAPA]),
- nla_len(tb[NL80211_ATTR_EXT_CAPA]));
- } else {
- os_free(drv->extended_capa);
- drv->extended_capa = NULL;
- drv->extended_capa_len = 0;
- }
- }
-
- if (tb[NL80211_ATTR_VENDOR_DATA]) {
- struct nlattr *nl;
- int rem;
-
- nla_for_each_nested(nl, tb[NL80211_ATTR_VENDOR_DATA], rem) {
- struct nl80211_vendor_cmd_info *vinfo;
- if (nla_len(nl) != sizeof(*vinfo)) {
- wpa_printf(MSG_DEBUG, "nl80211: Unexpected vendor data info");
- continue;
- }
- vinfo = nla_data(nl);
- switch (vinfo->subcmd) {
- case QCA_NL80211_VENDOR_SUBCMD_ROAMING:
- drv->roaming_vendor_cmd_avail = 1;
- break;
- case QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY:
- drv->dfs_vendor_cmd_avail = 1;
- break;
- }
-
- wpa_printf(MSG_DEBUG, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u",
- vinfo->vendor_id, vinfo->subcmd);
- }
- }
-
- if (tb[NL80211_ATTR_VENDOR_EVENTS]) {
- struct nlattr *nl;
- int rem;
-
- nla_for_each_nested(nl, tb[NL80211_ATTR_VENDOR_EVENTS], rem) {
- struct nl80211_vendor_cmd_info *vinfo;
- if (nla_len(nl) != sizeof(*vinfo)) {
- wpa_printf(MSG_DEBUG, "nl80211: Unexpected vendor data info");
- continue;
- }
- vinfo = nla_data(nl);
- wpa_printf(MSG_DEBUG, "nl80211: Supported vendor event: vendor_id=0x%x subcmd=%u",
- vinfo->vendor_id, vinfo->subcmd);
- }
- }
-
- wiphy_info_wowlan_triggers(capa,
- tb[NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED]);
-
- if (tb[NL80211_ATTR_MAX_AP_ASSOC_STA])
- capa->max_stations =
- nla_get_u32(tb[NL80211_ATTR_MAX_AP_ASSOC_STA]);
-
- return NL_SKIP;
-}
-
-
-static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
- struct wiphy_info_data *info)
-{
- u32 feat;
- struct nl_msg *msg;
-
- os_memset(info, 0, sizeof(*info));
- info->capa = &drv->capa;
- info->drv = drv;
-
- msg = nlmsg_alloc();
- if (!msg)
- return -1;
-
- feat = get_nl80211_protocol_features(drv);
- if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
- nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_WIPHY);
- else
- nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
-
- NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
- if (nl80211_set_iface_id(msg, drv->first_bss) < 0)
- goto nla_put_failure;
-
- if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info))
- return -1;
-
- if (info->auth_supported)
- drv->capa.flags |= WPA_DRIVER_FLAGS_SME;
- else if (!info->connect_supported) {
- wpa_printf(MSG_INFO, "nl80211: Driver does not support "
- "authentication/association or connect commands");
- info->error = 1;
- }
-
- if (info->p2p_go_supported && info->p2p_client_supported)
- drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE;
- if (info->p2p_concurrent) {
- wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
- "interface (driver advertised support)");
- drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
- drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
- }
- if (info->num_multichan_concurrent > 1) {
- wpa_printf(MSG_DEBUG, "nl80211: Enable multi-channel "
- "concurrent (driver advertised support)");
- drv->capa.num_multichan_concurrent =
- info->num_multichan_concurrent;
- }
-
- /* default to 5000 since early versions of mac80211 don't set it */
- if (!drv->capa.max_remain_on_chan)
- drv->capa.max_remain_on_chan = 5000;
-
- if (info->channel_switch_supported)
- drv->capa.flags |= WPA_DRIVER_FLAGS_AP_CSA;
-
- return 0;
-nla_put_failure:
- nlmsg_free(msg);
- return -1;
-}
-
-
-static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
-{
- struct wiphy_info_data info;
- if (wpa_driver_nl80211_get_info(drv, &info))
- return -1;
-
- if (info.error)
- return -1;
-
- drv->has_capability = 1;
- drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
- drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
- WPA_DRIVER_AUTH_SHARED |
- WPA_DRIVER_AUTH_LEAP;
-
- drv->capa.flags |= WPA_DRIVER_FLAGS_SANE_ERROR_CODES;
- drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE;
- drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
-
- /*
- * As all cfg80211 drivers must support cases where the AP interface is
- * removed without the knowledge of wpa_supplicant/hostapd, e.g., in
- * case that the user space daemon has crashed, they must be able to
- * cleanup all stations and key entries in the AP tear down flow. Thus,
- * this flag can/should always be set for cfg80211 drivers.
- */
- drv->capa.flags |= WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT;
-
- if (!info.device_ap_sme) {
- drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS;
-
- /*
- * No AP SME is currently assumed to also indicate no AP MLME
- * in the driver/firmware.
- */
- drv->capa.flags |= WPA_DRIVER_FLAGS_AP_MLME;
- }
-
- drv->device_ap_sme = info.device_ap_sme;
- drv->poll_command_supported = info.poll_command_supported;
- drv->data_tx_status = info.data_tx_status;
- if (info.set_qos_map_supported)
- drv->capa.flags |= WPA_DRIVER_FLAGS_QOS_MAPPING;
- drv->have_low_prio_scan = info.have_low_prio_scan;
-
- /*
- * If poll command and tx status are supported, mac80211 is new enough
- * to have everything we need to not need monitor interfaces.
- */
- drv->use_monitor = !info.poll_command_supported || !info.data_tx_status;
-
- if (drv->device_ap_sme && drv->use_monitor) {
- /*
- * Non-mac80211 drivers may not support monitor interface.
- * Make sure we do not get stuck with incorrect capability here
- * by explicitly testing this.
- */
- if (!info.monitor_supported) {
- wpa_printf(MSG_DEBUG, "nl80211: Disable use_monitor "
- "with device_ap_sme since no monitor mode "
- "support detected");
- drv->use_monitor = 0;
- }
- }
-
- /*
- * If we aren't going to use monitor interfaces, but the
- * driver doesn't support data TX status, we won't get TX
- * status for EAPOL frames.
- */
- if (!drv->use_monitor && !info.data_tx_status)
- drv->capa.flags &= ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
-
- return 0;
-}
-
-
-#ifdef ANDROID
-static int android_genl_ctrl_resolve(struct nl_handle *handle,
- const char *name)
-{
- /*
- * Android ICS has very minimal genl_ctrl_resolve() implementation, so
- * need to work around that.
- */
- struct nl_cache *cache = NULL;
- struct genl_family *nl80211 = NULL;
- int id = -1;
-
- if (genl_ctrl_alloc_cache(handle, &cache) < 0) {
- wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
- "netlink cache");
- goto fail;
- }
-
- nl80211 = genl_ctrl_search_by_name(cache, name);
- if (nl80211 == NULL)
- goto fail;
-
- id = genl_family_get_id(nl80211);
-
-fail:
- if (nl80211)
- genl_family_put(nl80211);
- if (cache)
- nl_cache_free(cache);
-
- return id;
-}
-#define genl_ctrl_resolve android_genl_ctrl_resolve
-#endif /* ANDROID */
-
-
static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global)
{
int ret;
@@ -4262,23 +1477,6 @@
}
-static int wpa_driver_nl80211_init_nl(struct wpa_driver_nl80211_data *drv)
-{
- drv->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
- if (!drv->nl_cb) {
- wpa_printf(MSG_ERROR, "nl80211: Failed to alloc cb struct");
- return -1;
- }
-
- nl_cb_set(drv->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
- no_seq_check, NULL);
- nl_cb_set(drv->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
- process_drv_event, drv);
-
- return 0;
-}
-
-
static void wpa_driver_nl80211_rfkill_blocked(void *ctx)
{
wpa_printf(MSG_DEBUG, "nl80211: RFKILL blocked");
@@ -4385,7 +1583,8 @@
static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
void *global_priv, int hostapd,
- const u8 *set_addr)
+ const u8 *set_addr,
+ const char *driver_params)
{
struct wpa_driver_nl80211_data *drv;
struct rfkill_config *rcfg;
@@ -4400,6 +1599,14 @@
drv->ctx = ctx;
drv->hostapd = !!hostapd;
drv->eapol_sock = -1;
+
+ /*
+ * There is no driver capability flag for this, so assume it is
+ * supported and disable this on first attempt to use if the driver
+ * rejects the command due to missing support.
+ */
+ drv->set_rekey_offload = 1;
+
drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);
drv->if_indices = drv->default_if_indices;
@@ -4418,11 +1625,6 @@
drv->eapol_tx_sock = -1;
drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
- if (wpa_driver_nl80211_init_nl(drv)) {
- os_free(drv);
- return NULL;
- }
-
if (nl80211_init_bss(bss))
goto failed;
@@ -4442,7 +1644,7 @@
if (linux_iface_up(drv->global->ioctl_sock, ifname) > 0)
drv->start_iface_up = 1;
- if (wpa_driver_nl80211_finish_drv_init(drv, set_addr, 1))
+ if (wpa_driver_nl80211_finish_drv_init(drv, set_addr, 1, driver_params))
goto failed;
drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
@@ -4491,7 +1693,8 @@
static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
void *global_priv)
{
- return wpa_driver_nl80211_drv_init(ctx, ifname, global_priv, 0, NULL);
+ return wpa_driver_nl80211_drv_init(ctx, ifname, global_priv, 0, NULL,
+ NULL);
}
@@ -4501,54 +1704,42 @@
{
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
- int ret = -1;
+ int ret;
char buf[30];
- msg = nlmsg_alloc();
- if (!msg)
- return -1;
-
buf[0] = '\0';
wpa_snprintf_hex(buf, sizeof(buf), match, match_len);
wpa_printf(MSG_DEBUG, "nl80211: Register frame type=0x%x (%s) nl_handle=%p match=%s",
type, fc2str(type), nl_handle, buf);
- nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_ACTION);
-
- if (nl80211_set_iface_id(msg, bss) < 0)
- goto nla_put_failure;
-
- NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, type);
- NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match);
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_REGISTER_ACTION)) ||
+ nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE, type) ||
+ nla_put(msg, NL80211_ATTR_FRAME_MATCH, match_len, match)) {
+ nlmsg_free(msg);
+ return -1;
+ }
ret = send_and_recv(drv->global, nl_handle, msg, NULL, NULL);
- msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Register frame command "
"failed (type=%u): ret=%d (%s)",
type, ret, strerror(-ret));
wpa_hexdump(MSG_DEBUG, "nl80211: Register frame match",
match, match_len);
- goto nla_put_failure;
}
- ret = 0;
-nla_put_failure:
- nlmsg_free(msg);
return ret;
}
static int nl80211_alloc_mgmt_handle(struct i802_bss *bss)
{
- struct wpa_driver_nl80211_data *drv = bss->drv;
-
if (bss->nl_mgmt) {
wpa_printf(MSG_DEBUG, "nl80211: Mgmt reporting "
"already on! (nl_mgmt=%p)", bss->nl_mgmt);
return -1;
}
- bss->nl_mgmt = nl_create_handle(drv->nl_cb, "mgmt");
+ bss->nl_mgmt = nl_create_handle(bss->nl_cb, "mgmt");
if (bss->nl_mgmt == NULL)
return -1;
@@ -4667,6 +1858,57 @@
ret = -1;
#endif /* CONFIG_HS20 */
+ /* WMM-AC ADDTS Response */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x11\x01", 2) < 0)
+ ret = -1;
+
+ /* WMM-AC DELTS */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x11\x02", 2) < 0)
+ ret = -1;
+
+ /* Radio Measurement - Neighbor Report Response */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x05\x05", 2) < 0)
+ ret = -1;
+
+ /* Radio Measurement - Link Measurement Request */
+ if ((drv->capa.rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION) &&
+ (nl80211_register_action_frame(bss, (u8 *) "\x05\x02", 2) < 0))
+ ret = -1;
+
+ nl80211_mgmt_handle_register_eloop(bss);
+
+ return ret;
+}
+
+
+static int nl80211_mgmt_subscribe_mesh(struct i802_bss *bss)
+{
+ int ret = 0;
+
+ if (nl80211_alloc_mgmt_handle(bss))
+ return -1;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Subscribe to mgmt frames with mesh handle %p",
+ bss->nl_mgmt);
+
+ /* Auth frames for mesh SAE */
+ if (nl80211_register_frame(bss, bss->nl_mgmt,
+ (WLAN_FC_TYPE_MGMT << 2) |
+ (WLAN_FC_STYPE_AUTH << 4),
+ NULL, 0) < 0)
+ ret = -1;
+
+ /* Mesh peering open */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x01", 2) < 0)
+ ret = -1;
+ /* Mesh peering confirm */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x02", 2) < 0)
+ ret = -1;
+ /* Mesh peering close */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x03", 2) < 0)
+ ret = -1;
+
nl80211_mgmt_handle_register_eloop(bss);
return ret;
@@ -4675,29 +1917,16 @@
static int nl80211_register_spurious_class3(struct i802_bss *bss)
{
- struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
- int ret = -1;
+ int ret;
- msg = nlmsg_alloc();
- if (!msg)
- return -1;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_UNEXPECTED_FRAME);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
-
- ret = send_and_recv(drv->global, bss->nl_mgmt, msg, NULL, NULL);
- msg = NULL;
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_UNEXPECTED_FRAME);
+ ret = send_and_recv(bss->drv->global, bss->nl_mgmt, msg, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Register spurious class3 "
"failed: ret=%d (%s)",
ret, strerror(-ret));
- goto nla_put_failure;
}
- ret = 0;
-nla_put_failure:
- nlmsg_free(msg);
return ret;
}
@@ -4792,56 +2021,31 @@
static void nl80211_del_p2pdev(struct i802_bss *bss)
{
- struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
int ret;
- msg = nlmsg_alloc();
- if (!msg)
- return;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_INTERFACE);
- NLA_PUT_U64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
-
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- msg = NULL;
+ msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_DEL_INTERFACE);
+ ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
wpa_printf(MSG_DEBUG, "nl80211: Delete P2P Device %s (0x%llx): %s",
bss->ifname, (long long unsigned int) bss->wdev_id,
strerror(-ret));
-
-nla_put_failure:
- nlmsg_free(msg);
}
static int nl80211_set_p2pdev(struct i802_bss *bss, int start)
{
- struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
- int ret = -1;
+ int ret;
- msg = nlmsg_alloc();
- if (!msg)
- return -1;
-
- if (start)
- nl80211_cmd(drv, msg, 0, NL80211_CMD_START_P2P_DEVICE);
- else
- nl80211_cmd(drv, msg, 0, NL80211_CMD_STOP_P2P_DEVICE);
-
- NLA_PUT_U64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
-
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- msg = NULL;
+ msg = nl80211_cmd_msg(bss, 0, start ? NL80211_CMD_START_P2P_DEVICE :
+ NL80211_CMD_STOP_P2P_DEVICE);
+ ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
wpa_printf(MSG_DEBUG, "nl80211: %s P2P Device %s (0x%llx): %s",
start ? "Start" : "Stop",
bss->ifname, (long long unsigned int) bss->wdev_id,
strerror(-ret));
-
-nla_put_failure:
- nlmsg_free(msg);
return ret;
}
@@ -4863,7 +2067,8 @@
static int
wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
- const u8 *set_addr, int first)
+ const u8 *set_addr, int first,
+ const char *driver_params)
{
struct i802_bss *bss = drv->first_bss;
int send_rfkill_event = 0;
@@ -4884,6 +2089,9 @@
if (wpa_driver_nl80211_capa(drv))
return -1;
+ if (driver_params && nl80211_set_param(bss, driver_params) < 0)
+ return -1;
+
wpa_printf(MSG_DEBUG, "nl80211: interface %s in phy %s",
bss->ifname, drv->phyname);
@@ -4951,19 +2159,10 @@
{
struct nl_msg *msg;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
wpa_printf(MSG_DEBUG, "nl80211: Remove beacon (ifindex=%d)",
drv->ifindex);
- nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_BEACON);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_DEL_BEACON);
return send_and_recv_msgs(drv, msg, NULL, NULL);
- nla_put_failure:
- nlmsg_free(msg);
- return -ENOBUFS;
}
@@ -4978,6 +2177,9 @@
{
struct wpa_driver_nl80211_data *drv = bss->drv;
+ wpa_printf(MSG_INFO, "nl80211: deinit ifname=%s disabled_11b_rates=%d",
+ bss->ifname, drv->disabled_11b_rates);
+
bss->in_deinit = 1;
if (drv->data_tx_status)
eloop_unregister_read_sock(drv->eapol_tx_sock);
@@ -4996,6 +2198,11 @@
nl80211_handle_destroy(drv->rtnl_sk);
}
if (bss->added_bridge) {
+ if (linux_set_iface_flags(drv->global->ioctl_sock, bss->brname,
+ 0) < 0)
+ wpa_printf(MSG_INFO,
+ "nl80211: Could not set bridge %s down",
+ bss->brname);
if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
wpa_printf(MSG_INFO, "nl80211: Failed to remove "
"bridge %s: %s",
@@ -5029,7 +2236,11 @@
(void) i802_set_iface_flags(bss, 0);
if (drv->addr_changed) {
- linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0);
+ if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname,
+ 0) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Could not set interface down to restore permanent MAC address");
+ }
if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
drv->perm_addr) < 0) {
wpa_printf(MSG_DEBUG,
@@ -5046,7 +2257,6 @@
nl80211_mgmt_unsubscribe(bss, "deinit");
nl80211_del_p2pdev(bss);
}
- nl_cb_put(drv->nl_cb);
nl80211_destroy_bss(drv->first_bss);
@@ -5064,720 +2274,6 @@
}
-/**
- * wpa_driver_nl80211_scan_timeout - Scan timeout to report scan completion
- * @eloop_ctx: Driver private data
- * @timeout_ctx: ctx argument given to wpa_driver_nl80211_init()
- *
- * This function can be used as registered timeout when starting a scan to
- * generate a scan completed event if the driver does not report this.
- */
-static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
-{
- struct wpa_driver_nl80211_data *drv = eloop_ctx;
- if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED) {
- wpa_driver_nl80211_set_mode(drv->first_bss,
- drv->ap_scan_as_station);
- drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
- }
- wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
- wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
-}
-
-
-static struct nl_msg *
-nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
- struct wpa_driver_scan_params *params, u64 *wdev_id)
-{
- struct nl_msg *msg;
- size_t i;
- u32 scan_flags = 0;
-
- msg = nlmsg_alloc();
- if (!msg)
- return NULL;
-
- nl80211_cmd(drv, msg, 0, cmd);
-
- if (!wdev_id)
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
- else
- NLA_PUT_U64(msg, NL80211_ATTR_WDEV, *wdev_id);
-
- if (params->num_ssids) {
- struct nlattr *ssids;
-
- ssids = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS);
- if (ssids == NULL)
- goto fail;
- for (i = 0; i < params->num_ssids; i++) {
- wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",
- params->ssids[i].ssid,
- params->ssids[i].ssid_len);
- if (nla_put(msg, i + 1, params->ssids[i].ssid_len,
- params->ssids[i].ssid) < 0)
- goto fail;
- }
- nla_nest_end(msg, ssids);
- }
-
- if (params->extra_ies) {
- wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs",
- params->extra_ies, params->extra_ies_len);
- if (nla_put(msg, NL80211_ATTR_IE, params->extra_ies_len,
- params->extra_ies) < 0)
- goto fail;
- }
-
- if (params->freqs) {
- struct nlattr *freqs;
- freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
- if (freqs == NULL)
- goto fail;
- for (i = 0; params->freqs[i]; i++) {
- wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
- "MHz", params->freqs[i]);
- if (nla_put_u32(msg, i + 1, params->freqs[i]) < 0)
- goto fail;
- }
- nla_nest_end(msg, freqs);
- }
-
- os_free(drv->filter_ssids);
- drv->filter_ssids = params->filter_ssids;
- params->filter_ssids = NULL;
- drv->num_filter_ssids = params->num_filter_ssids;
-
- if (params->only_new_results) {
- wpa_printf(MSG_DEBUG, "nl80211: Add NL80211_SCAN_FLAG_FLUSH");
- scan_flags |= NL80211_SCAN_FLAG_FLUSH;
- }
-
- if (params->low_priority && drv->have_low_prio_scan) {
- wpa_printf(MSG_DEBUG,
- "nl80211: Add NL80211_SCAN_FLAG_LOW_PRIORITY");
- scan_flags |= NL80211_SCAN_FLAG_LOW_PRIORITY;
- }
-
- if (scan_flags)
- NLA_PUT_U32(msg, NL80211_ATTR_SCAN_FLAGS, scan_flags);
-
- return msg;
-
-fail:
-nla_put_failure:
- nlmsg_free(msg);
- return NULL;
-}
-
-
-/**
- * wpa_driver_nl80211_scan - Request the driver to initiate scan
- * @bss: Pointer to private driver data from wpa_driver_nl80211_init()
- * @params: Scan parameters
- * Returns: 0 on success, -1 on failure
- */
-static int wpa_driver_nl80211_scan(struct i802_bss *bss,
- struct wpa_driver_scan_params *params)
-{
- struct wpa_driver_nl80211_data *drv = bss->drv;
- int ret = -1, timeout;
- struct nl_msg *msg = NULL;
-
- wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: scan request");
- drv->scan_for_auth = 0;
-
- msg = nl80211_scan_common(drv, NL80211_CMD_TRIGGER_SCAN, params,
- bss->wdev_id_set ? &bss->wdev_id : NULL);
- if (!msg)
- return -1;
-
- if (params->p2p_probe) {
- struct nlattr *rates;
-
- wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates");
-
- rates = nla_nest_start(msg, NL80211_ATTR_SCAN_SUPP_RATES);
- if (rates == NULL)
- goto nla_put_failure;
-
- /*
- * Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates
- * by masking out everything else apart from the OFDM rates 6,
- * 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz
- * rates are left enabled.
- */
- NLA_PUT(msg, NL80211_BAND_2GHZ, 8,
- "\x0c\x12\x18\x24\x30\x48\x60\x6c");
- nla_nest_end(msg, rates);
-
- NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
- }
-
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- msg = NULL;
- if (ret) {
- wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
- "(%s)", ret, strerror(-ret));
- if (drv->hostapd && is_ap_interface(drv->nlmode)) {
- enum nl80211_iftype old_mode = drv->nlmode;
-
- /*
- * mac80211 does not allow scan requests in AP mode, so
- * try to do this in station mode.
- */
- if (wpa_driver_nl80211_set_mode(
- bss, NL80211_IFTYPE_STATION))
- goto nla_put_failure;
-
- if (wpa_driver_nl80211_scan(bss, params)) {
- wpa_driver_nl80211_set_mode(bss, drv->nlmode);
- goto nla_put_failure;
- }
-
- /* Restore AP mode when processing scan results */
- drv->ap_scan_as_station = old_mode;
- ret = 0;
- } else
- goto nla_put_failure;
- }
-
- drv->scan_state = SCAN_REQUESTED;
- /* Not all drivers generate "scan completed" wireless event, so try to
- * read results after a timeout. */
- timeout = 10;
- if (drv->scan_complete_events) {
- /*
- * The driver seems to deliver events to notify when scan is
- * complete, so use longer timeout to avoid race conditions
- * with scanning and following association request.
- */
- timeout = 30;
- }
- wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
- "seconds", ret, timeout);
- eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
- eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout,
- drv, drv->ctx);
-
-nla_put_failure:
- nlmsg_free(msg);
- return ret;
-}
-
-
-/**
- * wpa_driver_nl80211_sched_scan - Initiate a scheduled scan
- * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
- * @params: Scan parameters
- * @interval: Interval between scan cycles in milliseconds
- * Returns: 0 on success, -1 on failure or if not supported
- */
-static int wpa_driver_nl80211_sched_scan(void *priv,
- struct wpa_driver_scan_params *params,
- u32 interval)
-{
- struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
- int ret = -1;
- struct nl_msg *msg;
- size_t i;
-
- wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: sched_scan request");
-
-#ifdef ANDROID
- if (!drv->capa.sched_scan_supported)
- return android_pno_start(bss, params);
-#endif /* ANDROID */
-
- msg = nl80211_scan_common(drv, NL80211_CMD_START_SCHED_SCAN, params,
- bss->wdev_id_set ? &bss->wdev_id : NULL);
- if (!msg)
- goto nla_put_failure;
-
- NLA_PUT_U32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, interval);
-
- if ((drv->num_filter_ssids &&
- (int) drv->num_filter_ssids <= drv->capa.max_match_sets) ||
- params->filter_rssi) {
- struct nlattr *match_sets;
- match_sets = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_MATCH);
- if (match_sets == NULL)
- goto nla_put_failure;
-
- for (i = 0; i < drv->num_filter_ssids; i++) {
- struct nlattr *match_set_ssid;
- wpa_hexdump_ascii(MSG_MSGDUMP,
- "nl80211: Sched scan filter SSID",
- drv->filter_ssids[i].ssid,
- drv->filter_ssids[i].ssid_len);
-
- match_set_ssid = nla_nest_start(msg, i + 1);
- if (match_set_ssid == NULL)
- goto nla_put_failure;
- NLA_PUT(msg, NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
- drv->filter_ssids[i].ssid_len,
- drv->filter_ssids[i].ssid);
- if (params->filter_rssi)
- NLA_PUT_U32(msg,
- NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
- params->filter_rssi);
-
- nla_nest_end(msg, match_set_ssid);
- }
-
- /*
- * Due to backward compatibility code, newer kernels treat this
- * matchset (with only an RSSI filter) as the default for all
- * other matchsets, unless it's the only one, in which case the
- * matchset will actually allow all SSIDs above the RSSI.
- */
- if (params->filter_rssi) {
- struct nlattr *match_set_rssi;
- match_set_rssi = nla_nest_start(msg, 0);
- if (match_set_rssi == NULL)
- goto nla_put_failure;
- NLA_PUT_U32(msg, NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
- params->filter_rssi);
- wpa_printf(MSG_MSGDUMP,
- "nl80211: Sched scan RSSI filter %d dBm",
- params->filter_rssi);
- nla_nest_end(msg, match_set_rssi);
- }
-
- nla_nest_end(msg, match_sets);
- }
-
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-
- /* TODO: if we get an error here, we should fall back to normal scan */
-
- msg = NULL;
- if (ret) {
- wpa_printf(MSG_DEBUG, "nl80211: Sched scan start failed: "
- "ret=%d (%s)", ret, strerror(-ret));
- goto nla_put_failure;
- }
-
- wpa_printf(MSG_DEBUG, "nl80211: Sched scan requested (ret=%d) - "
- "scan interval %d msec", ret, interval);
-
-nla_put_failure:
- nlmsg_free(msg);
- return ret;
-}
-
-
-/**
- * wpa_driver_nl80211_stop_sched_scan - Stop a scheduled scan
- * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
- * Returns: 0 on success, -1 on failure or if not supported
- */
-static int wpa_driver_nl80211_stop_sched_scan(void *priv)
-{
- struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
- int ret = 0;
- struct nl_msg *msg;
-
-#ifdef ANDROID
- if (!drv->capa.sched_scan_supported)
- return android_pno_stop(bss);
-#endif /* ANDROID */
-
- msg = nlmsg_alloc();
- if (!msg)
- return -1;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_STOP_SCHED_SCAN);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- msg = NULL;
- if (ret) {
- wpa_printf(MSG_DEBUG, "nl80211: Sched scan stop failed: "
- "ret=%d (%s)", ret, strerror(-ret));
- goto nla_put_failure;
- }
-
- wpa_printf(MSG_DEBUG, "nl80211: Sched scan stop sent (ret=%d)", ret);
-
-nla_put_failure:
- nlmsg_free(msg);
- return ret;
-}
-
-
-static const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie)
-{
- const u8 *end, *pos;
-
- if (ies == NULL)
- return NULL;
-
- pos = ies;
- end = ies + ies_len;
-
- while (pos + 1 < end) {
- if (pos + 2 + pos[1] > end)
- break;
- if (pos[0] == ie)
- return pos;
- pos += 2 + pos[1];
- }
-
- return NULL;
-}
-
-
-static int nl80211_scan_filtered(struct wpa_driver_nl80211_data *drv,
- const u8 *ie, size_t ie_len)
-{
- const u8 *ssid;
- size_t i;
-
- if (drv->filter_ssids == NULL)
- return 0;
-
- ssid = nl80211_get_ie(ie, ie_len, WLAN_EID_SSID);
- if (ssid == NULL)
- return 1;
-
- for (i = 0; i < drv->num_filter_ssids; i++) {
- if (ssid[1] == drv->filter_ssids[i].ssid_len &&
- os_memcmp(ssid + 2, drv->filter_ssids[i].ssid, ssid[1]) ==
- 0)
- return 0;
- }
-
- return 1;
-}
-
-
-static int bss_info_handler(struct nl_msg *msg, void *arg)
-{
- struct nlattr *tb[NL80211_ATTR_MAX + 1];
- struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
- struct nlattr *bss[NL80211_BSS_MAX + 1];
- static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
- [NL80211_BSS_BSSID] = { .type = NLA_UNSPEC },
- [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
- [NL80211_BSS_TSF] = { .type = NLA_U64 },
- [NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
- [NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
- [NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC },
- [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
- [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
- [NL80211_BSS_STATUS] = { .type = NLA_U32 },
- [NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
- [NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC },
- };
- struct nl80211_bss_info_arg *_arg = arg;
- struct wpa_scan_results *res = _arg->res;
- struct wpa_scan_res **tmp;
- struct wpa_scan_res *r;
- const u8 *ie, *beacon_ie;
- size_t ie_len, beacon_ie_len;
- u8 *pos;
- size_t i;
-
- nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
- genlmsg_attrlen(gnlh, 0), NULL);
- if (!tb[NL80211_ATTR_BSS])
- return NL_SKIP;
- if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
- bss_policy))
- return NL_SKIP;
- if (bss[NL80211_BSS_STATUS]) {
- enum nl80211_bss_status status;
- status = nla_get_u32(bss[NL80211_BSS_STATUS]);
- if (status == NL80211_BSS_STATUS_ASSOCIATED &&
- bss[NL80211_BSS_FREQUENCY]) {
- _arg->assoc_freq =
- nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
- wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz",
- _arg->assoc_freq);
- }
- if (status == NL80211_BSS_STATUS_IBSS_JOINED &&
- bss[NL80211_BSS_FREQUENCY]) {
- _arg->ibss_freq =
- nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
- wpa_printf(MSG_DEBUG, "nl80211: IBSS-joined on %u MHz",
- _arg->ibss_freq);
- }
- if (status == NL80211_BSS_STATUS_ASSOCIATED &&
- bss[NL80211_BSS_BSSID]) {
- os_memcpy(_arg->assoc_bssid,
- nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN);
- wpa_printf(MSG_DEBUG, "nl80211: Associated with "
- MACSTR, MAC2STR(_arg->assoc_bssid));
- }
- }
- if (!res)
- return NL_SKIP;
- if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
- ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
- ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
- } else {
- ie = NULL;
- ie_len = 0;
- }
- if (bss[NL80211_BSS_BEACON_IES]) {
- beacon_ie = nla_data(bss[NL80211_BSS_BEACON_IES]);
- beacon_ie_len = nla_len(bss[NL80211_BSS_BEACON_IES]);
- } else {
- beacon_ie = NULL;
- beacon_ie_len = 0;
- }
-
- if (nl80211_scan_filtered(_arg->drv, ie ? ie : beacon_ie,
- ie ? ie_len : beacon_ie_len))
- return NL_SKIP;
-
- r = os_zalloc(sizeof(*r) + ie_len + beacon_ie_len);
- if (r == NULL)
- return NL_SKIP;
- if (bss[NL80211_BSS_BSSID])
- os_memcpy(r->bssid, nla_data(bss[NL80211_BSS_BSSID]),
- ETH_ALEN);
- if (bss[NL80211_BSS_FREQUENCY])
- r->freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
- if (bss[NL80211_BSS_BEACON_INTERVAL])
- r->beacon_int = nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]);
- if (bss[NL80211_BSS_CAPABILITY])
- r->caps = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
- r->flags |= WPA_SCAN_NOISE_INVALID;
- if (bss[NL80211_BSS_SIGNAL_MBM]) {
- r->level = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
- r->level /= 100; /* mBm to dBm */
- r->flags |= WPA_SCAN_LEVEL_DBM | WPA_SCAN_QUAL_INVALID;
- } else if (bss[NL80211_BSS_SIGNAL_UNSPEC]) {
- r->level = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
- r->flags |= WPA_SCAN_QUAL_INVALID;
- } else
- r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID;
- if (bss[NL80211_BSS_TSF])
- r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]);
- if (bss[NL80211_BSS_SEEN_MS_AGO])
- r->age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]);
- r->ie_len = ie_len;
- pos = (u8 *) (r + 1);
- if (ie) {
- os_memcpy(pos, ie, ie_len);
- pos += ie_len;
- }
- r->beacon_ie_len = beacon_ie_len;
- if (beacon_ie)
- os_memcpy(pos, beacon_ie, beacon_ie_len);
-
- if (bss[NL80211_BSS_STATUS]) {
- enum nl80211_bss_status status;
- status = nla_get_u32(bss[NL80211_BSS_STATUS]);
- switch (status) {
- case NL80211_BSS_STATUS_AUTHENTICATED:
- r->flags |= WPA_SCAN_AUTHENTICATED;
- break;
- case NL80211_BSS_STATUS_ASSOCIATED:
- r->flags |= WPA_SCAN_ASSOCIATED;
- break;
- default:
- break;
- }
- }
-
- /*
- * cfg80211 maintains separate BSS table entries for APs if the same
- * BSSID,SSID pair is seen on multiple channels. wpa_supplicant does
- * not use frequency as a separate key in the BSS table, so filter out
- * duplicated entries. Prefer associated BSS entry in such a case in
- * order to get the correct frequency into the BSS table. Similarly,
- * prefer newer entries over older.
- */
- for (i = 0; i < res->num; i++) {
- const u8 *s1, *s2;
- if (os_memcmp(res->res[i]->bssid, r->bssid, ETH_ALEN) != 0)
- continue;
-
- s1 = nl80211_get_ie((u8 *) (res->res[i] + 1),
- res->res[i]->ie_len, WLAN_EID_SSID);
- s2 = nl80211_get_ie((u8 *) (r + 1), r->ie_len, WLAN_EID_SSID);
- if (s1 == NULL || s2 == NULL || s1[1] != s2[1] ||
- os_memcmp(s1, s2, 2 + s1[1]) != 0)
- continue;
-
- /* Same BSSID,SSID was already included in scan results */
- wpa_printf(MSG_DEBUG, "nl80211: Remove duplicated scan result "
- "for " MACSTR, MAC2STR(r->bssid));
-
- if (((r->flags & WPA_SCAN_ASSOCIATED) &&
- !(res->res[i]->flags & WPA_SCAN_ASSOCIATED)) ||
- r->age < res->res[i]->age) {
- os_free(res->res[i]);
- res->res[i] = r;
- } else
- os_free(r);
- return NL_SKIP;
- }
-
- tmp = os_realloc_array(res->res, res->num + 1,
- sizeof(struct wpa_scan_res *));
- if (tmp == NULL) {
- os_free(r);
- return NL_SKIP;
- }
- tmp[res->num++] = r;
- res->res = tmp;
-
- return NL_SKIP;
-}
-
-
-static void clear_state_mismatch(struct wpa_driver_nl80211_data *drv,
- const u8 *addr)
-{
- if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
- wpa_printf(MSG_DEBUG, "nl80211: Clear possible state "
- "mismatch (" MACSTR ")", MAC2STR(addr));
- wpa_driver_nl80211_mlme(drv, addr,
- NL80211_CMD_DEAUTHENTICATE,
- WLAN_REASON_PREV_AUTH_NOT_VALID, 1);
- }
-}
-
-
-static void wpa_driver_nl80211_check_bss_status(
- struct wpa_driver_nl80211_data *drv, struct wpa_scan_results *res)
-{
- size_t i;
-
- for (i = 0; i < res->num; i++) {
- struct wpa_scan_res *r = res->res[i];
- if (r->flags & WPA_SCAN_AUTHENTICATED) {
- wpa_printf(MSG_DEBUG, "nl80211: Scan results "
- "indicates BSS status with " MACSTR
- " as authenticated",
- MAC2STR(r->bssid));
- if (is_sta_interface(drv->nlmode) &&
- os_memcmp(r->bssid, drv->bssid, ETH_ALEN) != 0 &&
- os_memcmp(r->bssid, drv->auth_bssid, ETH_ALEN) !=
- 0) {
- wpa_printf(MSG_DEBUG, "nl80211: Unknown BSSID"
- " in local state (auth=" MACSTR
- " assoc=" MACSTR ")",
- MAC2STR(drv->auth_bssid),
- MAC2STR(drv->bssid));
- clear_state_mismatch(drv, r->bssid);
- }
- }
-
- if (r->flags & WPA_SCAN_ASSOCIATED) {
- wpa_printf(MSG_DEBUG, "nl80211: Scan results "
- "indicate BSS status with " MACSTR
- " as associated",
- MAC2STR(r->bssid));
- if (is_sta_interface(drv->nlmode) &&
- !drv->associated) {
- wpa_printf(MSG_DEBUG, "nl80211: Local state "
- "(not associated) does not match "
- "with BSS state");
- clear_state_mismatch(drv, r->bssid);
- } else if (is_sta_interface(drv->nlmode) &&
- os_memcmp(drv->bssid, r->bssid, ETH_ALEN) !=
- 0) {
- wpa_printf(MSG_DEBUG, "nl80211: Local state "
- "(associated with " MACSTR ") does "
- "not match with BSS state",
- MAC2STR(drv->bssid));
- clear_state_mismatch(drv, r->bssid);
- clear_state_mismatch(drv, drv->bssid);
- }
- }
- }
-}
-
-
-static struct wpa_scan_results *
-nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
-{
- struct nl_msg *msg;
- struct wpa_scan_results *res;
- int ret;
- struct nl80211_bss_info_arg arg;
-
- res = os_zalloc(sizeof(*res));
- if (res == NULL)
- return NULL;
- msg = nlmsg_alloc();
- if (!msg)
- goto nla_put_failure;
-
- nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
- if (nl80211_set_iface_id(msg, drv->first_bss) < 0)
- goto nla_put_failure;
-
- arg.drv = drv;
- arg.res = res;
- ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
- msg = NULL;
- if (ret == 0) {
- wpa_printf(MSG_DEBUG, "nl80211: Received scan results (%lu "
- "BSSes)", (unsigned long) res->num);
- nl80211_get_noise_for_scan_results(drv, res);
- return res;
- }
- wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
- "(%s)", ret, strerror(-ret));
-nla_put_failure:
- nlmsg_free(msg);
- wpa_scan_results_free(res);
- return NULL;
-}
-
-
-/**
- * wpa_driver_nl80211_get_scan_results - Fetch the latest scan results
- * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
- * Returns: Scan results on success, -1 on failure
- */
-static struct wpa_scan_results *
-wpa_driver_nl80211_get_scan_results(void *priv)
-{
- struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
- struct wpa_scan_results *res;
-
- res = nl80211_get_scan_results(drv);
- if (res)
- wpa_driver_nl80211_check_bss_status(drv, res);
- return res;
-}
-
-
-static void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv)
-{
- struct wpa_scan_results *res;
- size_t i;
-
- res = nl80211_get_scan_results(drv);
- if (res == NULL) {
- wpa_printf(MSG_DEBUG, "nl80211: Failed to get scan results");
- return;
- }
-
- wpa_printf(MSG_DEBUG, "nl80211: Scan result dump");
- for (i = 0; i < res->num; i++) {
- struct wpa_scan_res *r = res->res[i];
- wpa_printf(MSG_DEBUG, "nl80211: %d/%d " MACSTR "%s%s",
- (int) i, (int) res->num, MAC2STR(r->bssid),
- r->flags & WPA_SCAN_AUTHENTICATED ? " [auth]" : "",
- r->flags & WPA_SCAN_ASSOCIATED ? " [assoc]" : "");
- }
-
- wpa_scan_results_free(res);
-}
-
-
static u32 wpa_alg_to_cipher_suite(enum wpa_alg alg, size_t key_len)
{
switch (alg) {
@@ -5869,6 +2365,35 @@
}
+static int issue_key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
+ const u8 *key, size_t key_len)
+{
+ struct nl_msg *msg;
+ int ret;
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD))
+ return 0;
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY) ||
+ nla_put(msg, NL80211_ATTR_VENDOR_DATA, key_len, key)) {
+ nl80211_nlmsg_clear(msg);
+ nlmsg_free(msg);
+ return -1;
+ }
+ ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Key management set key failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ }
+
+ return ret;
+}
+
+
static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
enum wpa_alg alg, const u8 *addr,
int key_idx, int set_tx,
@@ -5897,33 +2422,44 @@
}
#endif /* CONFIG_TDLS */
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
+ if (alg == WPA_ALG_PMK &&
+ (drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD)) {
+ wpa_printf(MSG_DEBUG, "%s: calling issue_key_mgmt_set_key",
+ __func__);
+ ret = issue_key_mgmt_set_key(drv, key, key_len);
+ return ret;
+ }
if (alg == WPA_ALG_NONE) {
- nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_KEY);
+ msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_DEL_KEY);
+ if (!msg)
+ return -ENOBUFS;
} else {
- nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_KEY);
- NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key);
+ msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_NEW_KEY);
+ if (!msg ||
+ nla_put(msg, NL80211_ATTR_KEY_DATA, key_len, key) ||
+ nla_put_u32(msg, NL80211_ATTR_KEY_CIPHER,
+ wpa_alg_to_cipher_suite(alg, key_len)))
+ goto fail;
wpa_hexdump_key(MSG_DEBUG, "nl80211: KEY_DATA", key, key_len);
- NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
- wpa_alg_to_cipher_suite(alg, key_len));
}
if (seq && seq_len) {
- NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, seq_len, seq);
+ if (nla_put(msg, NL80211_ATTR_KEY_SEQ, seq_len, seq))
+ goto fail;
wpa_hexdump(MSG_DEBUG, "nl80211: KEY_SEQ", seq, seq_len);
}
if (addr && !is_broadcast_ether_addr(addr)) {
wpa_printf(MSG_DEBUG, " addr=" MACSTR, MAC2STR(addr));
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+ if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
+ goto fail;
if (alg != WPA_ALG_WEP && key_idx && !set_tx) {
wpa_printf(MSG_DEBUG, " RSN IBSS RX GTK");
- NLA_PUT_U32(msg, NL80211_ATTR_KEY_TYPE,
- NL80211_KEYTYPE_GROUP);
+ if (nla_put_u32(msg, NL80211_ATTR_KEY_TYPE,
+ NL80211_KEYTYPE_GROUP))
+ goto fail;
}
} else if (addr && is_broadcast_ether_addr(addr)) {
struct nlattr *types;
@@ -5931,15 +2467,15 @@
wpa_printf(MSG_DEBUG, " broadcast key");
types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
- if (!types)
- goto nla_put_failure;
- NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
+ if (!types ||
+ nla_put_flag(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST))
+ goto fail;
nla_nest_end(msg, types);
}
- NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
+ if (nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx))
+ goto fail;
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, key ? (void *) -1 : NULL);
if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE)
ret = 0;
if (ret)
@@ -5956,32 +2492,31 @@
!is_broadcast_ether_addr(addr))
return ret;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_KEY);
- NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
- if (alg == WPA_ALG_IGTK)
- NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT_MGMT);
- else
- NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT);
+ msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_SET_KEY);
+ if (!msg ||
+ nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx) ||
+ nla_put_flag(msg, (alg == WPA_ALG_IGTK ||
+ alg == WPA_ALG_BIP_GMAC_128 ||
+ alg == WPA_ALG_BIP_GMAC_256 ||
+ alg == WPA_ALG_BIP_CMAC_256) ?
+ NL80211_ATTR_KEY_DEFAULT_MGMT :
+ NL80211_ATTR_KEY_DEFAULT))
+ goto fail;
if (addr && is_broadcast_ether_addr(addr)) {
struct nlattr *types;
types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
- if (!types)
- goto nla_put_failure;
- NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
+ if (!types ||
+ nla_put_flag(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST))
+ goto fail;
nla_nest_end(msg, types);
} else if (addr) {
struct nlattr *types;
types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
- if (!types)
- goto nla_put_failure;
- NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_UNICAST);
+ if (!types ||
+ nla_put_flag(msg, NL80211_KEY_DEFAULT_TYPE_UNICAST))
+ goto fail;
nla_nest_end(msg, types);
}
@@ -5993,7 +2528,8 @@
"err=%d %s)", ret, strerror(-ret));
return ret;
-nla_put_failure:
+fail:
+ nl80211_nlmsg_clear(msg);
nlmsg_free(msg);
return -ENOBUFS;
}
@@ -6008,26 +2544,25 @@
if (!key_attr)
return -1;
- if (defkey && alg == WPA_ALG_IGTK)
- NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_MGMT);
- else if (defkey)
- NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT);
+ if (defkey && alg == WPA_ALG_IGTK) {
+ if (nla_put_flag(msg, NL80211_KEY_DEFAULT_MGMT))
+ return -1;
+ } else if (defkey) {
+ if (nla_put_flag(msg, NL80211_KEY_DEFAULT))
+ return -1;
+ }
- NLA_PUT_U8(msg, NL80211_KEY_IDX, key_idx);
-
- NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
- wpa_alg_to_cipher_suite(alg, key_len));
-
- if (seq && seq_len)
- NLA_PUT(msg, NL80211_KEY_SEQ, seq_len, seq);
-
- NLA_PUT(msg, NL80211_KEY_DATA, key_len, key);
+ if (nla_put_u8(msg, NL80211_KEY_IDX, key_idx) ||
+ nla_put_u32(msg, NL80211_KEY_CIPHER,
+ wpa_alg_to_cipher_suite(alg, key_len)) ||
+ (seq && seq_len &&
+ nla_put(msg, NL80211_KEY_SEQ, seq_len, seq)) ||
+ nla_put(msg, NL80211_KEY_DATA, key_len, key))
+ return -1;
nla_nest_end(msg, key_attr);
return 0;
- nla_put_failure:
- return -1;
}
@@ -6052,77 +2587,60 @@
if (!privacy)
return 0;
- NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY);
+ if (nla_put_flag(msg, NL80211_ATTR_PRIVACY))
+ return -ENOBUFS;
nl_keys = nla_nest_start(msg, NL80211_ATTR_KEYS);
if (!nl_keys)
- goto nla_put_failure;
+ return -ENOBUFS;
for (i = 0; i < 4; i++) {
if (!params->wep_key[i])
continue;
nl_key = nla_nest_start(msg, i);
- if (!nl_key)
- goto nla_put_failure;
-
- NLA_PUT(msg, NL80211_KEY_DATA, params->wep_key_len[i],
- params->wep_key[i]);
- if (params->wep_key_len[i] == 5)
- NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
- WLAN_CIPHER_SUITE_WEP40);
- else
- NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
- WLAN_CIPHER_SUITE_WEP104);
-
- NLA_PUT_U8(msg, NL80211_KEY_IDX, i);
-
- if (i == params->wep_tx_keyidx)
- NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT);
+ if (!nl_key ||
+ nla_put(msg, NL80211_KEY_DATA, params->wep_key_len[i],
+ params->wep_key[i]) ||
+ nla_put_u32(msg, NL80211_KEY_CIPHER,
+ params->wep_key_len[i] == 5 ?
+ WLAN_CIPHER_SUITE_WEP40 :
+ WLAN_CIPHER_SUITE_WEP104) ||
+ nla_put_u8(msg, NL80211_KEY_IDX, i) ||
+ (i == params->wep_tx_keyidx &&
+ nla_put_flag(msg, NL80211_KEY_DEFAULT)))
+ return -ENOBUFS;
nla_nest_end(msg, nl_key);
}
nla_nest_end(msg, nl_keys);
return 0;
-
-nla_put_failure:
- return -ENOBUFS;
}
-static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
- const u8 *addr, int cmd, u16 reason_code,
- int local_state_change)
+int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
+ const u8 *addr, int cmd, u16 reason_code,
+ int local_state_change)
{
- int ret = -1;
+ int ret;
struct nl_msg *msg;
- msg = nlmsg_alloc();
- if (!msg)
+ if (!(msg = nl80211_drv_msg(drv, 0, cmd)) ||
+ nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code) ||
+ (addr && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) ||
+ (local_state_change &&
+ nla_put_flag(msg, NL80211_ATTR_LOCAL_STATE_CHANGE))) {
+ nlmsg_free(msg);
return -1;
-
- nl80211_cmd(drv, msg, 0, cmd);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
- NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason_code);
- if (addr)
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
- if (local_state_change)
- NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE);
+ }
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- msg = NULL;
if (ret) {
wpa_dbg(drv->ctx, MSG_DEBUG,
"nl80211: MLME command failed: reason=%u ret=%d (%s)",
reason_code, ret, strerror(-ret));
- goto nla_put_failure;
}
- ret = 0;
-
-nla_put_failure:
- nlmsg_free(msg);
return ret;
}
@@ -6155,7 +2673,7 @@
if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
nl80211_mark_disconnected(drv);
- return nl80211_leave_ibss(drv);
+ return nl80211_leave_ibss(drv, 1);
}
if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
return wpa_driver_nl80211_disconnect(drv, reason_code);
@@ -6219,6 +2737,25 @@
}
+static void nl80211_unmask_11b_rates(struct i802_bss *bss)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ if (is_p2p_net_interface(drv->nlmode) || !drv->disabled_11b_rates)
+ return;
+
+ /*
+ * Looks like we failed to unmask 11b rates previously. This could
+ * happen, e.g., if the interface was down at the point in time when a
+ * P2P group was terminated.
+ */
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Interface %s mode is for non-P2P, but 11b rates were disabled - re-enable them",
+ bss->ifname);
+ nl80211_disable_11b_rates(drv, drv->ifindex, 0);
+}
+
+
static int wpa_driver_nl80211_authenticate(
struct i802_bss *bss, struct wpa_driver_auth_params *params)
{
@@ -6230,6 +2767,8 @@
int count = 0;
int is_retry;
+ nl80211_unmask_11b_rates(bss);
+
is_retry = drv->retry_auth;
drv->retry_auth = 0;
drv->ignore_deauth_event = 0;
@@ -6248,14 +2787,12 @@
return -1;
retry:
- msg = nlmsg_alloc();
- if (!msg)
- return -1;
-
wpa_printf(MSG_DEBUG, "nl80211: Authenticate (ifindex=%d)",
drv->ifindex);
- nl80211_cmd(drv, msg, 0, NL80211_CMD_AUTHENTICATE);
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_AUTHENTICATE);
+ if (!msg)
+ goto fail;
for (i = 0; i < 4; i++) {
if (!params->wep_key[i])
@@ -6268,36 +2805,38 @@
if (params->wep_tx_keyidx != i)
continue;
if (nl_add_key(msg, WPA_ALG_WEP, i, 1, NULL, 0,
- params->wep_key[i], params->wep_key_len[i])) {
- nlmsg_free(msg);
- return -1;
- }
+ params->wep_key[i], params->wep_key_len[i]))
+ goto fail;
}
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
if (params->bssid) {
wpa_printf(MSG_DEBUG, " * bssid=" MACSTR,
MAC2STR(params->bssid));
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
+ if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
+ goto fail;
}
if (params->freq) {
wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq))
+ goto fail;
}
if (params->ssid) {
wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
params->ssid, params->ssid_len);
- NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
- params->ssid);
+ if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len,
+ params->ssid))
+ goto fail;
}
wpa_hexdump(MSG_DEBUG, " * IEs", params->ie, params->ie_len);
- if (params->ie)
- NLA_PUT(msg, NL80211_ATTR_IE, params->ie_len, params->ie);
+ if (params->ie &&
+ nla_put(msg, NL80211_ATTR_IE, params->ie_len, params->ie))
+ goto fail;
if (params->sae_data) {
wpa_hexdump(MSG_DEBUG, " * SAE data", params->sae_data,
params->sae_data_len);
- NLA_PUT(msg, NL80211_ATTR_SAE_DATA, params->sae_data_len,
- params->sae_data);
+ if (nla_put(msg, NL80211_ATTR_SAE_DATA, params->sae_data_len,
+ params->sae_data))
+ goto fail;
}
if (params->auth_alg & WPA_AUTH_ALG_OPEN)
type = NL80211_AUTHTYPE_OPEN_SYSTEM;
@@ -6310,12 +2849,14 @@
else if (params->auth_alg & WPA_AUTH_ALG_SAE)
type = NL80211_AUTHTYPE_SAE;
else
- goto nla_put_failure;
+ goto fail;
wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
- NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type);
+ if (nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
+ goto fail;
if (params->local_state_change) {
wpa_printf(MSG_DEBUG, " * Local state change only");
- NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE);
+ if (nla_put_flag(msg, NL80211_ATTR_LOCAL_STATE_CHANGE))
+ goto fail;
}
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -6383,21 +2924,18 @@
wpa_supplicant_event(drv->ctx, EVENT_AUTH_TIMED_OUT,
&event);
}
-
- goto nla_put_failure;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Authentication request send successfully");
}
- ret = 0;
- wpa_printf(MSG_DEBUG, "nl80211: Authentication request send "
- "successfully");
-nla_put_failure:
+fail:
nlmsg_free(msg);
return ret;
}
-static int wpa_driver_nl80211_authenticate_retry(
- struct wpa_driver_nl80211_data *drv)
+int wpa_driver_nl80211_authenticate_retry(struct wpa_driver_nl80211_data *drv)
{
struct wpa_driver_auth_params params;
struct i802_bss *bss = drv->first_bss;
@@ -6435,726 +2973,6 @@
}
-struct phy_info_arg {
- u16 *num_modes;
- struct hostapd_hw_modes *modes;
- int last_mode, last_chan_idx;
-};
-
-static void phy_info_ht_capa(struct hostapd_hw_modes *mode, struct nlattr *capa,
- struct nlattr *ampdu_factor,
- struct nlattr *ampdu_density,
- struct nlattr *mcs_set)
-{
- if (capa)
- mode->ht_capab = nla_get_u16(capa);
-
- if (ampdu_factor)
- mode->a_mpdu_params |= nla_get_u8(ampdu_factor) & 0x03;
-
- if (ampdu_density)
- mode->a_mpdu_params |= nla_get_u8(ampdu_density) << 2;
-
- if (mcs_set && nla_len(mcs_set) >= 16) {
- u8 *mcs;
- mcs = nla_data(mcs_set);
- os_memcpy(mode->mcs_set, mcs, 16);
- }
-}
-
-
-static void phy_info_vht_capa(struct hostapd_hw_modes *mode,
- struct nlattr *capa,
- struct nlattr *mcs_set)
-{
- if (capa)
- mode->vht_capab = nla_get_u32(capa);
-
- if (mcs_set && nla_len(mcs_set) >= 8) {
- u8 *mcs;
- mcs = nla_data(mcs_set);
- os_memcpy(mode->vht_mcs_set, mcs, 8);
- }
-}
-
-
-static void phy_info_freq(struct hostapd_hw_modes *mode,
- struct hostapd_channel_data *chan,
- struct nlattr *tb_freq[])
-{
- u8 channel;
- chan->freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
- chan->flag = 0;
- chan->dfs_cac_ms = 0;
- if (ieee80211_freq_to_chan(chan->freq, &channel) != NUM_HOSTAPD_MODES)
- chan->chan = channel;
-
- if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
- chan->flag |= HOSTAPD_CHAN_DISABLED;
- if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IR])
- chan->flag |= HOSTAPD_CHAN_PASSIVE_SCAN | HOSTAPD_CHAN_NO_IBSS;
- if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR])
- chan->flag |= HOSTAPD_CHAN_RADAR;
-
- if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]) {
- enum nl80211_dfs_state state =
- nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]);
-
- switch (state) {
- case NL80211_DFS_USABLE:
- chan->flag |= HOSTAPD_CHAN_DFS_USABLE;
- break;
- case NL80211_DFS_AVAILABLE:
- chan->flag |= HOSTAPD_CHAN_DFS_AVAILABLE;
- break;
- case NL80211_DFS_UNAVAILABLE:
- chan->flag |= HOSTAPD_CHAN_DFS_UNAVAILABLE;
- break;
- }
- }
-
- if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME]) {
- chan->dfs_cac_ms = nla_get_u32(
- tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME]);
- }
-}
-
-
-static int phy_info_freqs(struct phy_info_arg *phy_info,
- struct hostapd_hw_modes *mode, struct nlattr *tb)
-{
- static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
- [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
- [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG },
- [NL80211_FREQUENCY_ATTR_NO_IR] = { .type = NLA_FLAG },
- [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
- [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
- [NL80211_FREQUENCY_ATTR_DFS_STATE] = { .type = NLA_U32 },
- };
- int new_channels = 0;
- struct hostapd_channel_data *channel;
- struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
- struct nlattr *nl_freq;
- int rem_freq, idx;
-
- if (tb == NULL)
- return NL_OK;
-
- nla_for_each_nested(nl_freq, tb, rem_freq) {
- nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX,
- nla_data(nl_freq), nla_len(nl_freq), freq_policy);
- if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
- continue;
- new_channels++;
- }
-
- channel = os_realloc_array(mode->channels,
- mode->num_channels + new_channels,
- sizeof(struct hostapd_channel_data));
- if (!channel)
- return NL_SKIP;
-
- mode->channels = channel;
- mode->num_channels += new_channels;
-
- idx = phy_info->last_chan_idx;
-
- nla_for_each_nested(nl_freq, tb, rem_freq) {
- nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX,
- nla_data(nl_freq), nla_len(nl_freq), freq_policy);
- if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
- continue;
- phy_info_freq(mode, &mode->channels[idx], tb_freq);
- idx++;
- }
- phy_info->last_chan_idx = idx;
-
- return NL_OK;
-}
-
-
-static int phy_info_rates(struct hostapd_hw_modes *mode, struct nlattr *tb)
-{
- static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = {
- [NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 },
- [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] =
- { .type = NLA_FLAG },
- };
- struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1];
- struct nlattr *nl_rate;
- int rem_rate, idx;
-
- if (tb == NULL)
- return NL_OK;
-
- nla_for_each_nested(nl_rate, tb, rem_rate) {
- nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX,
- nla_data(nl_rate), nla_len(nl_rate),
- rate_policy);
- if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
- continue;
- mode->num_rates++;
- }
-
- mode->rates = os_calloc(mode->num_rates, sizeof(int));
- if (!mode->rates)
- return NL_SKIP;
-
- idx = 0;
-
- nla_for_each_nested(nl_rate, tb, rem_rate) {
- nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX,
- nla_data(nl_rate), nla_len(nl_rate),
- rate_policy);
- if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
- continue;
- mode->rates[idx] = nla_get_u32(
- tb_rate[NL80211_BITRATE_ATTR_RATE]);
- idx++;
- }
-
- return NL_OK;
-}
-
-
-static int phy_info_band(struct phy_info_arg *phy_info, struct nlattr *nl_band)
-{
- struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
- struct hostapd_hw_modes *mode;
- int ret;
-
- if (phy_info->last_mode != nl_band->nla_type) {
- mode = os_realloc_array(phy_info->modes,
- *phy_info->num_modes + 1,
- sizeof(*mode));
- if (!mode)
- return NL_SKIP;
- phy_info->modes = mode;
-
- mode = &phy_info->modes[*(phy_info->num_modes)];
- os_memset(mode, 0, sizeof(*mode));
- mode->mode = NUM_HOSTAPD_MODES;
- mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN |
- HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN;
-
- /*
- * Unsupported VHT MCS stream is defined as value 3, so the VHT
- * MCS RX/TX map must be initialized with 0xffff to mark all 8
- * possible streams as unsupported. This will be overridden if
- * driver advertises VHT support.
- */
- mode->vht_mcs_set[0] = 0xff;
- mode->vht_mcs_set[1] = 0xff;
- mode->vht_mcs_set[4] = 0xff;
- mode->vht_mcs_set[5] = 0xff;
-
- *(phy_info->num_modes) += 1;
- phy_info->last_mode = nl_band->nla_type;
- phy_info->last_chan_idx = 0;
- } else
- mode = &phy_info->modes[*(phy_info->num_modes) - 1];
-
- nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
- nla_len(nl_band), NULL);
-
- phy_info_ht_capa(mode, tb_band[NL80211_BAND_ATTR_HT_CAPA],
- tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR],
- tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY],
- tb_band[NL80211_BAND_ATTR_HT_MCS_SET]);
- phy_info_vht_capa(mode, tb_band[NL80211_BAND_ATTR_VHT_CAPA],
- tb_band[NL80211_BAND_ATTR_VHT_MCS_SET]);
- ret = phy_info_freqs(phy_info, mode, tb_band[NL80211_BAND_ATTR_FREQS]);
- if (ret != NL_OK)
- return ret;
- ret = phy_info_rates(mode, tb_band[NL80211_BAND_ATTR_RATES]);
- if (ret != NL_OK)
- return ret;
-
- return NL_OK;
-}
-
-
-static int phy_info_handler(struct nl_msg *msg, void *arg)
-{
- struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
- struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
- struct phy_info_arg *phy_info = arg;
- struct nlattr *nl_band;
- int rem_band;
-
- nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
- genlmsg_attrlen(gnlh, 0), NULL);
-
- if (!tb_msg[NL80211_ATTR_WIPHY_BANDS])
- return NL_SKIP;
-
- nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band)
- {
- int res = phy_info_band(phy_info, nl_band);
- if (res != NL_OK)
- return res;
- }
-
- return NL_SKIP;
-}
-
-
-static struct hostapd_hw_modes *
-wpa_driver_nl80211_postprocess_modes(struct hostapd_hw_modes *modes,
- u16 *num_modes)
-{
- u16 m;
- struct hostapd_hw_modes *mode11g = NULL, *nmodes, *mode;
- int i, mode11g_idx = -1;
-
- /* heuristic to set up modes */
- for (m = 0; m < *num_modes; m++) {
- if (!modes[m].num_channels)
- continue;
- if (modes[m].channels[0].freq < 4000) {
- modes[m].mode = HOSTAPD_MODE_IEEE80211B;
- for (i = 0; i < modes[m].num_rates; i++) {
- if (modes[m].rates[i] > 200) {
- modes[m].mode = HOSTAPD_MODE_IEEE80211G;
- break;
- }
- }
- } else if (modes[m].channels[0].freq > 50000)
- modes[m].mode = HOSTAPD_MODE_IEEE80211AD;
- else
- modes[m].mode = HOSTAPD_MODE_IEEE80211A;
- }
-
- /* If only 802.11g mode is included, use it to construct matching
- * 802.11b mode data. */
-
- for (m = 0; m < *num_modes; m++) {
- if (modes[m].mode == HOSTAPD_MODE_IEEE80211B)
- return modes; /* 802.11b already included */
- if (modes[m].mode == HOSTAPD_MODE_IEEE80211G)
- mode11g_idx = m;
- }
-
- if (mode11g_idx < 0)
- return modes; /* 2.4 GHz band not supported at all */
-
- nmodes = os_realloc_array(modes, *num_modes + 1, sizeof(*nmodes));
- if (nmodes == NULL)
- return modes; /* Could not add 802.11b mode */
-
- mode = &nmodes[*num_modes];
- os_memset(mode, 0, sizeof(*mode));
- (*num_modes)++;
- modes = nmodes;
-
- mode->mode = HOSTAPD_MODE_IEEE80211B;
-
- mode11g = &modes[mode11g_idx];
- mode->num_channels = mode11g->num_channels;
- mode->channels = os_malloc(mode11g->num_channels *
- sizeof(struct hostapd_channel_data));
- if (mode->channels == NULL) {
- (*num_modes)--;
- return modes; /* Could not add 802.11b mode */
- }
- os_memcpy(mode->channels, mode11g->channels,
- mode11g->num_channels * sizeof(struct hostapd_channel_data));
-
- mode->num_rates = 0;
- mode->rates = os_malloc(4 * sizeof(int));
- if (mode->rates == NULL) {
- os_free(mode->channels);
- (*num_modes)--;
- return modes; /* Could not add 802.11b mode */
- }
-
- for (i = 0; i < mode11g->num_rates; i++) {
- if (mode11g->rates[i] != 10 && mode11g->rates[i] != 20 &&
- mode11g->rates[i] != 55 && mode11g->rates[i] != 110)
- continue;
- mode->rates[mode->num_rates] = mode11g->rates[i];
- mode->num_rates++;
- if (mode->num_rates == 4)
- break;
- }
-
- if (mode->num_rates == 0) {
- os_free(mode->channels);
- os_free(mode->rates);
- (*num_modes)--;
- return modes; /* No 802.11b rates */
- }
-
- wpa_printf(MSG_DEBUG, "nl80211: Added 802.11b mode based on 802.11g "
- "information");
-
- return modes;
-}
-
-
-static void nl80211_set_ht40_mode(struct hostapd_hw_modes *mode, int start,
- int end)
-{
- int c;
-
- for (c = 0; c < mode->num_channels; c++) {
- struct hostapd_channel_data *chan = &mode->channels[c];
- if (chan->freq - 10 >= start && chan->freq + 10 <= end)
- chan->flag |= HOSTAPD_CHAN_HT40;
- }
-}
-
-
-static void nl80211_set_ht40_mode_sec(struct hostapd_hw_modes *mode, int start,
- int end)
-{
- int c;
-
- for (c = 0; c < mode->num_channels; c++) {
- struct hostapd_channel_data *chan = &mode->channels[c];
- if (!(chan->flag & HOSTAPD_CHAN_HT40))
- continue;
- if (chan->freq - 30 >= start && chan->freq - 10 <= end)
- chan->flag |= HOSTAPD_CHAN_HT40MINUS;
- if (chan->freq + 10 >= start && chan->freq + 30 <= end)
- chan->flag |= HOSTAPD_CHAN_HT40PLUS;
- }
-}
-
-
-static void nl80211_reg_rule_max_eirp(u32 start, u32 end, u32 max_eirp,
- struct phy_info_arg *results)
-{
- u16 m;
-
- for (m = 0; m < *results->num_modes; m++) {
- int c;
- struct hostapd_hw_modes *mode = &results->modes[m];
-
- for (c = 0; c < mode->num_channels; c++) {
- struct hostapd_channel_data *chan = &mode->channels[c];
- if ((u32) chan->freq - 10 >= start &&
- (u32) chan->freq + 10 <= end)
- chan->max_tx_power = max_eirp;
- }
- }
-}
-
-
-static void nl80211_reg_rule_ht40(u32 start, u32 end,
- struct phy_info_arg *results)
-{
- u16 m;
-
- for (m = 0; m < *results->num_modes; m++) {
- if (!(results->modes[m].ht_capab &
- HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
- continue;
- nl80211_set_ht40_mode(&results->modes[m], start, end);
- }
-}
-
-
-static void nl80211_reg_rule_sec(struct nlattr *tb[],
- struct phy_info_arg *results)
-{
- u32 start, end, max_bw;
- u16 m;
-
- if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
- tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
- tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
- return;
-
- start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
- end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
- max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
-
- if (max_bw < 20)
- return;
-
- for (m = 0; m < *results->num_modes; m++) {
- if (!(results->modes[m].ht_capab &
- HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
- continue;
- nl80211_set_ht40_mode_sec(&results->modes[m], start, end);
- }
-}
-
-
-static void nl80211_set_vht_mode(struct hostapd_hw_modes *mode, int start,
- int end)
-{
- int c;
-
- for (c = 0; c < mode->num_channels; c++) {
- struct hostapd_channel_data *chan = &mode->channels[c];
- if (chan->freq - 10 >= start && chan->freq + 70 <= end)
- chan->flag |= HOSTAPD_CHAN_VHT_10_70;
-
- if (chan->freq - 30 >= start && chan->freq + 50 <= end)
- chan->flag |= HOSTAPD_CHAN_VHT_30_50;
-
- if (chan->freq - 50 >= start && chan->freq + 30 <= end)
- chan->flag |= HOSTAPD_CHAN_VHT_50_30;
-
- if (chan->freq - 70 >= start && chan->freq + 10 <= end)
- chan->flag |= HOSTAPD_CHAN_VHT_70_10;
- }
-}
-
-
-static void nl80211_reg_rule_vht(struct nlattr *tb[],
- struct phy_info_arg *results)
-{
- u32 start, end, max_bw;
- u16 m;
-
- if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
- tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
- tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
- return;
-
- start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
- end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
- max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
-
- if (max_bw < 80)
- return;
-
- for (m = 0; m < *results->num_modes; m++) {
- if (!(results->modes[m].ht_capab &
- HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
- continue;
- /* TODO: use a real VHT support indication */
- if (!results->modes[m].vht_capab)
- continue;
-
- nl80211_set_vht_mode(&results->modes[m], start, end);
- }
-}
-
-
-static const char * dfs_domain_name(enum nl80211_dfs_regions region)
-{
- switch (region) {
- case NL80211_DFS_UNSET:
- return "DFS-UNSET";
- case NL80211_DFS_FCC:
- return "DFS-FCC";
- case NL80211_DFS_ETSI:
- return "DFS-ETSI";
- case NL80211_DFS_JP:
- return "DFS-JP";
- default:
- return "DFS-invalid";
- }
-}
-
-
-static int nl80211_get_reg(struct nl_msg *msg, void *arg)
-{
- struct phy_info_arg *results = arg;
- struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
- struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
- struct nlattr *nl_rule;
- struct nlattr *tb_rule[NL80211_FREQUENCY_ATTR_MAX + 1];
- int rem_rule;
- static struct nla_policy reg_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
- [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 },
- [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 },
- [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 },
- [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 },
- [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 },
- [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
- };
-
- nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
- genlmsg_attrlen(gnlh, 0), NULL);
- if (!tb_msg[NL80211_ATTR_REG_ALPHA2] ||
- !tb_msg[NL80211_ATTR_REG_RULES]) {
- wpa_printf(MSG_DEBUG, "nl80211: No regulatory information "
- "available");
- return NL_SKIP;
- }
-
- if (tb_msg[NL80211_ATTR_DFS_REGION]) {
- enum nl80211_dfs_regions dfs_domain;
- dfs_domain = nla_get_u8(tb_msg[NL80211_ATTR_DFS_REGION]);
- wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s (%s)",
- (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]),
- dfs_domain_name(dfs_domain));
- } else {
- wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s",
- (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]));
- }
-
- nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
- {
- u32 start, end, max_eirp = 0, max_bw = 0, flags = 0;
- nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
- nla_data(nl_rule), nla_len(nl_rule), reg_policy);
- if (tb_rule[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
- tb_rule[NL80211_ATTR_FREQ_RANGE_END] == NULL)
- continue;
- start = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
- end = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
- if (tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP])
- max_eirp = nla_get_u32(tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP]) / 100;
- if (tb_rule[NL80211_ATTR_FREQ_RANGE_MAX_BW])
- max_bw = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
- if (tb_rule[NL80211_ATTR_REG_RULE_FLAGS])
- flags = nla_get_u32(tb_rule[NL80211_ATTR_REG_RULE_FLAGS]);
-
- wpa_printf(MSG_DEBUG, "nl80211: %u-%u @ %u MHz %u mBm%s%s%s%s%s%s%s%s",
- start, end, max_bw, max_eirp,
- flags & NL80211_RRF_NO_OFDM ? " (no OFDM)" : "",
- flags & NL80211_RRF_NO_CCK ? " (no CCK)" : "",
- flags & NL80211_RRF_NO_INDOOR ? " (no indoor)" : "",
- flags & NL80211_RRF_NO_OUTDOOR ? " (no outdoor)" :
- "",
- flags & NL80211_RRF_DFS ? " (DFS)" : "",
- flags & NL80211_RRF_PTP_ONLY ? " (PTP only)" : "",
- flags & NL80211_RRF_PTMP_ONLY ? " (PTMP only)" : "",
- flags & NL80211_RRF_NO_IR ? " (no IR)" : "");
- if (max_bw >= 40)
- nl80211_reg_rule_ht40(start, end, results);
- if (tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP])
- nl80211_reg_rule_max_eirp(start, end, max_eirp,
- results);
- }
-
- nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
- {
- nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
- nla_data(nl_rule), nla_len(nl_rule), reg_policy);
- nl80211_reg_rule_sec(tb_rule, results);
- }
-
- nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
- {
- nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
- nla_data(nl_rule), nla_len(nl_rule), reg_policy);
- nl80211_reg_rule_vht(tb_rule, results);
- }
-
- return NL_SKIP;
-}
-
-
-static int nl80211_set_regulatory_flags(struct wpa_driver_nl80211_data *drv,
- struct phy_info_arg *results)
-{
- struct nl_msg *msg;
-
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
- return send_and_recv_msgs(drv, msg, nl80211_get_reg, results);
-}
-
-
-static struct hostapd_hw_modes *
-wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
-{
- u32 feat;
- struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
- struct nl_msg *msg;
- struct phy_info_arg result = {
- .num_modes = num_modes,
- .modes = NULL,
- .last_mode = -1,
- };
-
- *num_modes = 0;
- *flags = 0;
-
- msg = nlmsg_alloc();
- if (!msg)
- return NULL;
-
- feat = get_nl80211_protocol_features(drv);
- if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
- nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_WIPHY);
- else
- nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
-
- NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
- if (nl80211_set_iface_id(msg, bss) < 0)
- goto nla_put_failure;
-
- if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) {
- nl80211_set_regulatory_flags(drv, &result);
- return wpa_driver_nl80211_postprocess_modes(result.modes,
- num_modes);
- }
- msg = NULL;
- nla_put_failure:
- nlmsg_free(msg);
- return NULL;
-}
-
-
-static int wpa_driver_nl80211_send_mntr(struct wpa_driver_nl80211_data *drv,
- const void *data, size_t len,
- int encrypt, int noack)
-{
- __u8 rtap_hdr[] = {
- 0x00, 0x00, /* radiotap version */
- 0x0e, 0x00, /* radiotap length */
- 0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */
- IEEE80211_RADIOTAP_F_FRAG, /* F_FRAG (fragment if required) */
- 0x00, /* padding */
- 0x00, 0x00, /* RX and TX flags to indicate that */
- 0x00, 0x00, /* this is the injected frame directly */
- };
- struct iovec iov[2] = {
- {
- .iov_base = &rtap_hdr,
- .iov_len = sizeof(rtap_hdr),
- },
- {
- .iov_base = (void *) data,
- .iov_len = len,
- }
- };
- struct msghdr msg = {
- .msg_name = NULL,
- .msg_namelen = 0,
- .msg_iov = iov,
- .msg_iovlen = 2,
- .msg_control = NULL,
- .msg_controllen = 0,
- .msg_flags = 0,
- };
- int res;
- u16 txflags = 0;
-
- if (encrypt)
- rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP;
-
- if (drv->monitor_sock < 0) {
- wpa_printf(MSG_DEBUG, "nl80211: No monitor socket available "
- "for %s", __func__);
- return -1;
- }
-
- if (noack)
- txflags |= IEEE80211_RADIOTAP_F_TX_NOACK;
- WPA_PUT_LE16(&rtap_hdr[12], txflags);
-
- res = sendmsg(drv->monitor_sock, &msg, 0);
- if (res < 0) {
- wpa_printf(MSG_INFO, "nl80211: sendmsg: %s", strerror(errno));
- return -1;
- }
- return 0;
-}
-
-
static int wpa_driver_nl80211_send_frame(struct i802_bss *bss,
const void *data, size_t len,
int encrypt, int noack,
@@ -7178,10 +2996,9 @@
}
if (drv->use_monitor) {
- wpa_printf(MSG_DEBUG, "nl80211: send_frame(freq=%u bss->freq=%u) -> send_mntr",
+ wpa_printf(MSG_DEBUG, "nl80211: send_frame(freq=%u bss->freq=%u) -> send_monitor",
freq, bss->freq);
- return wpa_driver_nl80211_send_mntr(drv, data, len,
- encrypt, noack);
+ return nl80211_send_monitor(drv, data, len, encrypt, noack);
}
wpa_printf(MSG_DEBUG, "nl80211: send_frame -> send_frame_cmd");
@@ -7280,48 +3097,46 @@
}
+static int nl80211_put_basic_rates(struct nl_msg *msg, const int *basic_rates)
+{
+ u8 rates[NL80211_MAX_SUPP_RATES];
+ u8 rates_len = 0;
+ int i;
+
+ if (!basic_rates)
+ return 0;
+
+ for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0; i++)
+ rates[rates_len++] = basic_rates[i] / 5;
+
+ return nla_put(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
+}
+
+
static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
int slot, int ht_opmode, int ap_isolate,
- int *basic_rates)
+ const int *basic_rates)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_BSS);
-
- if (cts >= 0)
- NLA_PUT_U8(msg, NL80211_ATTR_BSS_CTS_PROT, cts);
- if (preamble >= 0)
- NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble);
- if (slot >= 0)
- NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot);
- if (ht_opmode >= 0)
- NLA_PUT_U16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode);
- if (ap_isolate >= 0)
- NLA_PUT_U8(msg, NL80211_ATTR_AP_ISOLATE, ap_isolate);
-
- if (basic_rates) {
- u8 rates[NL80211_MAX_SUPP_RATES];
- u8 rates_len = 0;
- int i;
-
- for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0;
- i++)
- rates[rates_len++] = basic_rates[i] / 5;
-
- NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_BSS)) ||
+ (cts >= 0 &&
+ nla_put_u8(msg, NL80211_ATTR_BSS_CTS_PROT, cts)) ||
+ (preamble >= 0 &&
+ nla_put_u8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble)) ||
+ (slot >= 0 &&
+ nla_put_u8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot)) ||
+ (ht_opmode >= 0 &&
+ nla_put_u16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode)) ||
+ (ap_isolate >= 0 &&
+ nla_put_u8(msg, NL80211_ATTR_AP_ISOLATE, ap_isolate)) ||
+ nl80211_put_basic_rates(msg, basic_rates)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
}
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
-
return send_and_recv_msgs(drv, msg, NULL, NULL);
- nla_put_failure:
- nlmsg_free(msg);
- return -ENOBUFS;
}
@@ -7333,7 +3148,7 @@
struct nl_msg *msg;
struct nlattr *acl;
unsigned int i;
- int ret = 0;
+ int ret;
if (!(drv->capa.max_acl_mac_addrs))
return -ENOTSUP;
@@ -7341,44 +3156,49 @@
if (params->num_mac_acl > drv->capa.max_acl_mac_addrs)
return -ENOTSUP;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
wpa_printf(MSG_DEBUG, "nl80211: Set %s ACL (num_mac_acl=%u)",
params->acl_policy ? "Accept" : "Deny", params->num_mac_acl);
- nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_MAC_ACL);
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_MAC_ACL)) ||
+ nla_put_u32(msg, NL80211_ATTR_ACL_POLICY, params->acl_policy ?
+ NL80211_ACL_POLICY_DENY_UNLESS_LISTED :
+ NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED) ||
+ (acl = nla_nest_start(msg, NL80211_ATTR_MAC_ADDRS)) == NULL) {
+ nlmsg_free(msg);
+ return -ENOMEM;
+ }
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
- NLA_PUT_U32(msg, NL80211_ATTR_ACL_POLICY, params->acl_policy ?
- NL80211_ACL_POLICY_DENY_UNLESS_LISTED :
- NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED);
-
- acl = nla_nest_start(msg, NL80211_ATTR_MAC_ADDRS);
- if (acl == NULL)
- goto nla_put_failure;
-
- for (i = 0; i < params->num_mac_acl; i++)
- NLA_PUT(msg, i + 1, ETH_ALEN, params->mac_acl[i].addr);
+ for (i = 0; i < params->num_mac_acl; i++) {
+ if (nla_put(msg, i + 1, ETH_ALEN, params->mac_acl[i].addr)) {
+ nlmsg_free(msg);
+ return -ENOMEM;
+ }
+ }
nla_nest_end(msg, acl);
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Failed to set MAC ACL: %d (%s)",
ret, strerror(-ret));
}
-nla_put_failure:
- nlmsg_free(msg);
-
return ret;
}
+static int nl80211_put_beacon_int(struct nl_msg *msg, int beacon_int)
+{
+ if (beacon_int > 0) {
+ wpa_printf(MSG_DEBUG, " * beacon_int=%d", beacon_int);
+ return nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL,
+ beacon_int);
+ }
+
+ return 0;
+}
+
+
static int wpa_driver_nl80211_set_ap(void *priv,
struct wpa_driver_ap_params *params)
{
@@ -7388,75 +3208,80 @@
u8 cmd = NL80211_CMD_NEW_BEACON;
int ret;
int beacon_set;
- int ifindex = if_nametoindex(bss->ifname);
int num_suites;
+ int smps_mode;
u32 suites[10], suite;
u32 ver;
beacon_set = bss->beacon_set;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
wpa_printf(MSG_DEBUG, "nl80211: Set beacon (beacon_set=%d)",
beacon_set);
if (beacon_set)
cmd = NL80211_CMD_SET_BEACON;
- nl80211_cmd(drv, msg, 0, cmd);
wpa_hexdump(MSG_DEBUG, "nl80211: Beacon head",
params->head, params->head_len);
- NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, params->head_len, params->head);
wpa_hexdump(MSG_DEBUG, "nl80211: Beacon tail",
params->tail, params->tail_len);
- NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len, params->tail);
- wpa_printf(MSG_DEBUG, "nl80211: ifindex=%d", ifindex);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
+ wpa_printf(MSG_DEBUG, "nl80211: ifindex=%d", bss->ifindex);
wpa_printf(MSG_DEBUG, "nl80211: beacon_int=%d", params->beacon_int);
- NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, params->beacon_int);
wpa_printf(MSG_DEBUG, "nl80211: dtim_period=%d", params->dtim_period);
- NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtim_period);
wpa_hexdump_ascii(MSG_DEBUG, "nl80211: ssid",
params->ssid, params->ssid_len);
- NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
- params->ssid);
+ if (!(msg = nl80211_bss_msg(bss, 0, cmd)) ||
+ nla_put(msg, NL80211_ATTR_BEACON_HEAD, params->head_len,
+ params->head) ||
+ nla_put(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len,
+ params->tail) ||
+ nl80211_put_beacon_int(msg, params->beacon_int) ||
+ nla_put_u32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtim_period) ||
+ nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
+ goto fail;
if (params->proberesp && params->proberesp_len) {
wpa_hexdump(MSG_DEBUG, "nl80211: proberesp (offload)",
params->proberesp, params->proberesp_len);
- NLA_PUT(msg, NL80211_ATTR_PROBE_RESP, params->proberesp_len,
- params->proberesp);
+ if (nla_put(msg, NL80211_ATTR_PROBE_RESP, params->proberesp_len,
+ params->proberesp))
+ goto fail;
}
switch (params->hide_ssid) {
case NO_SSID_HIDING:
wpa_printf(MSG_DEBUG, "nl80211: hidden SSID not in use");
- NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
- NL80211_HIDDEN_SSID_NOT_IN_USE);
+ if (nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID,
+ NL80211_HIDDEN_SSID_NOT_IN_USE))
+ goto fail;
break;
case HIDDEN_SSID_ZERO_LEN:
wpa_printf(MSG_DEBUG, "nl80211: hidden SSID zero len");
- NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
- NL80211_HIDDEN_SSID_ZERO_LEN);
+ if (nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID,
+ NL80211_HIDDEN_SSID_ZERO_LEN))
+ goto fail;
break;
case HIDDEN_SSID_ZERO_CONTENTS:
wpa_printf(MSG_DEBUG, "nl80211: hidden SSID zero contents");
- NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
- NL80211_HIDDEN_SSID_ZERO_CONTENTS);
+ if (nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID,
+ NL80211_HIDDEN_SSID_ZERO_CONTENTS))
+ goto fail;
break;
}
wpa_printf(MSG_DEBUG, "nl80211: privacy=%d", params->privacy);
- if (params->privacy)
- NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY);
+ if (params->privacy &&
+ nla_put_flag(msg, NL80211_ATTR_PRIVACY))
+ goto fail;
wpa_printf(MSG_DEBUG, "nl80211: auth_algs=0x%x", params->auth_algs);
if ((params->auth_algs & (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) ==
(WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) {
/* Leave out the attribute */
- } else if (params->auth_algs & WPA_AUTH_ALG_SHARED)
- NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE,
- NL80211_AUTHTYPE_SHARED_KEY);
- else
- NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE,
- NL80211_AUTHTYPE_OPEN_SYSTEM);
+ } else if (params->auth_algs & WPA_AUTH_ALG_SHARED) {
+ if (nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE,
+ NL80211_AUTHTYPE_SHARED_KEY))
+ goto fail;
+ } else {
+ if (nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE,
+ NL80211_AUTHTYPE_OPEN_SYSTEM))
+ goto fail;
+ }
wpa_printf(MSG_DEBUG, "nl80211: wpa_version=0x%x", params->wpa_version);
ver = 0;
@@ -7464,8 +3289,9 @@
ver |= NL80211_WPA_VERSION_1;
if (params->wpa_version & WPA_PROTO_RSN)
ver |= NL80211_WPA_VERSION_2;
- if (ver)
- NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
+ if (ver &&
+ nla_put_u32(msg, NL80211_ATTR_WPA_VERSIONS, ver))
+ goto fail;
wpa_printf(MSG_DEBUG, "nl80211: key_mgmt_suites=0x%x",
params->key_mgmt_suites);
@@ -7474,56 +3300,82 @@
suites[num_suites++] = WLAN_AKM_SUITE_8021X;
if (params->key_mgmt_suites & WPA_KEY_MGMT_PSK)
suites[num_suites++] = WLAN_AKM_SUITE_PSK;
- if (num_suites) {
- NLA_PUT(msg, NL80211_ATTR_AKM_SUITES,
- num_suites * sizeof(u32), suites);
- }
+ if (num_suites &&
+ nla_put(msg, NL80211_ATTR_AKM_SUITES, num_suites * sizeof(u32),
+ suites))
+ goto fail;
- if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X &&
- params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40))
- NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT);
+ if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
+ params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40) &&
+ nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT))
+ goto fail;
wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x",
params->pairwise_ciphers);
num_suites = wpa_cipher_to_cipher_suites(params->pairwise_ciphers,
suites, ARRAY_SIZE(suites));
- if (num_suites) {
- NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
- num_suites * sizeof(u32), suites);
- }
+ if (num_suites &&
+ nla_put(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
+ num_suites * sizeof(u32), suites))
+ goto fail;
wpa_printf(MSG_DEBUG, "nl80211: group_cipher=0x%x",
params->group_cipher);
suite = wpa_cipher_to_cipher_suite(params->group_cipher);
- if (suite)
- NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, suite);
+ if (suite &&
+ nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, suite))
+ goto fail;
+
+ switch (params->smps_mode) {
+ case HT_CAP_INFO_SMPS_DYNAMIC:
+ wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - dynamic");
+ smps_mode = NL80211_SMPS_DYNAMIC;
+ break;
+ case HT_CAP_INFO_SMPS_STATIC:
+ wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - static");
+ smps_mode = NL80211_SMPS_STATIC;
+ break;
+ default:
+ /* invalid - fallback to smps off */
+ case HT_CAP_INFO_SMPS_DISABLED:
+ wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - off");
+ smps_mode = NL80211_SMPS_OFF;
+ break;
+ }
+ if (nla_put_u32(msg, NL80211_ATTR_SMPS_MODE, smps_mode))
+ goto fail;
if (params->beacon_ies) {
wpa_hexdump_buf(MSG_DEBUG, "nl80211: beacon_ies",
params->beacon_ies);
- NLA_PUT(msg, NL80211_ATTR_IE, wpabuf_len(params->beacon_ies),
- wpabuf_head(params->beacon_ies));
+ if (nla_put(msg, NL80211_ATTR_IE,
+ wpabuf_len(params->beacon_ies),
+ wpabuf_head(params->beacon_ies)))
+ goto fail;
}
if (params->proberesp_ies) {
wpa_hexdump_buf(MSG_DEBUG, "nl80211: proberesp_ies",
params->proberesp_ies);
- NLA_PUT(msg, NL80211_ATTR_IE_PROBE_RESP,
- wpabuf_len(params->proberesp_ies),
- wpabuf_head(params->proberesp_ies));
+ if (nla_put(msg, NL80211_ATTR_IE_PROBE_RESP,
+ wpabuf_len(params->proberesp_ies),
+ wpabuf_head(params->proberesp_ies)))
+ goto fail;
}
if (params->assocresp_ies) {
wpa_hexdump_buf(MSG_DEBUG, "nl80211: assocresp_ies",
params->assocresp_ies);
- NLA_PUT(msg, NL80211_ATTR_IE_ASSOC_RESP,
- wpabuf_len(params->assocresp_ies),
- wpabuf_head(params->assocresp_ies));
+ if (nla_put(msg, NL80211_ATTR_IE_ASSOC_RESP,
+ wpabuf_len(params->assocresp_ies),
+ wpabuf_head(params->assocresp_ies)))
+ goto fail;
}
if (drv->capa.flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER) {
wpa_printf(MSG_DEBUG, "nl80211: ap_max_inactivity=%d",
params->ap_max_inactivity);
- NLA_PUT_U16(msg, NL80211_ATTR_INACTIVITY_TIMEOUT,
- params->ap_max_inactivity);
+ if (nla_put_u16(msg, NL80211_ATTR_INACTIVITY_TIMEOUT,
+ params->ap_max_inactivity))
+ goto fail;
}
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -7561,65 +3413,80 @@
}
}
return ret;
- nla_put_failure:
+fail:
nlmsg_free(msg);
return -ENOBUFS;
}
static int nl80211_put_freq_params(struct nl_msg *msg,
- struct hostapd_freq_params *freq)
+ const struct hostapd_freq_params *freq)
{
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq);
+ wpa_printf(MSG_DEBUG, " * freq=%d", freq->freq);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq))
+ return -ENOBUFS;
+
+ wpa_printf(MSG_DEBUG, " * vht_enabled=%d", freq->vht_enabled);
+ wpa_printf(MSG_DEBUG, " * ht_enabled=%d", freq->ht_enabled);
+
if (freq->vht_enabled) {
+ enum nl80211_chan_width cw;
+
+ wpa_printf(MSG_DEBUG, " * bandwidth=%d", freq->bandwidth);
switch (freq->bandwidth) {
case 20:
- NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
- NL80211_CHAN_WIDTH_20);
+ cw = NL80211_CHAN_WIDTH_20;
break;
case 40:
- NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
- NL80211_CHAN_WIDTH_40);
+ cw = NL80211_CHAN_WIDTH_40;
break;
case 80:
if (freq->center_freq2)
- NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
- NL80211_CHAN_WIDTH_80P80);
+ cw = NL80211_CHAN_WIDTH_80P80;
else
- NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
- NL80211_CHAN_WIDTH_80);
+ cw = NL80211_CHAN_WIDTH_80;
break;
case 160:
- NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
- NL80211_CHAN_WIDTH_160);
+ cw = NL80211_CHAN_WIDTH_160;
break;
default:
return -EINVAL;
}
- NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, freq->center_freq1);
- if (freq->center_freq2)
- NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ2,
- freq->center_freq2);
+
+ wpa_printf(MSG_DEBUG, " * channel_width=%d", cw);
+ wpa_printf(MSG_DEBUG, " * center_freq1=%d",
+ freq->center_freq1);
+ wpa_printf(MSG_DEBUG, " * center_freq2=%d",
+ freq->center_freq2);
+ if (nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, cw) ||
+ nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ1,
+ freq->center_freq1) ||
+ (freq->center_freq2 &&
+ nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ2,
+ freq->center_freq2)))
+ return -ENOBUFS;
} else if (freq->ht_enabled) {
+ enum nl80211_channel_type ct;
+
+ wpa_printf(MSG_DEBUG, " * sec_channel_offset=%d",
+ freq->sec_channel_offset);
switch (freq->sec_channel_offset) {
case -1:
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
- NL80211_CHAN_HT40MINUS);
+ ct = NL80211_CHAN_HT40MINUS;
break;
case 1:
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
- NL80211_CHAN_HT40PLUS);
+ ct = NL80211_CHAN_HT40PLUS;
break;
default:
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
- NL80211_CHAN_HT20);
+ ct = NL80211_CHAN_HT20;
break;
}
+
+ wpa_printf(MSG_DEBUG, " * channel_type=%d", ct);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, ct))
+ return -ENOBUFS;
}
return 0;
-
-nla_put_failure:
- return -ENOBUFS;
}
@@ -7634,27 +3501,21 @@
"nl80211: Set freq %d (ht_enabled=%d, vht_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
freq->freq, freq->ht_enabled, freq->vht_enabled,
freq->bandwidth, freq->center_freq1, freq->center_freq2);
- msg = nlmsg_alloc();
- if (!msg)
+
+ msg = nl80211_drv_msg(drv, 0, set_chan ? NL80211_CMD_SET_CHANNEL :
+ NL80211_CMD_SET_WIPHY);
+ if (!msg || nl80211_put_freq_params(msg, freq) < 0) {
+ nlmsg_free(msg);
return -1;
-
- nl80211_cmd(drv, msg, 0, set_chan ? NL80211_CMD_SET_CHANNEL :
- NL80211_CMD_SET_WIPHY);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
- if (nl80211_put_freq_params(msg, freq) < 0)
- goto nla_put_failure;
+ }
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- msg = NULL;
if (ret == 0) {
bss->freq = freq->freq;
return 0;
}
wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): "
"%d (%s)", freq->freq, ret, strerror(-ret));
-nla_put_failure:
- nlmsg_free(msg);
return -1;
}
@@ -7673,11 +3534,40 @@
f |= BIT(NL80211_STA_FLAG_MFP);
if (flags & WPA_STA_TDLS_PEER)
f |= BIT(NL80211_STA_FLAG_TDLS_PEER);
+ if (flags & WPA_STA_AUTHENTICATED)
+ f |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
return f;
}
+#ifdef CONFIG_MESH
+static u32 sta_plink_state_nl80211(enum mesh_plink_state state)
+{
+ switch (state) {
+ case PLINK_LISTEN:
+ return NL80211_PLINK_LISTEN;
+ case PLINK_OPEN_SENT:
+ return NL80211_PLINK_OPN_SNT;
+ case PLINK_OPEN_RCVD:
+ return NL80211_PLINK_OPN_RCVD;
+ case PLINK_CNF_RCVD:
+ return NL80211_PLINK_CNF_RCVD;
+ case PLINK_ESTAB:
+ return NL80211_PLINK_ESTAB;
+ case PLINK_HOLDING:
+ return NL80211_PLINK_HOLDING;
+ case PLINK_BLOCKED:
+ return NL80211_PLINK_BLOCKED;
+ default:
+ wpa_printf(MSG_ERROR, "nl80211: Invalid mesh plink state %d",
+ state);
+ }
+ return -1;
+}
+#endif /* CONFIG_MESH */
+
+
static int wpa_driver_nl80211_sta_add(void *priv,
struct hostapd_sta_add_params *params)
{
@@ -7691,25 +3581,57 @@
!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
return -EOPNOTSUPP;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
wpa_printf(MSG_DEBUG, "nl80211: %s STA " MACSTR,
params->set ? "Set" : "Add", MAC2STR(params->addr));
- nl80211_cmd(drv, msg, 0, params->set ? NL80211_CMD_SET_STATION :
- NL80211_CMD_NEW_STATION);
+ msg = nl80211_bss_msg(bss, 0, params->set ? NL80211_CMD_SET_STATION :
+ NL80211_CMD_NEW_STATION);
+ if (!msg || nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr))
+ goto fail;
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr);
- NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, params->supp_rates_len,
- params->supp_rates);
- wpa_hexdump(MSG_DEBUG, " * supported rates", params->supp_rates,
- params->supp_rates_len);
+ if (!params->set || (params->flags & WPA_STA_TDLS_PEER)) {
+ wpa_hexdump(MSG_DEBUG, " * supported rates",
+ params->supp_rates, params->supp_rates_len);
+ wpa_printf(MSG_DEBUG, " * capability=0x%x",
+ params->capability);
+ if (nla_put(msg, NL80211_ATTR_STA_SUPPORTED_RATES,
+ params->supp_rates_len, params->supp_rates) ||
+ nla_put_u16(msg, NL80211_ATTR_STA_CAPABILITY,
+ params->capability))
+ goto fail;
+
+ if (params->ht_capabilities) {
+ wpa_hexdump(MSG_DEBUG, " * ht_capabilities",
+ (u8 *) params->ht_capabilities,
+ sizeof(*params->ht_capabilities));
+ if (nla_put(msg, NL80211_ATTR_HT_CAPABILITY,
+ sizeof(*params->ht_capabilities),
+ params->ht_capabilities))
+ goto fail;
+ }
+
+ if (params->vht_capabilities) {
+ wpa_hexdump(MSG_DEBUG, " * vht_capabilities",
+ (u8 *) params->vht_capabilities,
+ sizeof(*params->vht_capabilities));
+ if (nla_put(msg, NL80211_ATTR_VHT_CAPABILITY,
+ sizeof(*params->vht_capabilities),
+ params->vht_capabilities))
+ goto fail;
+ }
+
+ if (params->ext_capab) {
+ wpa_hexdump(MSG_DEBUG, " * ext_capab",
+ params->ext_capab, params->ext_capab_len);
+ if (nla_put(msg, NL80211_ATTR_STA_EXT_CAPABILITY,
+ params->ext_capab_len, params->ext_capab))
+ goto fail;
+ }
+ }
if (!params->set) {
if (params->aid) {
wpa_printf(MSG_DEBUG, " * aid=%u", params->aid);
- NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
+ if (nla_put_u16(msg, NL80211_ATTR_STA_AID, params->aid))
+ goto fail;
} else {
/*
* cfg80211 validates that AID is non-zero, so we have
@@ -7717,85 +3639,71 @@
* a dummy STA entry is used for now.
*/
wpa_printf(MSG_DEBUG, " * aid=1 (TDLS workaround)");
- NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, 1);
+ if (nla_put_u16(msg, NL80211_ATTR_STA_AID, 1))
+ goto fail;
}
wpa_printf(MSG_DEBUG, " * listen_interval=%u",
params->listen_interval);
- NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
- params->listen_interval);
+ if (nla_put_u16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
+ params->listen_interval))
+ goto fail;
} else if (params->aid && (params->flags & WPA_STA_TDLS_PEER)) {
wpa_printf(MSG_DEBUG, " * peer_aid=%u", params->aid);
- NLA_PUT_U16(msg, NL80211_ATTR_PEER_AID, params->aid);
- }
- if (params->ht_capabilities) {
- wpa_hexdump(MSG_DEBUG, " * ht_capabilities",
- (u8 *) params->ht_capabilities,
- sizeof(*params->ht_capabilities));
- NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY,
- sizeof(*params->ht_capabilities),
- params->ht_capabilities);
- }
-
- if (params->vht_capabilities) {
- wpa_hexdump(MSG_DEBUG, " * vht_capabilities",
- (u8 *) params->vht_capabilities,
- sizeof(*params->vht_capabilities));
- NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY,
- sizeof(*params->vht_capabilities),
- params->vht_capabilities);
+ if (nla_put_u16(msg, NL80211_ATTR_PEER_AID, params->aid))
+ goto fail;
}
if (params->vht_opmode_enabled) {
wpa_printf(MSG_DEBUG, " * opmode=%u", params->vht_opmode);
- NLA_PUT_U8(msg, NL80211_ATTR_OPMODE_NOTIF,
- params->vht_opmode);
- }
-
- wpa_printf(MSG_DEBUG, " * capability=0x%x", params->capability);
- NLA_PUT_U16(msg, NL80211_ATTR_STA_CAPABILITY, params->capability);
-
- if (params->ext_capab) {
- wpa_hexdump(MSG_DEBUG, " * ext_capab",
- params->ext_capab, params->ext_capab_len);
- NLA_PUT(msg, NL80211_ATTR_STA_EXT_CAPABILITY,
- params->ext_capab_len, params->ext_capab);
+ if (nla_put_u8(msg, NL80211_ATTR_OPMODE_NOTIF,
+ params->vht_opmode))
+ goto fail;
}
if (params->supp_channels) {
wpa_hexdump(MSG_DEBUG, " * supported channels",
params->supp_channels, params->supp_channels_len);
- NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_CHANNELS,
- params->supp_channels_len, params->supp_channels);
+ if (nla_put(msg, NL80211_ATTR_STA_SUPPORTED_CHANNELS,
+ params->supp_channels_len, params->supp_channels))
+ goto fail;
}
if (params->supp_oper_classes) {
wpa_hexdump(MSG_DEBUG, " * supported operating classes",
params->supp_oper_classes,
params->supp_oper_classes_len);
- NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES,
- params->supp_oper_classes_len,
- params->supp_oper_classes);
+ if (nla_put(msg, NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES,
+ params->supp_oper_classes_len,
+ params->supp_oper_classes))
+ goto fail;
}
os_memset(&upd, 0, sizeof(upd));
- upd.mask = sta_flags_nl80211(params->flags);
- upd.set = upd.mask;
+ upd.set = sta_flags_nl80211(params->flags);
+ upd.mask = upd.set | sta_flags_nl80211(params->flags_mask);
wpa_printf(MSG_DEBUG, " * flags set=0x%x mask=0x%x",
upd.set, upd.mask);
- NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
+ if (nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd))
+ goto fail;
+
+#ifdef CONFIG_MESH
+ if (params->plink_state &&
+ nla_put_u8(msg, NL80211_ATTR_STA_PLINK_STATE,
+ sta_plink_state_nl80211(params->plink_state)))
+ goto fail;
+#endif /* CONFIG_MESH */
if (params->flags & WPA_STA_WMM) {
struct nlattr *wme = nla_nest_start(msg, NL80211_ATTR_STA_WME);
- if (!wme)
- goto nla_put_failure;
-
wpa_printf(MSG_DEBUG, " * qosinfo=0x%x", params->qosinfo);
- NLA_PUT_U8(msg, NL80211_STA_WME_UAPSD_QUEUES,
- params->qosinfo & WMM_QOSINFO_STA_AC_MASK);
- NLA_PUT_U8(msg, NL80211_STA_WME_MAX_SP,
- (params->qosinfo >> WMM_QOSINFO_STA_SP_SHIFT) &
- WMM_QOSINFO_STA_SP_MASK);
+ if (!wme ||
+ nla_put_u8(msg, NL80211_STA_WME_UAPSD_QUEUES,
+ params->qosinfo & WMM_QOSINFO_STA_AC_MASK) ||
+ nla_put_u8(msg, NL80211_STA_WME_MAX_SP,
+ (params->qosinfo >> WMM_QOSINFO_STA_SP_SHIFT) &
+ WMM_QOSINFO_STA_SP_MASK))
+ goto fail;
nla_nest_end(msg, wme);
}
@@ -7807,7 +3715,7 @@
strerror(-ret));
if (ret == -EEXIST)
ret = 0;
- nla_put_failure:
+fail:
nlmsg_free(msg);
return ret;
}
@@ -7850,21 +3758,26 @@
}
-static int wpa_driver_nl80211_sta_remove(struct i802_bss *bss, const u8 *addr)
+static int wpa_driver_nl80211_sta_remove(struct i802_bss *bss, const u8 *addr,
+ int deauth, u16 reason_code)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
int ret;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
- if_nametoindex(bss->ifname));
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_DEL_STATION)) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
+ (deauth == 0 &&
+ nla_put_u8(msg, NL80211_ATTR_MGMT_SUBTYPE,
+ WLAN_FC_STYPE_DISASSOC)) ||
+ (deauth == 1 &&
+ nla_put_u8(msg, NL80211_ATTR_MGMT_SUBTYPE,
+ WLAN_FC_STYPE_DEAUTH)) ||
+ (reason_code &&
+ nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code))) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
wpa_printf(MSG_DEBUG, "nl80211: sta_remove -> DEL_STATION %s " MACSTR
@@ -7877,14 +3790,10 @@
if (ret == -ENOENT)
return 0;
return ret;
- nla_put_failure:
- nlmsg_free(msg);
- return -ENOBUFS;
}
-static void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv,
- int ifidx)
+void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv, int ifidx)
{
struct nl_msg *msg;
struct wpa_driver_nl80211_data *drv2;
@@ -7896,18 +3805,9 @@
struct wpa_driver_nl80211_data, list)
del_ifidx(drv2, ifidx);
- msg = nlmsg_alloc();
- if (!msg)
- goto nla_put_failure;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_INTERFACE);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifidx);
-
+ msg = nl80211_ifindex_msg(drv, ifidx, 0, NL80211_CMD_DEL_INTERFACE);
if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
return;
- msg = NULL;
- nla_put_failure:
- nlmsg_free(msg);
wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d)", ifidx);
}
@@ -7955,40 +3855,37 @@
wpa_printf(MSG_DEBUG, "nl80211: Create interface iftype %d (%s)",
iftype, nl80211_iftype_str(iftype));
- msg = nlmsg_alloc();
- if (!msg)
- return -1;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_INTERFACE);
- if (nl80211_set_iface_id(msg, drv->first_bss) < 0)
- goto nla_put_failure;
- NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname);
- NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype);
+ msg = nl80211_cmd_msg(drv->first_bss, 0, NL80211_CMD_NEW_INTERFACE);
+ if (!msg ||
+ nla_put_string(msg, NL80211_ATTR_IFNAME, ifname) ||
+ nla_put_u32(msg, NL80211_ATTR_IFTYPE, iftype))
+ goto fail;
if (iftype == NL80211_IFTYPE_MONITOR) {
struct nlattr *flags;
flags = nla_nest_start(msg, NL80211_ATTR_MNTR_FLAGS);
- if (!flags)
- goto nla_put_failure;
-
- NLA_PUT_FLAG(msg, NL80211_MNTR_FLAG_COOK_FRAMES);
+ if (!flags ||
+ nla_put_flag(msg, NL80211_MNTR_FLAG_COOK_FRAMES))
+ goto fail;
nla_nest_end(msg, flags);
} else if (wds) {
- NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, wds);
+ if (nla_put_u8(msg, NL80211_ATTR_4ADDR, wds))
+ goto fail;
}
/*
* Tell cfg80211 that the interface belongs to the socket that created
* it, and the interface should be deleted when the socket is closed.
*/
- NLA_PUT_FLAG(msg, NL80211_ATTR_IFACE_SOCKET_OWNER);
+ if (nla_put_flag(msg, NL80211_ATTR_IFACE_SOCKET_OWNER))
+ goto fail;
ret = send_and_recv_msgs(drv, msg, handler, arg);
msg = NULL;
if (ret) {
- nla_put_failure:
+ fail:
nlmsg_free(msg);
wpa_printf(MSG_ERROR, "Failed to create interface %s: %d (%s)",
ifname, ret, strerror(-ret));
@@ -8027,11 +3924,11 @@
}
-static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
- const char *ifname, enum nl80211_iftype iftype,
- const u8 *addr, int wds,
- int (*handler)(struct nl_msg *, void *),
- void *arg, int use_existing)
+int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
+ const char *ifname, enum nl80211_iftype iftype,
+ const u8 *addr, int wds,
+ int (*handler)(struct nl_msg *, void *),
+ void *arg, int use_existing)
{
int ret;
@@ -8065,426 +3962,17 @@
wds, handler, arg);
}
- if (ret >= 0 && is_p2p_net_interface(iftype))
+ if (ret >= 0 && is_p2p_net_interface(iftype)) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Interface %s created for P2P - disable 11b rates",
+ ifname);
nl80211_disable_11b_rates(drv, ret, 1);
+ }
return ret;
}
-static void handle_tx_callback(void *ctx, u8 *buf, size_t len, int ok)
-{
- struct ieee80211_hdr *hdr;
- u16 fc;
- union wpa_event_data event;
-
- hdr = (struct ieee80211_hdr *) buf;
- fc = le_to_host16(hdr->frame_control);
-
- os_memset(&event, 0, sizeof(event));
- event.tx_status.type = WLAN_FC_GET_TYPE(fc);
- event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
- event.tx_status.dst = hdr->addr1;
- event.tx_status.data = buf;
- event.tx_status.data_len = len;
- event.tx_status.ack = ok;
- wpa_supplicant_event(ctx, EVENT_TX_STATUS, &event);
-}
-
-
-static void from_unknown_sta(struct wpa_driver_nl80211_data *drv,
- u8 *buf, size_t len)
-{
- struct ieee80211_hdr *hdr = (void *)buf;
- u16 fc;
- union wpa_event_data event;
-
- if (len < sizeof(*hdr))
- return;
-
- fc = le_to_host16(hdr->frame_control);
-
- os_memset(&event, 0, sizeof(event));
- event.rx_from_unknown.bssid = get_hdr_bssid(hdr, len);
- event.rx_from_unknown.addr = hdr->addr2;
- event.rx_from_unknown.wds = (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) ==
- (WLAN_FC_FROMDS | WLAN_FC_TODS);
- wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
-}
-
-
-static void handle_frame(struct wpa_driver_nl80211_data *drv,
- u8 *buf, size_t len, int datarate, int ssi_signal)
-{
- struct ieee80211_hdr *hdr;
- u16 fc;
- union wpa_event_data event;
-
- hdr = (struct ieee80211_hdr *) buf;
- fc = le_to_host16(hdr->frame_control);
-
- switch (WLAN_FC_GET_TYPE(fc)) {
- case WLAN_FC_TYPE_MGMT:
- os_memset(&event, 0, sizeof(event));
- event.rx_mgmt.frame = buf;
- event.rx_mgmt.frame_len = len;
- event.rx_mgmt.datarate = datarate;
- event.rx_mgmt.ssi_signal = ssi_signal;
- wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
- break;
- case WLAN_FC_TYPE_CTRL:
- /* can only get here with PS-Poll frames */
- wpa_printf(MSG_DEBUG, "CTRL");
- from_unknown_sta(drv, buf, len);
- break;
- case WLAN_FC_TYPE_DATA:
- from_unknown_sta(drv, buf, len);
- break;
- }
-}
-
-
-static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
-{
- struct wpa_driver_nl80211_data *drv = eloop_ctx;
- int len;
- unsigned char buf[3000];
- struct ieee80211_radiotap_iterator iter;
- int ret;
- int datarate = 0, ssi_signal = 0;
- int injected = 0, failed = 0, rxflags = 0;
-
- len = recv(sock, buf, sizeof(buf), 0);
- if (len < 0) {
- wpa_printf(MSG_ERROR, "nl80211: Monitor socket recv failed: %s",
- strerror(errno));
- return;
- }
-
- if (ieee80211_radiotap_iterator_init(&iter, (void *) buf, len, NULL)) {
- wpa_printf(MSG_INFO, "nl80211: received invalid radiotap frame");
- return;
- }
-
- while (1) {
- ret = ieee80211_radiotap_iterator_next(&iter);
- if (ret == -ENOENT)
- break;
- if (ret) {
- wpa_printf(MSG_INFO, "nl80211: received invalid radiotap frame (%d)",
- ret);
- return;
- }
- switch (iter.this_arg_index) {
- case IEEE80211_RADIOTAP_FLAGS:
- if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS)
- len -= 4;
- break;
- case IEEE80211_RADIOTAP_RX_FLAGS:
- rxflags = 1;
- break;
- case IEEE80211_RADIOTAP_TX_FLAGS:
- injected = 1;
- failed = le_to_host16((*(uint16_t *) iter.this_arg)) &
- IEEE80211_RADIOTAP_F_TX_FAIL;
- break;
- case IEEE80211_RADIOTAP_DATA_RETRIES:
- break;
- case IEEE80211_RADIOTAP_CHANNEL:
- /* TODO: convert from freq/flags to channel number */
- break;
- case IEEE80211_RADIOTAP_RATE:
- datarate = *iter.this_arg * 5;
- break;
- case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:
- ssi_signal = (s8) *iter.this_arg;
- break;
- }
- }
-
- if (rxflags && injected)
- return;
-
- if (!injected)
- handle_frame(drv, buf + iter._max_length,
- len - iter._max_length, datarate, ssi_signal);
- else
- handle_tx_callback(drv->ctx, buf + iter._max_length,
- len - iter._max_length, !failed);
-}
-
-
-/*
- * we post-process the filter code later and rewrite
- * this to the offset to the last instruction
- */
-#define PASS 0xFF
-#define FAIL 0xFE
-
-static struct sock_filter msock_filter_insns[] = {
- /*
- * do a little-endian load of the radiotap length field
- */
- /* load lower byte into A */
- BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 2),
- /* put it into X (== index register) */
- BPF_STMT(BPF_MISC| BPF_TAX, 0),
- /* load upper byte into A */
- BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 3),
- /* left-shift it by 8 */
- BPF_STMT(BPF_ALU | BPF_LSH | BPF_K, 8),
- /* or with X */
- BPF_STMT(BPF_ALU | BPF_OR | BPF_X, 0),
- /* put result into X */
- BPF_STMT(BPF_MISC| BPF_TAX, 0),
-
- /*
- * Allow management frames through, this also gives us those
- * management frames that we sent ourselves with status
- */
- /* load the lower byte of the IEEE 802.11 frame control field */
- BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0),
- /* mask off frame type and version */
- BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0xF),
- /* accept frame if it's both 0, fall through otherwise */
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, PASS, 0),
-
- /*
- * TODO: add a bit to radiotap RX flags that indicates
- * that the sending station is not associated, then
- * add a filter here that filters on our DA and that flag
- * to allow us to deauth frames to that bad station.
- *
- * For now allow all To DS data frames through.
- */
- /* load the IEEE 802.11 frame control field */
- BPF_STMT(BPF_LD | BPF_H | BPF_IND, 0),
- /* mask off frame type, version and DS status */
- BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0F03),
- /* accept frame if version 0, type 2 and To DS, fall through otherwise
- */
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0801, PASS, 0),
-
-#if 0
- /*
- * drop non-data frames
- */
- /* load the lower byte of the frame control field */
- BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0),
- /* mask off QoS bit */
- BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0c),
- /* drop non-data frames */
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 8, 0, FAIL),
-#endif
- /* load the upper byte of the frame control field */
- BPF_STMT(BPF_LD | BPF_B | BPF_IND, 1),
- /* mask off toDS/fromDS */
- BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x03),
- /* accept WDS frames */
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 3, PASS, 0),
-
- /*
- * add header length to index
- */
- /* load the lower byte of the frame control field */
- BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0),
- /* mask off QoS bit */
- BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x80),
- /* right shift it by 6 to give 0 or 2 */
- BPF_STMT(BPF_ALU | BPF_RSH | BPF_K, 6),
- /* add data frame header length */
- BPF_STMT(BPF_ALU | BPF_ADD | BPF_K, 24),
- /* add index, was start of 802.11 header */
- BPF_STMT(BPF_ALU | BPF_ADD | BPF_X, 0),
- /* move to index, now start of LL header */
- BPF_STMT(BPF_MISC | BPF_TAX, 0),
-
- /*
- * Accept empty data frames, we use those for
- * polling activity.
- */
- BPF_STMT(BPF_LD | BPF_W | BPF_LEN, 0),
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_X, 0, PASS, 0),
-
- /*
- * Accept EAPOL frames
- */
- BPF_STMT(BPF_LD | BPF_W | BPF_IND, 0),
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA0300, 0, FAIL),
- BPF_STMT(BPF_LD | BPF_W | BPF_IND, 4),
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0000888E, PASS, FAIL),
-
- /* keep these last two statements or change the code below */
- /* return 0 == "DROP" */
- BPF_STMT(BPF_RET | BPF_K, 0),
- /* return ~0 == "keep all" */
- BPF_STMT(BPF_RET | BPF_K, ~0),
-};
-
-static struct sock_fprog msock_filter = {
- .len = ARRAY_SIZE(msock_filter_insns),
- .filter = msock_filter_insns,
-};
-
-
-static int add_monitor_filter(int s)
-{
- int idx;
-
- /* rewrite all PASS/FAIL jump offsets */
- for (idx = 0; idx < msock_filter.len; idx++) {
- struct sock_filter *insn = &msock_filter_insns[idx];
-
- if (BPF_CLASS(insn->code) == BPF_JMP) {
- if (insn->code == (BPF_JMP|BPF_JA)) {
- if (insn->k == PASS)
- insn->k = msock_filter.len - idx - 2;
- else if (insn->k == FAIL)
- insn->k = msock_filter.len - idx - 3;
- }
-
- if (insn->jt == PASS)
- insn->jt = msock_filter.len - idx - 2;
- else if (insn->jt == FAIL)
- insn->jt = msock_filter.len - idx - 3;
-
- if (insn->jf == PASS)
- insn->jf = msock_filter.len - idx - 2;
- else if (insn->jf == FAIL)
- insn->jf = msock_filter.len - idx - 3;
- }
- }
-
- if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER,
- &msock_filter, sizeof(msock_filter))) {
- wpa_printf(MSG_ERROR, "nl80211: setsockopt(SO_ATTACH_FILTER) failed: %s",
- strerror(errno));
- return -1;
- }
-
- return 0;
-}
-
-
-static void nl80211_remove_monitor_interface(
- struct wpa_driver_nl80211_data *drv)
-{
- if (drv->monitor_refcount > 0)
- drv->monitor_refcount--;
- wpa_printf(MSG_DEBUG, "nl80211: Remove monitor interface: refcount=%d",
- drv->monitor_refcount);
- if (drv->monitor_refcount > 0)
- return;
-
- if (drv->monitor_ifidx >= 0) {
- nl80211_remove_iface(drv, drv->monitor_ifidx);
- drv->monitor_ifidx = -1;
- }
- if (drv->monitor_sock >= 0) {
- eloop_unregister_read_sock(drv->monitor_sock);
- close(drv->monitor_sock);
- drv->monitor_sock = -1;
- }
-}
-
-
-static int
-nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
-{
- char buf[IFNAMSIZ];
- struct sockaddr_ll ll;
- int optval;
- socklen_t optlen;
-
- if (drv->monitor_ifidx >= 0) {
- drv->monitor_refcount++;
- wpa_printf(MSG_DEBUG, "nl80211: Re-use existing monitor interface: refcount=%d",
- drv->monitor_refcount);
- return 0;
- }
-
- if (os_strncmp(drv->first_bss->ifname, "p2p-", 4) == 0) {
- /*
- * P2P interface name is of the format p2p-%s-%d. For monitor
- * interface name corresponding to P2P GO, replace "p2p-" with
- * "mon-" to retain the same interface name length and to
- * indicate that it is a monitor interface.
- */
- snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss->ifname + 4);
- } else {
- /* Non-P2P interface with AP functionality. */
- snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss->ifname);
- }
-
- buf[IFNAMSIZ - 1] = '\0';
-
- drv->monitor_ifidx =
- nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
- 0, NULL, NULL, 0);
-
- if (drv->monitor_ifidx == -EOPNOTSUPP) {
- /*
- * This is backward compatibility for a few versions of
- * the kernel only that didn't advertise the right
- * attributes for the only driver that then supported
- * AP mode w/o monitor -- ath6kl.
- */
- wpa_printf(MSG_DEBUG, "nl80211: Driver does not support "
- "monitor interface type - try to run without it");
- drv->device_ap_sme = 1;
- }
-
- if (drv->monitor_ifidx < 0)
- return -1;
-
- if (linux_set_iface_flags(drv->global->ioctl_sock, buf, 1))
- goto error;
-
- memset(&ll, 0, sizeof(ll));
- ll.sll_family = AF_PACKET;
- ll.sll_ifindex = drv->monitor_ifidx;
- drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
- if (drv->monitor_sock < 0) {
- wpa_printf(MSG_ERROR, "nl80211: socket[PF_PACKET,SOCK_RAW] failed: %s",
- strerror(errno));
- goto error;
- }
-
- if (add_monitor_filter(drv->monitor_sock)) {
- wpa_printf(MSG_INFO, "Failed to set socket filter for monitor "
- "interface; do filtering in user space");
- /* This works, but will cost in performance. */
- }
-
- if (bind(drv->monitor_sock, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
- wpa_printf(MSG_ERROR, "nl80211: monitor socket bind failed: %s",
- strerror(errno));
- goto error;
- }
-
- optlen = sizeof(optval);
- optval = 20;
- if (setsockopt
- (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) {
- wpa_printf(MSG_ERROR, "nl80211: Failed to set socket priority: %s",
- strerror(errno));
- goto error;
- }
-
- if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read,
- drv, NULL)) {
- wpa_printf(MSG_INFO, "nl80211: Could not register monitor read socket");
- goto error;
- }
-
- drv->monitor_refcount++;
- return 0;
- error:
- nl80211_remove_monitor_interface(drv);
- return -1;
-}
-
-
static int nl80211_setup_ap(struct i802_bss *bss)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -8643,7 +4131,6 @@
int flags_or, int flags_and)
{
struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
struct nlattr *flags;
struct nl80211_sta_flag_update upd;
@@ -8653,47 +4140,38 @@
bss->ifname, MAC2STR(addr), total_flags, flags_or, flags_and,
!!(total_flags & WPA_STA_AUTHORIZED));
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
- if_nametoindex(bss->ifname));
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
+ goto fail;
/*
* Backwards compatibility version using NL80211_ATTR_STA_FLAGS. This
* can be removed eventually.
*/
flags = nla_nest_start(msg, NL80211_ATTR_STA_FLAGS);
- if (!flags)
- goto nla_put_failure;
- if (total_flags & WPA_STA_AUTHORIZED)
- NLA_PUT_FLAG(msg, NL80211_STA_FLAG_AUTHORIZED);
-
- if (total_flags & WPA_STA_WMM)
- NLA_PUT_FLAG(msg, NL80211_STA_FLAG_WME);
-
- if (total_flags & WPA_STA_SHORT_PREAMBLE)
- NLA_PUT_FLAG(msg, NL80211_STA_FLAG_SHORT_PREAMBLE);
-
- if (total_flags & WPA_STA_MFP)
- NLA_PUT_FLAG(msg, NL80211_STA_FLAG_MFP);
-
- if (total_flags & WPA_STA_TDLS_PEER)
- NLA_PUT_FLAG(msg, NL80211_STA_FLAG_TDLS_PEER);
+ if (!flags ||
+ ((total_flags & WPA_STA_AUTHORIZED) &&
+ nla_put_flag(msg, NL80211_STA_FLAG_AUTHORIZED)) ||
+ ((total_flags & WPA_STA_WMM) &&
+ nla_put_flag(msg, NL80211_STA_FLAG_WME)) ||
+ ((total_flags & WPA_STA_SHORT_PREAMBLE) &&
+ nla_put_flag(msg, NL80211_STA_FLAG_SHORT_PREAMBLE)) ||
+ ((total_flags & WPA_STA_MFP) &&
+ nla_put_flag(msg, NL80211_STA_FLAG_MFP)) ||
+ ((total_flags & WPA_STA_TDLS_PEER) &&
+ nla_put_flag(msg, NL80211_STA_FLAG_TDLS_PEER)))
+ goto fail;
nla_nest_end(msg, flags);
os_memset(&upd, 0, sizeof(upd));
upd.mask = sta_flags_nl80211(flags_or | ~flags_and);
upd.set = sta_flags_nl80211(flags_or);
- NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
+ if (nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd))
+ goto fail;
- return send_and_recv_msgs(drv, msg, NULL, NULL);
- nla_put_failure:
+ return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+fail:
nlmsg_free(msg);
return -ENOBUFS;
}
@@ -8728,40 +4206,75 @@
}
-static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv)
+static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv,
+ int reset_mode)
{
struct nl_msg *msg;
- int ret = -1;
+ int ret;
- msg = nlmsg_alloc();
- if (!msg)
- return -1;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_LEAVE_IBSS);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_LEAVE_IBSS);
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS failed: ret=%d "
"(%s)", ret, strerror(-ret));
- goto nla_put_failure;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Leave IBSS request sent successfully");
}
- ret = 0;
- wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS request sent successfully");
-
-nla_put_failure:
- if (wpa_driver_nl80211_set_mode(drv->first_bss,
+ if (reset_mode &&
+ wpa_driver_nl80211_set_mode(drv->first_bss,
NL80211_IFTYPE_STATION)) {
wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
"station mode");
}
- nlmsg_free(msg);
return ret;
}
+static int nl80211_ht_vht_overrides(struct nl_msg *msg,
+ struct wpa_driver_associate_params *params)
+{
+ if (params->disable_ht && nla_put_flag(msg, NL80211_ATTR_DISABLE_HT))
+ return -1;
+
+ if (params->htcaps && params->htcaps_mask) {
+ int sz = sizeof(struct ieee80211_ht_capabilities);
+ wpa_hexdump(MSG_DEBUG, " * htcaps", params->htcaps, sz);
+ wpa_hexdump(MSG_DEBUG, " * htcaps_mask",
+ params->htcaps_mask, sz);
+ if (nla_put(msg, NL80211_ATTR_HT_CAPABILITY, sz,
+ params->htcaps) ||
+ nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
+ params->htcaps_mask))
+ return -1;
+ }
+
+#ifdef CONFIG_VHT_OVERRIDES
+ if (params->disable_vht) {
+ wpa_printf(MSG_DEBUG, " * VHT disabled");
+ if (nla_put_flag(msg, NL80211_ATTR_DISABLE_VHT))
+ return -1;
+ }
+
+ if (params->vhtcaps && params->vhtcaps_mask) {
+ int sz = sizeof(struct ieee80211_vht_capabilities);
+ wpa_hexdump(MSG_DEBUG, " * vhtcaps", params->vhtcaps, sz);
+ wpa_hexdump(MSG_DEBUG, " * vhtcaps_mask",
+ params->vhtcaps_mask, sz);
+ if (nla_put(msg, NL80211_ATTR_VHT_CAPABILITY, sz,
+ params->vhtcaps) ||
+ nla_put(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz,
+ params->vhtcaps_mask))
+ return -1;
+ }
+#endif /* CONFIG_VHT_OVERRIDES */
+
+ return 0;
+}
+
+
static int wpa_driver_nl80211_ibss(struct wpa_driver_nl80211_data *drv,
struct wpa_driver_associate_params *params)
{
@@ -8778,48 +4291,30 @@
}
retry:
- msg = nlmsg_alloc();
- if (!msg)
- return -1;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_JOIN_IBSS);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
- if (params->ssid == NULL || params->ssid_len > sizeof(drv->ssid))
- goto nla_put_failure;
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_JOIN_IBSS)) ||
+ params->ssid == NULL || params->ssid_len > sizeof(drv->ssid))
+ goto fail;
wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
params->ssid, params->ssid_len);
- NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
- params->ssid);
+ if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
+ goto fail;
os_memcpy(drv->ssid, params->ssid, params->ssid_len);
drv->ssid_len = params->ssid_len;
- wpa_printf(MSG_DEBUG, " * freq=%d", params->freq.freq);
- wpa_printf(MSG_DEBUG, " * ht_enabled=%d", params->freq.ht_enabled);
- wpa_printf(MSG_DEBUG, " * sec_channel_offset=%d",
- params->freq.sec_channel_offset);
- wpa_printf(MSG_DEBUG, " * vht_enabled=%d", params->freq.vht_enabled);
- wpa_printf(MSG_DEBUG, " * center_freq1=%d", params->freq.center_freq1);
- wpa_printf(MSG_DEBUG, " * center_freq2=%d", params->freq.center_freq2);
- wpa_printf(MSG_DEBUG, " * bandwidth=%d", params->freq.bandwidth);
- if (nl80211_put_freq_params(msg, ¶ms->freq) < 0)
- goto nla_put_failure;
-
- if (params->beacon_int > 0) {
- wpa_printf(MSG_DEBUG, " * beacon_int=%d", params->beacon_int);
- NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL,
- params->beacon_int);
- }
+ if (nl80211_put_freq_params(msg, ¶ms->freq) < 0 ||
+ nl80211_put_beacon_int(msg, params->beacon_int))
+ goto fail;
ret = nl80211_set_conn_keys(params, msg);
if (ret)
- goto nla_put_failure;
+ goto fail;
if (params->bssid && params->fixed_bssid) {
wpa_printf(MSG_DEBUG, " * BSSID=" MACSTR,
MAC2STR(params->bssid));
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
+ if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
+ goto fail;
}
if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
@@ -8827,17 +4322,22 @@
params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256) {
wpa_printf(MSG_DEBUG, " * control port");
- NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT);
+ if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT))
+ goto fail;
}
if (params->wpa_ie) {
wpa_hexdump(MSG_DEBUG,
" * Extra IEs for Beacon/Probe Response frames",
params->wpa_ie, params->wpa_ie_len);
- NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
- params->wpa_ie);
+ if (nla_put(msg, NL80211_ATTR_IE, params->wpa_ie_len,
+ params->wpa_ie))
+ goto fail;
}
+ if (nl80211_ht_vht_overrides(msg, params) < 0)
+ return -1;
+
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
msg = NULL;
if (ret) {
@@ -8847,17 +4347,16 @@
if (ret == -EALREADY && count == 1) {
wpa_printf(MSG_DEBUG, "nl80211: Retry IBSS join after "
"forced leave");
- nl80211_leave_ibss(drv);
+ nl80211_leave_ibss(drv, 0);
nlmsg_free(msg);
goto retry;
}
-
- goto nla_put_failure;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Join IBSS request sent successfully");
}
- ret = 0;
- wpa_printf(MSG_DEBUG, "nl80211: Join IBSS request sent successfully");
-nla_put_failure:
+fail:
nlmsg_free(msg);
return ret;
}
@@ -8867,56 +4366,61 @@
struct wpa_driver_associate_params *params,
struct nl_msg *msg)
{
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
if (params->bssid) {
wpa_printf(MSG_DEBUG, " * bssid=" MACSTR,
MAC2STR(params->bssid));
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
+ if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
+ return -1;
}
if (params->bssid_hint) {
wpa_printf(MSG_DEBUG, " * bssid_hint=" MACSTR,
MAC2STR(params->bssid_hint));
- NLA_PUT(msg, NL80211_ATTR_MAC_HINT, ETH_ALEN,
- params->bssid_hint);
+ if (nla_put(msg, NL80211_ATTR_MAC_HINT, ETH_ALEN,
+ params->bssid_hint))
+ return -1;
}
if (params->freq.freq) {
wpa_printf(MSG_DEBUG, " * freq=%d", params->freq.freq);
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq.freq);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
+ params->freq.freq))
+ return -1;
drv->assoc_freq = params->freq.freq;
} else
drv->assoc_freq = 0;
if (params->freq_hint) {
wpa_printf(MSG_DEBUG, " * freq_hint=%d", params->freq_hint);
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ_HINT,
- params->freq_hint);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ_HINT,
+ params->freq_hint))
+ return -1;
}
if (params->bg_scan_period >= 0) {
wpa_printf(MSG_DEBUG, " * bg scan period=%d",
params->bg_scan_period);
- NLA_PUT_U16(msg, NL80211_ATTR_BG_SCAN_PERIOD,
- params->bg_scan_period);
+ if (nla_put_u16(msg, NL80211_ATTR_BG_SCAN_PERIOD,
+ params->bg_scan_period))
+ return -1;
}
if (params->ssid) {
wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
params->ssid, params->ssid_len);
- NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
- params->ssid);
+ if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len,
+ params->ssid))
+ return -1;
if (params->ssid_len > sizeof(drv->ssid))
- goto nla_put_failure;
+ return -1;
os_memcpy(drv->ssid, params->ssid, params->ssid_len);
drv->ssid_len = params->ssid_len;
}
wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie, params->wpa_ie_len);
- if (params->wpa_ie)
- NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
- params->wpa_ie);
+ if (params->wpa_ie &&
+ nla_put(msg, NL80211_ATTR_IE, params->wpa_ie_len, params->wpa_ie))
+ return -1;
if (params->wpa_proto) {
enum nl80211_wpa_versions ver = 0;
@@ -8927,13 +4431,16 @@
ver |= NL80211_WPA_VERSION_2;
wpa_printf(MSG_DEBUG, " * WPA Versions 0x%x", ver);
- NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
+ if (nla_put_u32(msg, NL80211_ATTR_WPA_VERSIONS, ver))
+ return -1;
}
if (params->pairwise_suite != WPA_CIPHER_NONE) {
u32 cipher = wpa_cipher_to_cipher_suite(params->pairwise_suite);
wpa_printf(MSG_DEBUG, " * pairwise=0x%x", cipher);
- NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher);
+ if (nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
+ cipher))
+ return -1;
}
if (params->group_suite == WPA_CIPHER_GTK_NOT_USED &&
@@ -8946,7 +4453,8 @@
} else if (params->group_suite != WPA_CIPHER_NONE) {
u32 cipher = wpa_cipher_to_cipher_suite(params->group_suite);
wpa_printf(MSG_DEBUG, " * group=0x%x", cipher);
- NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher);
+ if (nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher))
+ return -1;
}
if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
@@ -8956,7 +4464,9 @@
params->key_mgmt_suite == WPA_KEY_MGMT_CCKM ||
params->key_mgmt_suite == WPA_KEY_MGMT_OSEN ||
params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
- params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256) {
+ params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
int mgmt = WLAN_AKM_SUITE_PSK;
switch (params->key_mgmt_suite) {
@@ -8981,56 +4491,45 @@
case WPA_KEY_MGMT_OSEN:
mgmt = WLAN_AKM_SUITE_OSEN;
break;
+ case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
+ mgmt = WLAN_AKM_SUITE_8021X_SUITE_B;
+ break;
+ case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
+ mgmt = WLAN_AKM_SUITE_8021X_SUITE_B_192;
+ break;
case WPA_KEY_MGMT_PSK:
default:
mgmt = WLAN_AKM_SUITE_PSK;
break;
}
wpa_printf(MSG_DEBUG, " * akm=0x%x", mgmt);
- NLA_PUT_U32(msg, NL80211_ATTR_AKM_SUITES, mgmt);
+ if (nla_put_u32(msg, NL80211_ATTR_AKM_SUITES, mgmt))
+ return -1;
}
- NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT);
+ if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT))
+ return -1;
- if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED)
- NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED);
+ if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED &&
+ nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED))
+ return -1;
- if (params->disable_ht)
- NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_HT);
-
- if (params->htcaps && params->htcaps_mask) {
- int sz = sizeof(struct ieee80211_ht_capabilities);
- wpa_hexdump(MSG_DEBUG, " * htcaps", params->htcaps, sz);
- NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY, sz, params->htcaps);
- wpa_hexdump(MSG_DEBUG, " * htcaps_mask",
- params->htcaps_mask, sz);
- NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
- params->htcaps_mask);
+ if (params->rrm_used) {
+ u32 drv_rrm_flags = drv->capa.rrm_flags;
+ if (!(drv_rrm_flags &
+ WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES) ||
+ !(drv_rrm_flags & WPA_DRIVER_FLAGS_QUIET) ||
+ nla_put_flag(msg, NL80211_ATTR_USE_RRM))
+ return -1;
}
-#ifdef CONFIG_VHT_OVERRIDES
- if (params->disable_vht) {
- wpa_printf(MSG_DEBUG, " * VHT disabled");
- NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_VHT);
- }
-
- if (params->vhtcaps && params->vhtcaps_mask) {
- int sz = sizeof(struct ieee80211_vht_capabilities);
- wpa_hexdump(MSG_DEBUG, " * vhtcaps", params->vhtcaps, sz);
- NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY, sz, params->vhtcaps);
- wpa_hexdump(MSG_DEBUG, " * vhtcaps_mask",
- params->vhtcaps_mask, sz);
- NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz,
- params->vhtcaps_mask);
- }
-#endif /* CONFIG_VHT_OVERRIDES */
+ if (nl80211_ht_vht_overrides(msg, params) < 0)
+ return -1;
if (params->p2p)
wpa_printf(MSG_DEBUG, " * P2P group");
return 0;
-nla_put_failure:
- return -1;
}
@@ -9043,16 +4542,24 @@
int ret;
int algs;
- msg = nlmsg_alloc();
+ if (params->req_key_mgmt_offload && params->psk &&
+ (params->key_mgmt_suite == WPA_KEY_MGMT_PSK ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_FT_PSK)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Key management set PSK");
+ ret = issue_key_mgmt_set_key(drv, params->psk, 32);
+ if (ret)
+ return ret;
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex);
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_CONNECT);
if (!msg)
return -1;
- wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex);
- nl80211_cmd(drv, msg, 0, NL80211_CMD_CONNECT);
-
ret = nl80211_connect_common(drv, params, msg);
if (ret)
- goto nla_put_failure;
+ goto fail;
algs = 0;
if (params->auth_alg & WPA_AUTH_ALG_OPEN)
@@ -9076,27 +4583,28 @@
else if (params->auth_alg & WPA_AUTH_ALG_FT)
type = NL80211_AUTHTYPE_FT;
else
- goto nla_put_failure;
+ goto fail;
wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
- NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type);
+ if (nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
+ goto fail;
skip_auth_type:
ret = nl80211_set_conn_keys(params, msg);
if (ret)
- goto nla_put_failure;
+ goto fail;
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
"(%s)", ret, strerror(-ret));
- goto nla_put_failure;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Connect request send successfully");
}
- ret = 0;
- wpa_printf(MSG_DEBUG, "nl80211: Connect request send successfully");
-nla_put_failure:
+fail:
nlmsg_free(msg);
return ret;
@@ -9139,9 +4647,11 @@
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
- int ret;
+ int ret = -1;
struct nl_msg *msg;
+ nl80211_unmask_11b_rates(bss);
+
if (params->mode == IEEE80211_MODE_AP)
return wpa_driver_nl80211_ap(drv, params);
@@ -9159,23 +4669,22 @@
nl80211_mark_disconnected(drv);
- msg = nlmsg_alloc();
+ wpa_printf(MSG_DEBUG, "nl80211: Associate (ifindex=%d)",
+ drv->ifindex);
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_ASSOCIATE);
if (!msg)
return -1;
- wpa_printf(MSG_DEBUG, "nl80211: Associate (ifindex=%d)",
- drv->ifindex);
- nl80211_cmd(drv, msg, 0, NL80211_CMD_ASSOCIATE);
-
ret = nl80211_connect_common(drv, params, msg);
if (ret)
- goto nla_put_failure;
+ goto fail;
if (params->prev_bssid) {
wpa_printf(MSG_DEBUG, " * prev_bssid=" MACSTR,
MAC2STR(params->prev_bssid));
- NLA_PUT(msg, NL80211_ATTR_PREV_BSSID, ETH_ALEN,
- params->prev_bssid);
+ if (nla_put(msg, NL80211_ATTR_PREV_BSSID, ETH_ALEN,
+ params->prev_bssid))
+ goto fail;
}
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -9185,13 +4694,12 @@
"nl80211: MLME command failed (assoc): ret=%d (%s)",
ret, strerror(-ret));
nl80211_dump_scan(drv);
- goto nla_put_failure;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Association request send successfully");
}
- ret = 0;
- wpa_printf(MSG_DEBUG, "nl80211: Association request send "
- "successfully");
-nla_put_failure:
+fail:
nlmsg_free(msg);
return ret;
}
@@ -9206,20 +4714,15 @@
wpa_printf(MSG_DEBUG, "nl80211: Set mode ifindex %d iftype %d (%s)",
ifindex, mode, nl80211_iftype_str(mode));
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_INTERFACE);
- if (nl80211_set_iface_id(msg, drv->first_bss) < 0)
- goto nla_put_failure;
- NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode);
+ msg = nl80211_cmd_msg(drv->first_bss, 0, NL80211_CMD_SET_INTERFACE);
+ if (!msg || nla_put_u32(msg, NL80211_ATTR_IFTYPE, mode))
+ goto fail;
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
msg = NULL;
if (!ret)
return 0;
-nla_put_failure:
+fail:
nlmsg_free(msg);
wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface %d to mode %d:"
" %d (%s)", ifindex, mode, ret, strerror(-ret));
@@ -9281,7 +4784,7 @@
* on a frequency that the mode is disallowed in.
*/
if (desired_freq_params) {
- res = i802_set_freq(bss, desired_freq_params);
+ res = nl80211_set_channel(bss, desired_freq_params, 0);
if (res) {
wpa_printf(MSG_DEBUG,
"nl80211: Failed to set frequency on interface");
@@ -9322,10 +4825,17 @@
return ret;
}
- if (is_p2p_net_interface(nlmode))
+ if (is_p2p_net_interface(nlmode)) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Interface %s mode change to P2P - disable 11b rates",
+ bss->ifname);
nl80211_disable_11b_rates(drv, drv->ifindex, 1);
- else if (drv->disabled_11b_rates)
+ } else if (drv->disabled_11b_rates) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Interface %s mode changed to non-P2P - re-enable 11b rates",
+ bss->ifname);
nl80211_disable_11b_rates(drv, drv->ifindex, 0);
+ }
if (is_ap_interface(nlmode)) {
nl80211_mgmt_unsubscribe(bss, "start AP");
@@ -9339,7 +4849,12 @@
nl80211_mgmt_unsubscribe(bss, "mode change");
}
+ if (is_mesh_interface(nlmode) &&
+ nl80211_mgmt_subscribe_mesh(bss))
+ return -1;
+
if (!bss->in_deinit && !is_ap_interface(nlmode) &&
+ !is_mesh_interface(nlmode) &&
nl80211_mgmt_subscribe_non_ap(bss) < 0)
wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action "
"frame processing - ignore for now");
@@ -9348,37 +4863,8 @@
}
-static int dfs_info_handler(struct nl_msg *msg, void *arg)
-{
- struct nlattr *tb[NL80211_ATTR_MAX + 1];
- struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
- int *dfs_capability_ptr = arg;
-
- nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
- genlmsg_attrlen(gnlh, 0), NULL);
-
- if (tb[NL80211_ATTR_VENDOR_DATA]) {
- struct nlattr *nl_vend = tb[NL80211_ATTR_VENDOR_DATA];
- struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1];
-
- nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_MAX,
- nla_data(nl_vend), nla_len(nl_vend), NULL);
-
- if (tb_vendor[QCA_WLAN_VENDOR_ATTR_DFS]) {
- u32 val;
- val = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_DFS]);
- wpa_printf(MSG_DEBUG, "nl80211: DFS offload capability: %u",
- val);
- *dfs_capability_ptr = val;
- }
- }
-
- return NL_SKIP;
-}
-
-
-static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
- enum nl80211_iftype nlmode)
+int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
+ enum nl80211_iftype nlmode)
{
return wpa_driver_nl80211_set_mode_impl(bss, nlmode, NULL);
}
@@ -9397,9 +4883,6 @@
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
- struct nl_msg *msg;
- int dfs_capability = 0;
- int ret = 0;
if (!drv->has_capability)
return -1;
@@ -9410,37 +4893,7 @@
capa->extended_capa_len = drv->extended_capa_len;
}
- if ((capa->flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
- !drv->allow_p2p_device) {
- wpa_printf(MSG_DEBUG, "nl80211: Do not indicate P2P_DEVICE support (p2p_device=1 driver param not specified)");
- capa->flags &= ~WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE;
- }
-
- if (drv->dfs_vendor_cmd_avail == 1) {
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_VENDOR);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
- NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA);
- NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_SUBCMD,
- QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY);
-
- ret = send_and_recv_msgs(drv, msg, dfs_info_handler,
- &dfs_capability);
- if (!ret) {
- if (dfs_capability)
- capa->flags |= WPA_DRIVER_FLAGS_DFS_OFFLOAD;
- }
- }
-
- return ret;
-
- nla_put_failure:
- nlmsg_free(msg);
- return -ENOBUFS;
+ return 0;
}
@@ -9464,7 +4917,7 @@
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
struct nl80211_sta_flag_update upd;
- int ret = -ENOBUFS;
+ int ret;
if (!drv->associated && is_zero_ether_addr(drv->bssid) && !authorized) {
wpa_printf(MSG_DEBUG, "nl80211: Skip set_supp_port(unauthorized) while not associated");
@@ -9474,28 +4927,21 @@
wpa_printf(MSG_DEBUG, "nl80211: Set supplicant port %sauthorized for "
MACSTR, authorized ? "" : "un", MAC2STR(drv->bssid));
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
- if_nametoindex(bss->ifname));
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid);
-
os_memset(&upd, 0, sizeof(upd));
upd.mask = BIT(NL80211_STA_FLAG_AUTHORIZED);
if (authorized)
upd.set = BIT(NL80211_STA_FLAG_AUTHORIZED);
- NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
+
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid) ||
+ nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- msg = NULL;
if (!ret)
return 0;
- nla_put_failure:
- nlmsg_free(msg);
wpa_printf(MSG_DEBUG, "nl80211: Failed to set STA flag: %d (%s)",
ret, strerror(-ret));
return ret;
@@ -9546,23 +4992,18 @@
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_KEY);
-
- if (addr)
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
- NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface));
+ msg = nl80211_ifindex_msg(drv, if_nametoindex(iface), 0,
+ NL80211_CMD_GET_KEY);
+ if (!msg ||
+ (addr && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) ||
+ nla_put_u8(msg, NL80211_ATTR_KEY_IDX, idx)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
memset(seq, 0, 6);
return send_and_recv_msgs(drv, msg, get_key_handler, seq);
- nla_put_failure:
- nlmsg_free(msg);
- return -ENOBUFS;
}
@@ -9571,28 +5012,23 @@
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
- int ret = -ENOBUFS;
+ int ret;
u32 val;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
if (rts >= 2347)
val = (u32) -1;
else
val = rts;
- nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, val);
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_WIPHY)) ||
+ nla_put_u32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, val)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- msg = NULL;
if (!ret)
return 0;
-nla_put_failure:
- nlmsg_free(msg);
wpa_printf(MSG_DEBUG, "nl80211: Failed to set RTS threshold %d: "
"%d (%s)", rts, ret, strerror(-ret));
return ret;
@@ -9604,28 +5040,23 @@
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
- int ret = -ENOBUFS;
+ int ret;
u32 val;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
if (frag >= 2346)
val = (u32) -1;
else
val = frag;
- nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, val);
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_WIPHY)) ||
+ nla_put_u32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, val)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- msg = NULL;
if (!ret)
return 0;
-nla_put_failure:
- nlmsg_free(msg);
wpa_printf(MSG_DEBUG, "nl80211: Failed to set fragmentation threshold "
"%d: %d (%s)", frag, ret, strerror(-ret));
return ret;
@@ -9635,33 +5066,22 @@
static int i802_flush(void *priv)
{
struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
int res;
- msg = nlmsg_alloc();
- if (!msg)
- return -1;
-
wpa_printf(MSG_DEBUG, "nl80211: flush -> DEL_STATION %s (all)",
bss->ifname);
- nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION);
/*
* XXX: FIX! this needs to flush all VLANs too
*/
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
- if_nametoindex(bss->ifname));
-
- res = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_DEL_STATION);
+ res = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
if (res) {
wpa_printf(MSG_DEBUG, "nl80211: Station flush failed: ret=%d "
"(%s)", res, strerror(-res));
}
return res;
- nla_put_failure:
- nlmsg_free(msg);
- return -ENOBUFS;
}
@@ -9724,23 +5144,17 @@
struct hostap_sta_driver_data *data,
const u8 *addr)
{
- struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
os_memset(data, 0, sizeof(*data));
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
- nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_STATION);
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_GET_STATION)) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
-
- return send_and_recv_msgs(drv, msg, get_sta_handler, data);
- nla_put_failure:
- nlmsg_free(msg);
- return -ENOBUFS;
+ return send_and_recv_msgs(bss->drv, msg, get_sta_handler, data);
}
@@ -9752,43 +5166,45 @@
struct nl_msg *msg;
struct nlattr *txq, *params;
- msg = nlmsg_alloc();
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_WIPHY);
if (!msg)
return -1;
- nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
-
txq = nla_nest_start(msg, NL80211_ATTR_WIPHY_TXQ_PARAMS);
if (!txq)
- goto nla_put_failure;
+ goto fail;
/* We are only sending parameters for a single TXQ at a time */
params = nla_nest_start(msg, 1);
if (!params)
- goto nla_put_failure;
+ goto fail;
switch (queue) {
case 0:
- NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VO);
+ if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VO))
+ goto fail;
break;
case 1:
- NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VI);
+ if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VI))
+ goto fail;
break;
case 2:
- NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BE);
+ if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BE))
+ goto fail;
break;
case 3:
- NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BK);
+ if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BK))
+ goto fail;
break;
}
/* Burst time is configured in units of 0.1 msec and TXOP parameter in
* 32 usec, so need to convert the value here. */
- NLA_PUT_U16(msg, NL80211_TXQ_ATTR_TXOP, (burst_time * 100 + 16) / 32);
- NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMIN, cw_min);
- NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMAX, cw_max);
- NLA_PUT_U8(msg, NL80211_TXQ_ATTR_AIFS, aifs);
+ if (nla_put_u16(msg, NL80211_TXQ_ATTR_TXOP,
+ (burst_time * 100 + 16) / 32) ||
+ nla_put_u16(msg, NL80211_TXQ_ATTR_CWMIN, cw_min) ||
+ nla_put_u16(msg, NL80211_TXQ_ATTR_CWMAX, cw_max) ||
+ nla_put_u8(msg, NL80211_TXQ_ATTR_AIFS, aifs))
+ goto fail;
nla_nest_end(msg, params);
@@ -9797,7 +5213,7 @@
if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
return 0;
msg = NULL;
- nla_put_failure:
+fail:
nlmsg_free(msg);
return -1;
}
@@ -9808,34 +5224,26 @@
{
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
- int ret = -ENOBUFS;
-
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
+ int ret;
wpa_printf(MSG_DEBUG, "nl80211: %s[%d]: set_sta_vlan(" MACSTR
", ifname=%s[%d], vlan_id=%d)",
bss->ifname, if_nametoindex(bss->ifname),
MAC2STR(addr), ifname, if_nametoindex(ifname), vlan_id);
- nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
- if_nametoindex(bss->ifname));
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
- NLA_PUT_U32(msg, NL80211_ATTR_STA_VLAN,
- if_nametoindex(ifname));
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
+ nla_put_u32(msg, NL80211_ATTR_STA_VLAN, if_nametoindex(ifname))) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- msg = NULL;
if (ret < 0) {
wpa_printf(MSG_ERROR, "nl80211: NL80211_ATTR_STA_VLAN (addr="
MACSTR " ifname=%s vlan_id=%d) failed: %d (%s)",
MAC2STR(addr), ifname, vlan_id, ret,
strerror(-ret));
}
- nla_put_failure:
- nlmsg_free(msg);
return ret;
}
@@ -9847,6 +5255,8 @@
data.inactive_msec = (unsigned long) -1;
ret = i802_read_sta_data(priv, &data, addr);
+ if (ret == -ENOENT)
+ return -ENOENT;
if (ret || data.inactive_msec == (unsigned long) -1)
return -1;
return data.inactive_msec / 1000;
@@ -9869,8 +5279,11 @@
struct wpa_driver_nl80211_data *drv = bss->drv;
struct ieee80211_mgmt mgmt;
+ if (is_mesh_interface(drv->nlmode))
+ return -1;
+
if (drv->device_ap_sme)
- return wpa_driver_nl80211_sta_remove(bss, addr);
+ return wpa_driver_nl80211_sta_remove(bss, addr, 1, reason);
memset(&mgmt, 0, sizeof(mgmt));
mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
@@ -9893,8 +5306,11 @@
struct wpa_driver_nl80211_data *drv = bss->drv;
struct ieee80211_mgmt mgmt;
+ if (is_mesh_interface(drv->nlmode))
+ return -1;
+
if (drv->device_ap_sme)
- return wpa_driver_nl80211_sta_remove(bss, addr);
+ return wpa_driver_nl80211_sta_remove(bss, addr, 0, reason);
memset(&mgmt, 0, sizeof(mgmt));
mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
@@ -9922,7 +5338,7 @@
if (!drv->if_indices[i])
continue;
res = os_snprintf(pos, end - pos, " %d", drv->if_indices[i]);
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
break;
pos += res;
}
@@ -10071,12 +5487,12 @@
struct i802_bss *bss,
const char *brname, const char *ifname)
{
- int ifindex;
+ int br_ifindex;
char in_br[IFNAMSIZ];
os_strlcpy(bss->brname, brname, IFNAMSIZ);
- ifindex = if_nametoindex(brname);
- if (ifindex == 0) {
+ br_ifindex = if_nametoindex(brname);
+ if (br_ifindex == 0) {
/*
* Bridge was configured, but the bridge device does
* not exist. Try to add it now.
@@ -10088,8 +5504,10 @@
return -1;
}
bss->added_bridge = 1;
- add_ifidx(drv, if_nametoindex(brname));
+ br_ifindex = if_nametoindex(brname);
+ add_ifidx(drv, br_ifindex);
}
+ bss->br_ifindex = br_ifindex;
if (linux_br_get(in_br, ifname) == 0) {
if (os_strcmp(in_br, brname) == 0)
@@ -10133,7 +5551,7 @@
bss = wpa_driver_nl80211_drv_init(hapd, params->ifname,
params->global_priv, 1,
- params->bssid);
+ params->bssid, params->driver_params);
if (bss == NULL)
return NULL;
@@ -10143,10 +5561,12 @@
wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s",
params->ifname, brname);
br_ifindex = if_nametoindex(brname);
+ os_strlcpy(bss->brname, brname, IFNAMSIZ);
} else {
brname[0] = '\0';
br_ifindex = 0;
}
+ bss->br_ifindex = br_ifindex;
for (i = 0; i < params->num_bridge; i++) {
if (params->bridge[i]) {
@@ -10157,16 +5577,21 @@
br_added = 1;
}
}
- if (!br_added && br_ifindex &&
- (params->num_bridge == 0 || !params->bridge[0]))
- add_ifidx(drv, br_ifindex);
/* start listening for EAPOL on the default AP interface */
add_ifidx(drv, drv->ifindex);
- if (params->num_bridge && params->bridge[0] &&
- i802_check_bridge(drv, bss, params->bridge[0], params->ifname) < 0)
- goto failed;
+ if (params->num_bridge && params->bridge[0]) {
+ if (i802_check_bridge(drv, bss, params->bridge[0],
+ params->ifname) < 0)
+ goto failed;
+ if (os_strcmp(params->bridge[0], brname) != 0)
+ br_added = 1;
+ }
+
+ if (!br_added && br_ifindex &&
+ (params->num_bridge == 0 || !params->bridge[0]))
+ add_ifidx(drv, br_ifindex);
#ifdef CONFIG_LIBNL3_ROUTE
if (bss->added_if_into_bridge) {
@@ -10236,12 +5661,14 @@
return NL80211_IFTYPE_P2P_GO;
case WPA_IF_P2P_DEVICE:
return NL80211_IFTYPE_P2P_DEVICE;
+ case WPA_IF_MESH:
+ return NL80211_IFTYPE_MESH_POINT;
}
return -1;
}
-#ifdef CONFIG_P2P
+#if defined(CONFIG_P2P) || defined(CONFIG_MESH)
static int nl80211_addr_in_use(struct nl80211_global *global, const u8 *addr)
{
@@ -10255,8 +5682,7 @@
}
-static int nl80211_p2p_interface_addr(struct wpa_driver_nl80211_data *drv,
- u8 *new_addr)
+static int nl80211_vif_addr(struct wpa_driver_nl80211_data *drv, u8 *new_addr)
{
unsigned int idx;
@@ -10273,13 +5699,13 @@
if (idx == 64)
return -1;
- wpa_printf(MSG_DEBUG, "nl80211: Assigned new P2P Interface Address "
+ wpa_printf(MSG_DEBUG, "nl80211: Assigned new virtual interface address "
MACSTR, MAC2STR(new_addr));
return 0;
}
-#endif /* CONFIG_P2P */
+#endif /* CONFIG_P2P || CONFIG_MESH */
struct wdev_info {
@@ -10366,10 +5792,10 @@
}
}
-#ifdef CONFIG_P2P
+#if defined(CONFIG_P2P) || defined(CONFIG_MESH)
if (!addr &&
(type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP ||
- type == WPA_IF_P2P_GO)) {
+ type == WPA_IF_P2P_GO || type == WPA_IF_MESH)) {
/* Enforce unique P2P Interface Address */
u8 new_addr[ETH_ALEN];
@@ -10381,8 +5807,9 @@
}
if (nl80211_addr_in_use(drv->global, new_addr)) {
wpa_printf(MSG_DEBUG, "nl80211: Allocate new address "
- "for P2P group interface");
- if (nl80211_p2p_interface_addr(drv, new_addr) < 0) {
+ "for %s interface", type == WPA_IF_MESH ?
+ "mesh" : "P2P group");
+ if (nl80211_vif_addr(drv, new_addr) < 0) {
if (added)
nl80211_remove_iface(drv, ifidx);
return -1;
@@ -10396,7 +5823,7 @@
}
os_memcpy(if_addr, new_addr, ETH_ALEN);
}
-#endif /* CONFIG_P2P */
+#endif /* CONFIG_P2P || CONFIG_MESH */
if (type == WPA_IF_AP_BSS) {
struct i802_bss *new_bss = os_zalloc(sizeof(*new_bss));
@@ -10560,31 +5987,21 @@
u64 cookie;
int ret = -1;
- msg = nlmsg_alloc();
- if (!msg)
- return -1;
-
wpa_printf(MSG_MSGDUMP, "nl80211: CMD_FRAME freq=%u wait=%u no_cck=%d "
"no_ack=%d offchanok=%d",
freq, wait, no_cck, no_ack, offchanok);
wpa_hexdump(MSG_MSGDUMP, "CMD_FRAME", buf, buf_len);
- nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME);
- if (nl80211_set_iface_id(msg, bss) < 0)
- goto nla_put_failure;
- if (freq)
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
- if (wait)
- NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait);
- if (offchanok && ((drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) ||
- drv->test_use_roc_tx))
- NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK);
- if (no_cck)
- NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
- if (no_ack)
- NLA_PUT_FLAG(msg, NL80211_ATTR_DONT_WAIT_FOR_ACK);
-
- NLA_PUT(msg, NL80211_ATTR_FRAME, buf_len, buf);
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_FRAME)) ||
+ (freq && nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) ||
+ (wait && nla_put_u32(msg, NL80211_ATTR_DURATION, wait)) ||
+ (offchanok && ((drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) ||
+ drv->test_use_roc_tx) &&
+ nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK)) ||
+ (no_cck && nla_put_flag(msg, NL80211_ATTR_TX_NO_CCK_RATE)) ||
+ (no_ack && nla_put_flag(msg, NL80211_ATTR_DONT_WAIT_FOR_ACK)) ||
+ nla_put(msg, NL80211_ATTR_FRAME, buf_len, buf))
+ goto fail;
cookie = 0;
ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
@@ -10593,16 +6010,16 @@
wpa_printf(MSG_DEBUG, "nl80211: Frame command failed: ret=%d "
"(%s) (freq=%u wait=%u)", ret, strerror(-ret),
freq, wait);
- goto nla_put_failure;
+ } else {
+ wpa_printf(MSG_MSGDUMP, "nl80211: Frame TX command accepted%s; "
+ "cookie 0x%llx", no_ack ? " (no ACK)" : "",
+ (long long unsigned int) cookie);
+
+ if (cookie_out)
+ *cookie_out = no_ack ? (u64) -1 : cookie;
}
- wpa_printf(MSG_MSGDUMP, "nl80211: Frame TX command accepted%s; "
- "cookie 0x%llx", no_ack ? " (no ACK)" : "",
- (long long unsigned int) cookie);
- if (cookie_out)
- *cookie_out = no_ack ? (u64) -1 : cookie;
-
-nla_put_failure:
+fail:
nlmsg_free(msg);
return ret;
}
@@ -10661,26 +6078,18 @@
struct nl_msg *msg;
int ret;
- msg = nlmsg_alloc();
- if (!msg)
- return;
-
wpa_printf(MSG_DEBUG, "nl80211: Cancel TX frame wait: cookie=0x%llx",
(long long unsigned int) drv->send_action_cookie);
- nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME_WAIT_CANCEL);
-
- if (nl80211_set_iface_id(msg, bss) < 0)
- goto nla_put_failure;
- NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->send_action_cookie);
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_FRAME_WAIT_CANCEL)) ||
+ nla_put_u64(msg, NL80211_ATTR_COOKIE, drv->send_action_cookie)) {
+ nlmsg_free(msg);
+ return;
+ }
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- msg = NULL;
if (ret)
wpa_printf(MSG_DEBUG, "nl80211: wait cancel failed: ret=%d "
"(%s)", ret, strerror(-ret));
-
- nla_put_failure:
- nlmsg_free(msg);
}
@@ -10693,21 +6102,15 @@
int ret;
u64 cookie;
- msg = nlmsg_alloc();
- if (!msg)
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_REMAIN_ON_CHANNEL)) ||
+ nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) ||
+ nla_put_u32(msg, NL80211_ATTR_DURATION, duration)) {
+ nlmsg_free(msg);
return -1;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_REMAIN_ON_CHANNEL);
-
- if (nl80211_set_iface_id(msg, bss) < 0)
- goto nla_put_failure;
-
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
- NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration);
+ }
cookie = 0;
ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
- msg = NULL;
if (ret == 0) {
wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel cookie "
"0x%llx for freq=%u MHz duration=%u",
@@ -10719,8 +6122,6 @@
wpa_printf(MSG_DEBUG, "nl80211: Failed to request remain-on-channel "
"(freq=%d duration=%u): %d (%s)",
freq, duration, ret, strerror(-ret));
-nla_put_failure:
- nlmsg_free(msg);
return -1;
}
@@ -10742,25 +6143,18 @@
"0x%llx",
(long long unsigned int) drv->remain_on_chan_cookie);
- msg = nlmsg_alloc();
- if (!msg)
+ msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL);
+ if (!msg ||
+ nla_put_u64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie)) {
+ nlmsg_free(msg);
return -1;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL);
-
- if (nl80211_set_iface_id(msg, bss) < 0)
- goto nla_put_failure;
-
- NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie);
+ }
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- msg = NULL;
if (ret == 0)
return 0;
wpa_printf(MSG_DEBUG, "nl80211: Failed to cancel remain-on-channel: "
"%d (%s)", ret, strerror(-ret));
-nla_put_failure:
- nlmsg_free(msg);
return -1;
}
@@ -10825,16 +6219,19 @@
struct nlattr *bands, *band;
int ret;
- msg = nlmsg_alloc();
+ wpa_printf(MSG_DEBUG,
+ "nl80211: NL80211_CMD_SET_TX_BITRATE_MASK (ifindex=%d %s)",
+ ifindex, disabled ? "NL80211_TXRATE_LEGACY=OFDM-only" :
+ "no NL80211_TXRATE_LEGACY constraint");
+
+ msg = nl80211_ifindex_msg(drv, ifindex, 0,
+ NL80211_CMD_SET_TX_BITRATE_MASK);
if (!msg)
return -1;
- nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_TX_BITRATE_MASK);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
-
bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES);
if (!bands)
- goto nla_put_failure;
+ goto fail;
/*
* Disable 2 GHz rates 1, 2, 5.5, 11 Mbps by masking out everything
@@ -10842,18 +6239,15 @@
* rates. All 5 GHz rates are left enabled.
*/
band = nla_nest_start(msg, NL80211_BAND_2GHZ);
- if (!band)
- goto nla_put_failure;
- if (disabled) {
- NLA_PUT(msg, NL80211_TXRATE_LEGACY, 8,
- "\x0c\x12\x18\x24\x30\x48\x60\x6c");
- }
+ if (!band ||
+ (disabled && nla_put(msg, NL80211_TXRATE_LEGACY, 8,
+ "\x0c\x12\x18\x24\x30\x48\x60\x6c")))
+ goto fail;
nla_nest_end(msg, band);
nla_nest_end(msg, bands);
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Set TX rates failed: ret=%d "
"(%s)", ret, strerror(-ret));
@@ -10862,7 +6256,7 @@
return ret;
-nla_put_failure:
+fail:
nlmsg_free(msg);
return -1;
}
@@ -10875,6 +6269,7 @@
if (!is_ap_interface(drv->nlmode))
return -1;
wpa_driver_nl80211_del_beacon(drv);
+ bss->beacon_set = 0;
/*
* If the P2P GO interface was dynamically added, then it is
@@ -10926,86 +6321,26 @@
}
-static int nl80211_send_ft_action(void *priv, u8 action, const u8 *target_ap,
- const u8 *ies, size_t ies_len)
-{
- struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
- int ret;
- u8 *data, *pos;
- size_t data_len;
- const u8 *own_addr = bss->addr;
-
- if (action != 1) {
- wpa_printf(MSG_ERROR, "nl80211: Unsupported send_ft_action "
- "action %d", action);
- return -1;
- }
-
- /*
- * Action frame payload:
- * Category[1] = 6 (Fast BSS Transition)
- * Action[1] = 1 (Fast BSS Transition Request)
- * STA Address
- * Target AP Address
- * FT IEs
- */
-
- data_len = 2 + 2 * ETH_ALEN + ies_len;
- data = os_malloc(data_len);
- if (data == NULL)
- return -1;
- pos = data;
- *pos++ = 0x06; /* FT Action category */
- *pos++ = action;
- os_memcpy(pos, own_addr, ETH_ALEN);
- pos += ETH_ALEN;
- os_memcpy(pos, target_ap, ETH_ALEN);
- pos += ETH_ALEN;
- os_memcpy(pos, ies, ies_len);
-
- ret = wpa_driver_nl80211_send_action(bss, drv->assoc_freq, 0,
- drv->bssid, own_addr, drv->bssid,
- data, data_len, 0);
- os_free(data);
-
- return ret;
-}
-
-
static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
struct nlattr *cqm;
- int ret = -1;
wpa_printf(MSG_DEBUG, "nl80211: Signal monitor threshold=%d "
"hysteresis=%d", threshold, hysteresis);
- msg = nlmsg_alloc();
- if (!msg)
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_CQM)) ||
+ !(cqm = nla_nest_start(msg, NL80211_ATTR_CQM)) ||
+ nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_THOLD, threshold) ||
+ nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_HYST, hysteresis)) {
+ nlmsg_free(msg);
return -1;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_CQM);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
-
- cqm = nla_nest_start(msg, NL80211_ATTR_CQM);
- if (cqm == NULL)
- goto nla_put_failure;
-
- NLA_PUT_U32(msg, NL80211_ATTR_CQM_RSSI_THOLD, threshold);
- NLA_PUT_U32(msg, NL80211_ATTR_CQM_RSSI_HYST, hysteresis);
+ }
nla_nest_end(msg, cqm);
- ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- msg = NULL;
-
-nla_put_failure:
- nlmsg_free(msg);
- return ret;
+ return send_and_recv_msgs(drv, msg, NULL, NULL);
}
@@ -11042,18 +6377,8 @@
{
struct nl_msg *msg;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_INTERFACE);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE);
return send_and_recv_msgs(drv, msg, get_channel_width, sig);
-
-nla_put_failure:
- nlmsg_free(msg);
- return -ENOBUFS;
}
@@ -11142,12 +6467,6 @@
drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
}
-
- if (os_strstr(param, "p2p_device=1")) {
- struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
- drv->allow_p2p_device = 1;
- }
#endif /* CONFIG_P2P */
if (os_strstr(param, "use_monitor=1")) {
@@ -11258,22 +6577,14 @@
{
struct nl_msg *msg;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(bss->drv, msg, 0, cmd);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
- if (pmkid)
- NLA_PUT(msg, NL80211_ATTR_PMKID, 16, pmkid);
- if (bssid)
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid);
+ if (!(msg = nl80211_bss_msg(bss, 0, cmd)) ||
+ (pmkid && nla_put(msg, NL80211_ATTR_PMKID, 16, pmkid)) ||
+ (bssid && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
- nla_put_failure:
- nlmsg_free(msg);
- return -ENOBUFS;
}
@@ -11444,7 +6755,7 @@
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
- int err = -ENOBUFS;
+ int err;
union wpa_event_data data;
struct survey_results *survey_results;
@@ -11453,13 +6764,9 @@
dl_list_init(&survey_results->survey_list);
- msg = nlmsg_alloc();
+ msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
if (!msg)
- goto nla_put_failure;
-
- nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ return -ENOBUFS;
if (freq)
data.survey_results.freq_filter = freq;
@@ -11470,51 +6777,49 @@
survey_results);
} while (err > 0);
- if (err) {
+ if (err)
wpa_printf(MSG_ERROR, "nl80211: Failed to process survey data");
- goto out_clean;
- }
+ else
+ wpa_supplicant_event(drv->ctx, EVENT_SURVEY, &data);
- wpa_supplicant_event(drv->ctx, EVENT_SURVEY, &data);
-
-out_clean:
clean_survey_results(survey_results);
-nla_put_failure:
return err;
}
-static void nl80211_set_rekey_info(void *priv, const u8 *kek, const u8 *kck,
+static void nl80211_set_rekey_info(void *priv, const u8 *kek, size_t kek_len,
+ const u8 *kck, size_t kck_len,
const u8 *replay_ctr)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nlattr *replay_nested;
struct nl_msg *msg;
+ int ret;
- msg = nlmsg_alloc();
- if (!msg)
+ if (!drv->set_rekey_offload)
return;
- nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_REKEY_OFFLOAD);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
-
- replay_nested = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA);
- if (!replay_nested)
- goto nla_put_failure;
-
- NLA_PUT(msg, NL80211_REKEY_DATA_KEK, NL80211_KEK_LEN, kek);
- NLA_PUT(msg, NL80211_REKEY_DATA_KCK, NL80211_KCK_LEN, kck);
- NLA_PUT(msg, NL80211_REKEY_DATA_REPLAY_CTR, NL80211_REPLAY_CTR_LEN,
- replay_ctr);
+ wpa_printf(MSG_DEBUG, "nl80211: Set rekey offload");
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_REKEY_OFFLOAD)) ||
+ !(replay_nested = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA)) ||
+ nla_put(msg, NL80211_REKEY_DATA_KEK, kek_len, kek) ||
+ nla_put(msg, NL80211_REKEY_DATA_KCK, kck_len, kck) ||
+ nla_put(msg, NL80211_REKEY_DATA_REPLAY_CTR, NL80211_REPLAY_CTR_LEN,
+ replay_ctr)) {
+ nl80211_nlmsg_clear(msg);
+ nlmsg_free(msg);
+ return;
+ }
nla_nest_end(msg, replay_nested);
- send_and_recv_msgs(drv, msg, NULL, NULL);
- return;
- nla_put_failure:
- nlmsg_free(msg);
+ ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1);
+ if (ret == -EOPNOTSUPP) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Driver does not support rekey offload");
+ drv->set_rekey_offload = 0;
+ }
}
@@ -11568,19 +6873,13 @@
return;
}
- msg = nlmsg_alloc();
- if (!msg)
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_PROBE_CLIENT)) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
+ nlmsg_free(msg);
return;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_PROBE_CLIENT);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+ }
send_and_recv_msgs(drv, msg, NULL, NULL);
- return;
- nla_put_failure:
- nlmsg_free(msg);
}
@@ -11588,18 +6887,13 @@
{
struct nl_msg *msg;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_SET_POWER_SAVE);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
- NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE,
- enabled ? NL80211_PS_ENABLED : NL80211_PS_DISABLED);
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_POWER_SAVE)) ||
+ nla_put_u32(msg, NL80211_ATTR_PS_STATE,
+ enabled ? NL80211_PS_ENABLED : NL80211_PS_DISABLED)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
-nla_put_failure:
- nlmsg_free(msg);
- return -ENOBUFS;
}
@@ -11646,24 +6940,17 @@
return -1;
}
- msg = nlmsg_alloc();
- if (!msg)
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_RADAR_DETECT)) ||
+ nl80211_put_freq_params(msg, freq) < 0) {
+ nlmsg_free(msg);
return -1;
-
- nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_RADAR_DETECT);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
- if (nl80211_put_freq_params(msg, freq) < 0)
- goto nla_put_failure;
+ }
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
- msg = NULL;
if (ret == 0)
return 0;
wpa_printf(MSG_DEBUG, "nl80211: Failed to start radar detection: "
"%d (%s)", ret, strerror(-ret));
-nla_put_failure:
- nlmsg_free(msg);
return -1;
}
@@ -11684,16 +6971,12 @@
if (!dst)
return -EINVAL;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_TDLS_MGMT);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst);
- NLA_PUT_U8(msg, NL80211_ATTR_TDLS_ACTION, action_code);
- NLA_PUT_U8(msg, NL80211_ATTR_TDLS_DIALOG_TOKEN, dialog_token);
- NLA_PUT_U16(msg, NL80211_ATTR_STATUS_CODE, status_code);
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_TDLS_MGMT)) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dst) ||
+ nla_put_u8(msg, NL80211_ATTR_TDLS_ACTION, action_code) ||
+ nla_put_u8(msg, NL80211_ATTR_TDLS_DIALOG_TOKEN, dialog_token) ||
+ nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, status_code))
+ goto fail;
if (peer_capab) {
/*
* The internal enum tdls_peer_capability definition is
@@ -11701,15 +6984,18 @@
* nl80211_tdls_peer_capability, so no conversion is needed
* here.
*/
- NLA_PUT_U32(msg, NL80211_ATTR_TDLS_PEER_CAPABILITY, peer_capab);
+ if (nla_put_u32(msg, NL80211_ATTR_TDLS_PEER_CAPABILITY,
+ peer_capab))
+ goto fail;
}
- if (initiator)
- NLA_PUT_FLAG(msg, NL80211_ATTR_TDLS_INITIATOR);
- NLA_PUT(msg, NL80211_ATTR_IE, len, buf);
+ if ((initiator &&
+ nla_put_flag(msg, NL80211_ATTR_TDLS_INITIATOR)) ||
+ nla_put(msg, NL80211_ATTR_IE, len, buf))
+ goto fail;
return send_and_recv_msgs(drv, msg, NULL, NULL);
-nla_put_failure:
+fail:
nlmsg_free(msg);
return -ENOBUFS;
}
@@ -11749,158 +7035,75 @@
return -EINVAL;
}
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_TDLS_OPER);
- NLA_PUT_U8(msg, NL80211_ATTR_TDLS_OPERATION, nl80211_oper);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, peer);
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_TDLS_OPER)) ||
+ nla_put_u8(msg, NL80211_ATTR_TDLS_OPERATION, nl80211_oper) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
return send_and_recv_msgs(drv, msg, NULL, NULL);
+}
-nla_put_failure:
- nlmsg_free(msg);
- return -ENOBUFS;
+
+static int
+nl80211_tdls_enable_channel_switch(void *priv, const u8 *addr, u8 oper_class,
+ const struct hostapd_freq_params *params)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret = -ENOBUFS;
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT) ||
+ !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH))
+ return -EOPNOTSUPP;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Enable TDLS channel switch " MACSTR
+ " oper_class=%u freq=%u",
+ MAC2STR(addr), oper_class, params->freq);
+ msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_TDLS_CHANNEL_SWITCH);
+ if (!msg ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
+ nla_put_u8(msg, NL80211_ATTR_OPER_CLASS, oper_class) ||
+ (ret = nl80211_put_freq_params(msg, params))) {
+ nlmsg_free(msg);
+ wpa_printf(MSG_DEBUG, "nl80211: Could not build TDLS chan switch");
+ return ret;
+ }
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL);
+}
+
+
+static int
+nl80211_tdls_disable_channel_switch(void *priv, const u8 *addr)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT) ||
+ !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH))
+ return -EOPNOTSUPP;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Disable TDLS channel switch " MACSTR,
+ MAC2STR(addr));
+ msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH);
+ if (!msg ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
+ nlmsg_free(msg);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Could not build TDLS cancel chan switch");
+ return -ENOBUFS;
+ }
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL);
}
#endif /* CONFIG TDLS */
-#ifdef ANDROID
-
-typedef struct android_wifi_priv_cmd {
- char *buf;
- int used_len;
- int total_len;
-} android_wifi_priv_cmd;
-
-static int drv_errors = 0;
-
-static void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv)
-{
- drv_errors++;
- if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
- drv_errors = 0;
- wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
- }
-}
-
-
-static int android_priv_cmd(struct i802_bss *bss, const char *cmd)
-{
- struct wpa_driver_nl80211_data *drv = bss->drv;
- struct ifreq ifr;
- android_wifi_priv_cmd priv_cmd;
- char buf[MAX_DRV_CMD_SIZE];
- int ret;
-
- os_memset(&ifr, 0, sizeof(ifr));
- os_memset(&priv_cmd, 0, sizeof(priv_cmd));
- os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
-
- os_memset(buf, 0, sizeof(buf));
- os_strlcpy(buf, cmd, sizeof(buf));
-
- priv_cmd.buf = buf;
- priv_cmd.used_len = sizeof(buf);
- priv_cmd.total_len = sizeof(buf);
- ifr.ifr_data = &priv_cmd;
-
- ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
- if (ret < 0) {
- wpa_printf(MSG_ERROR, "%s: failed to issue private commands",
- __func__);
- wpa_driver_send_hang_msg(drv);
- return ret;
- }
-
- drv_errors = 0;
- return 0;
-}
-
-
-static int android_pno_start(struct i802_bss *bss,
- struct wpa_driver_scan_params *params)
-{
- struct wpa_driver_nl80211_data *drv = bss->drv;
- struct ifreq ifr;
- android_wifi_priv_cmd priv_cmd;
- int ret = 0, i = 0, bp;
- char buf[WEXT_PNO_MAX_COMMAND_SIZE];
-
- bp = WEXT_PNOSETUP_HEADER_SIZE;
- os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp);
- buf[bp++] = WEXT_PNO_TLV_PREFIX;
- buf[bp++] = WEXT_PNO_TLV_VERSION;
- buf[bp++] = WEXT_PNO_TLV_SUBVERSION;
- buf[bp++] = WEXT_PNO_TLV_RESERVED;
-
- while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) {
- /* Check that there is enough space needed for 1 more SSID, the
- * other sections and null termination */
- if ((bp + WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN +
- WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf))
- break;
- wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan",
- params->ssids[i].ssid,
- params->ssids[i].ssid_len);
- buf[bp++] = WEXT_PNO_SSID_SECTION;
- buf[bp++] = params->ssids[i].ssid_len;
- os_memcpy(&buf[bp], params->ssids[i].ssid,
- params->ssids[i].ssid_len);
- bp += params->ssids[i].ssid_len;
- i++;
- }
-
- buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION;
- os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x",
- WEXT_PNO_SCAN_INTERVAL);
- bp += WEXT_PNO_SCAN_INTERVAL_LENGTH;
-
- buf[bp++] = WEXT_PNO_REPEAT_SECTION;
- os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x",
- WEXT_PNO_REPEAT);
- bp += WEXT_PNO_REPEAT_LENGTH;
-
- buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION;
- os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x",
- WEXT_PNO_MAX_REPEAT);
- bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1;
-
- memset(&ifr, 0, sizeof(ifr));
- memset(&priv_cmd, 0, sizeof(priv_cmd));
- os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
-
- priv_cmd.buf = buf;
- priv_cmd.used_len = bp;
- priv_cmd.total_len = bp;
- ifr.ifr_data = &priv_cmd;
-
- ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
-
- if (ret < 0) {
- wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d",
- ret);
- wpa_driver_send_hang_msg(drv);
- return ret;
- }
-
- drv_errors = 0;
-
- return android_priv_cmd(bss, "PNOFORCE 1");
-}
-
-
-static int android_pno_stop(struct i802_bss *bss)
-{
- return android_priv_cmd(bss, "PNOFORCE 0");
-}
-
-#endif /* ANDROID */
-
-
static int driver_nl80211_set_key(const char *ifname, void *priv,
enum wpa_alg alg, const u8 *addr,
int key_idx, int set_tx,
@@ -11964,7 +7167,7 @@
static int driver_nl80211_sta_remove(void *priv, const u8 *addr)
{
struct i802_bss *bss = priv;
- return wpa_driver_nl80211_sta_remove(bss, addr);
+ return wpa_driver_nl80211_sta_remove(bss, addr, -1, 0);
}
@@ -12014,15 +7217,13 @@
struct wpa_driver_nl80211_data *drv = bss->drv;
u16 mdid = WPA_GET_LE16(md);
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
wpa_printf(MSG_DEBUG, "nl80211: Updating FT IEs");
- nl80211_cmd(drv, msg, 0, NL80211_CMD_UPDATE_FT_IES);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
- NLA_PUT(msg, NL80211_ATTR_IE, ies_len, ies);
- NLA_PUT_U16(msg, NL80211_ATTR_MDID, mdid);
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_UPDATE_FT_IES)) ||
+ nla_put(msg, NL80211_ATTR_IE, ies_len, ies) ||
+ nla_put_u16(msg, NL80211_ATTR_MDID, mdid)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
if (ret) {
@@ -12031,10 +7232,6 @@
}
return ret;
-
-nla_put_failure:
- nlmsg_free(msg);
- return -ENOBUFS;
}
@@ -12103,14 +7300,14 @@
bss->added_bridge ? "added_bridge=1\n" : "",
bss->in_deinit ? "in_deinit=1\n" : "",
bss->if_dynamic ? "if_dynamic=1\n" : "");
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
if (bss->wdev_id_set) {
res = os_snprintf(pos, end - pos, "wdev_id=%llu\n",
(unsigned long long) bss->wdev_id);
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
}
@@ -12132,7 +7329,7 @@
"monitor_refcount=%d\n"
"last_mgmt_freq=%u\n"
"eapol_tx_sock=%d\n"
- "%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ "%s%s%s%s%s%s%s%s%s%s%s%s%s",
drv->phyname,
MAC2STR(drv->perm_addr),
drv->ifindex,
@@ -12168,9 +7365,8 @@
drv->ignore_next_local_disconnect ?
"ignore_next_local_disconnect=1\n" : "",
drv->ignore_next_local_deauth ?
- "ignore_next_local_deauth=1\n" : "",
- drv->allow_p2p_device ? "allow_p2p_device=1\n" : "");
- if (res < 0 || res >= end - pos)
+ "ignore_next_local_deauth=1\n" : "");
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
@@ -12179,7 +7375,8 @@
"capa.key_mgmt=0x%x\n"
"capa.enc=0x%x\n"
"capa.auth=0x%x\n"
- "capa.flags=0x%x\n"
+ "capa.flags=0x%llx\n"
+ "capa.rrm_flags=0x%x\n"
"capa.max_scan_ssids=%d\n"
"capa.max_sched_scan_ssids=%d\n"
"capa.sched_scan_supported=%d\n"
@@ -12188,11 +7385,14 @@
"capa.max_stations=%u\n"
"capa.probe_resp_offloads=0x%x\n"
"capa.max_acl_mac_addrs=%u\n"
- "capa.num_multichan_concurrent=%u\n",
+ "capa.num_multichan_concurrent=%u\n"
+ "capa.mac_addr_rand_sched_scan_supported=%d\n"
+ "capa.mac_addr_rand_scan_supported=%d\n",
drv->capa.key_mgmt,
drv->capa.enc,
drv->capa.auth,
- drv->capa.flags,
+ (unsigned long long) drv->capa.flags,
+ drv->capa.rrm_flags,
drv->capa.max_scan_ssids,
drv->capa.max_sched_scan_ssids,
drv->capa.sched_scan_supported,
@@ -12201,8 +7401,10 @@
drv->capa.max_stations,
drv->capa.probe_resp_offloads,
drv->capa.max_acl_mac_addrs,
- drv->capa.num_multichan_concurrent);
- if (res < 0 || res >= end - pos)
+ drv->capa.num_multichan_concurrent,
+ drv->capa.mac_addr_rand_sched_scan_supported,
+ drv->capa.mac_addr_rand_scan_supported);
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
}
@@ -12213,35 +7415,27 @@
static int set_beacon_data(struct nl_msg *msg, struct beacon_data *settings)
{
- if (settings->head)
- NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD,
- settings->head_len, settings->head);
-
- if (settings->tail)
- NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL,
- settings->tail_len, settings->tail);
-
- if (settings->beacon_ies)
- NLA_PUT(msg, NL80211_ATTR_IE,
- settings->beacon_ies_len, settings->beacon_ies);
-
- if (settings->proberesp_ies)
- NLA_PUT(msg, NL80211_ATTR_IE_PROBE_RESP,
- settings->proberesp_ies_len, settings->proberesp_ies);
-
- if (settings->assocresp_ies)
- NLA_PUT(msg,
- NL80211_ATTR_IE_ASSOC_RESP,
- settings->assocresp_ies_len, settings->assocresp_ies);
-
- if (settings->probe_resp)
- NLA_PUT(msg, NL80211_ATTR_PROBE_RESP,
- settings->probe_resp_len, settings->probe_resp);
+ if ((settings->head &&
+ nla_put(msg, NL80211_ATTR_BEACON_HEAD,
+ settings->head_len, settings->head)) ||
+ (settings->tail &&
+ nla_put(msg, NL80211_ATTR_BEACON_TAIL,
+ settings->tail_len, settings->tail)) ||
+ (settings->beacon_ies &&
+ nla_put(msg, NL80211_ATTR_IE,
+ settings->beacon_ies_len, settings->beacon_ies)) ||
+ (settings->proberesp_ies &&
+ nla_put(msg, NL80211_ATTR_IE_PROBE_RESP,
+ settings->proberesp_ies_len, settings->proberesp_ies)) ||
+ (settings->assocresp_ies &&
+ nla_put(msg, NL80211_ATTR_IE_ASSOC_RESP,
+ settings->assocresp_ies_len, settings->assocresp_ies)) ||
+ (settings->probe_resp &&
+ nla_put(msg, NL80211_ATTR_PROBE_RESP,
+ settings->probe_resp_len, settings->probe_resp)))
+ return -ENOBUFS;
return 0;
-
-nla_put_failure:
- return -ENOBUFS;
}
@@ -12283,20 +7477,14 @@
settings->cs_count)))
return -EINVAL;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_CHANNEL_SWITCH);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
- NLA_PUT_U32(msg, NL80211_ATTR_CH_SWITCH_COUNT, settings->cs_count);
- ret = nl80211_put_freq_params(msg, &settings->freq_params);
- if (ret)
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_CHANNEL_SWITCH)) ||
+ nla_put_u32(msg, NL80211_ATTR_CH_SWITCH_COUNT,
+ settings->cs_count) ||
+ (ret = nl80211_put_freq_params(msg, &settings->freq_params)) ||
+ (settings->block_tx &&
+ nla_put_flag(msg, NL80211_ATTR_CH_SWITCH_BLOCK_TX)))
goto error;
- if (settings->block_tx)
- NLA_PUT_FLAG(msg, NL80211_ATTR_CH_SWITCH_BLOCK_TX);
-
/* beacon_after params */
ret = set_beacon_data(msg, &settings->beacon_after);
if (ret)
@@ -12305,18 +7493,18 @@
/* beacon_csa params */
beacon_csa = nla_nest_start(msg, NL80211_ATTR_CSA_IES);
if (!beacon_csa)
- goto nla_put_failure;
+ goto fail;
ret = set_beacon_data(msg, &settings->beacon_csa);
if (ret)
goto error;
- NLA_PUT_U16(msg, NL80211_ATTR_CSA_C_OFF_BEACON,
- settings->counter_offset_beacon);
-
- if (settings->beacon_csa.probe_resp)
- NLA_PUT_U16(msg, NL80211_ATTR_CSA_C_OFF_PRESP,
- settings->counter_offset_presp);
+ if (nla_put_u16(msg, NL80211_ATTR_CSA_C_OFF_BEACON,
+ settings->counter_offset_beacon) ||
+ (settings->beacon_csa.probe_resp &&
+ nla_put_u16(msg, NL80211_ATTR_CSA_C_OFF_PRESP,
+ settings->counter_offset_presp)))
+ goto fail;
nla_nest_end(msg, beacon_csa);
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -12326,7 +7514,7 @@
}
return ret;
-nla_put_failure:
+fail:
ret = -ENOBUFS;
error:
nlmsg_free(msg);
@@ -12335,6 +7523,66 @@
}
+static int nl80211_add_ts(void *priv, u8 tsid, const u8 *addr,
+ u8 user_priority, u16 admitted_time)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: add_ts request: tsid=%u admitted_time=%u up=%d",
+ tsid, admitted_time, user_priority);
+
+ if (!is_sta_interface(drv->nlmode))
+ return -ENOTSUP;
+
+ msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_ADD_TX_TS);
+ if (!msg ||
+ nla_put_u8(msg, NL80211_ATTR_TSID, tsid) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
+ nla_put_u8(msg, NL80211_ATTR_USER_PRIO, user_priority) ||
+ nla_put_u16(msg, NL80211_ATTR_ADMITTED_TIME, admitted_time)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret)
+ wpa_printf(MSG_DEBUG, "nl80211: add_ts failed err=%d (%s)",
+ ret, strerror(-ret));
+ return ret;
+}
+
+
+static int nl80211_del_ts(void *priv, u8 tsid, const u8 *addr)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "nl80211: del_ts request: tsid=%u", tsid);
+
+ if (!is_sta_interface(drv->nlmode))
+ return -ENOTSUP;
+
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_DEL_TX_TS)) ||
+ nla_put_u8(msg, NL80211_ATTR_TSID, tsid) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret)
+ wpa_printf(MSG_DEBUG, "nl80211: del_ts failed err=%d (%s)",
+ ret, strerror(-ret));
+ return ret;
+}
+
+
#ifdef CONFIG_TESTING_OPTIONS
static int cmd_reply_handler(struct nl_msg *msg, void *arg)
{
@@ -12397,16 +7645,16 @@
struct nl_msg *msg;
int ret;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
#ifdef CONFIG_TESTING_OPTIONS
if (vendor_id == 0xffffffff) {
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
nl80211_cmd(drv, msg, 0, subcmd);
if (nlmsg_append(msg, (void *) data, data_len, NLMSG_ALIGNTO) <
0)
- goto nla_put_failure;
+ goto fail;
ret = send_and_recv_msgs(drv, msg, cmd_reply_handler, buf);
if (ret)
wpa_printf(MSG_DEBUG, "nl80211: command failed err=%d",
@@ -12415,13 +7663,12 @@
}
#endif /* CONFIG_TESTING_OPTIONS */
- nl80211_cmd(drv, msg, 0, NL80211_CMD_VENDOR);
- if (nl80211_set_iface_id(msg, bss) < 0)
- goto nla_put_failure;
- NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_ID, vendor_id);
- NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_SUBCMD, subcmd);
- if (data)
- NLA_PUT(msg, NL80211_ATTR_VENDOR_DATA, data_len, data);
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, vendor_id) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, subcmd) ||
+ (data &&
+ nla_put(msg, NL80211_ATTR_VENDOR_DATA, data_len, data)))
+ goto fail;
ret = send_and_recv_msgs(drv, msg, vendor_reply_handler, buf);
if (ret)
@@ -12429,7 +7676,7 @@
ret);
return ret;
-nla_put_failure:
+fail:
nlmsg_free(msg);
return -ENOBUFS;
}
@@ -12443,26 +7690,20 @@
struct nl_msg *msg;
int ret;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
wpa_hexdump(MSG_DEBUG, "nl80211: Setting QoS Map",
qos_map_set, qos_map_set_len);
- nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_QOS_MAP);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
- NLA_PUT(msg, NL80211_ATTR_QOS_MAP, qos_map_set_len, qos_map_set);
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_QOS_MAP)) ||
+ nla_put(msg, NL80211_ATTR_QOS_MAP, qos_map_set_len, qos_map_set)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
if (ret)
wpa_printf(MSG_DEBUG, "nl80211: Setting QoS Map failed");
return ret;
-
-nla_put_failure:
- nlmsg_free(msg);
- return -ENOBUFS;
}
@@ -12475,33 +7716,28 @@
struct nlattr *wowlan_triggers;
int ret;
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
wpa_printf(MSG_DEBUG, "nl80211: Setting wowlan");
- nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WOWLAN);
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
- wowlan_triggers = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS);
- if (!wowlan_triggers)
- goto nla_put_failure;
-
- if (triggers->any)
- NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_ANY);
- if (triggers->disconnect)
- NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_DISCONNECT);
- if (triggers->magic_pkt)
- NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT);
- if (triggers->gtk_rekey_failure)
- NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE);
- if (triggers->eap_identity_req)
- NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST);
- if (triggers->four_way_handshake)
- NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE);
- if (triggers->rfkill_release)
- NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE);
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_WOWLAN)) ||
+ !(wowlan_triggers = nla_nest_start(msg,
+ NL80211_ATTR_WOWLAN_TRIGGERS)) ||
+ (triggers->any &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
+ (triggers->disconnect &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
+ (triggers->magic_pkt &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
+ (triggers->gtk_rekey_failure &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
+ (triggers->eap_identity_req &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
+ (triggers->four_way_handshake &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
+ (triggers->rfkill_release &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
nla_nest_end(msg, wowlan_triggers);
@@ -12510,10 +7746,6 @@
wpa_printf(MSG_DEBUG, "nl80211: Setting wowlan failed");
return ret;
-
-nla_put_failure:
- nlmsg_free(msg);
- return -ENOBUFS;
}
@@ -12532,32 +7764,22 @@
return -1;
}
- msg = nlmsg_alloc();
- if (!msg)
- return -ENOMEM;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_VENDOR);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
- NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA);
- NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_SUBCMD,
- QCA_NL80211_VENDOR_SUBCMD_ROAMING);
-
- params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
- if (!params)
- goto nla_put_failure;
- NLA_PUT_U32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY,
- allowed ? QCA_ROAMING_ALLOWED_WITHIN_ESS :
- QCA_ROAMING_NOT_ALLOWED);
- if (bssid)
- NLA_PUT(msg, QCA_WLAN_VENDOR_ATTR_MAC_ADDR, ETH_ALEN, bssid);
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_ROAMING) ||
+ !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY,
+ allowed ? QCA_ROAMING_ALLOWED_WITHIN_ESS :
+ QCA_ROAMING_NOT_ALLOWED) ||
+ (bssid &&
+ nla_put(msg, QCA_WLAN_VENDOR_ATTR_MAC_ADDR, ETH_ALEN, bssid))) {
+ nlmsg_free(msg);
+ return -1;
+ }
nla_nest_end(msg, params);
return send_and_recv_msgs(drv, msg, NULL, NULL);
-
- nla_put_failure:
- nlmsg_free(msg);
- return -1;
}
@@ -12601,6 +7823,472 @@
}
+#ifdef CONFIG_MESH
+
+static int wpa_driver_nl80211_init_mesh(void *priv)
+{
+ if (wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_MESH_POINT)) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Failed to set interface into mesh mode");
+ return -1;
+ }
+ return 0;
+}
+
+
+static int nl80211_put_mesh_id(struct nl_msg *msg, const u8 *mesh_id,
+ size_t mesh_id_len)
+{
+ if (mesh_id) {
+ wpa_hexdump_ascii(MSG_DEBUG, " * Mesh ID (SSID)",
+ mesh_id, mesh_id_len);
+ return nla_put(msg, NL80211_ATTR_MESH_ID, mesh_id_len, mesh_id);
+ }
+
+ return 0;
+}
+
+
+static int
+wpa_driver_nl80211_join_mesh(void *priv,
+ struct wpa_driver_mesh_join_params *params)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *container;
+ int ret = -1;
+ u32 timeout;
+
+ wpa_printf(MSG_DEBUG, "nl80211: mesh join (ifindex=%d)", drv->ifindex);
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_JOIN_MESH);
+ if (!msg ||
+ nl80211_put_freq_params(msg, ¶ms->freq) ||
+ nl80211_put_basic_rates(msg, params->basic_rates) ||
+ nl80211_put_mesh_id(msg, params->meshid, params->meshid_len) ||
+ nl80211_put_beacon_int(msg, params->beacon_int))
+ goto fail;
+
+ wpa_printf(MSG_DEBUG, " * flags=%08X", params->flags);
+
+ container = nla_nest_start(msg, NL80211_ATTR_MESH_SETUP);
+ if (!container)
+ goto fail;
+
+ if (params->ies) {
+ wpa_hexdump(MSG_DEBUG, " * IEs", params->ies, params->ie_len);
+ if (nla_put(msg, NL80211_MESH_SETUP_IE, params->ie_len,
+ params->ies))
+ goto fail;
+ }
+ /* WPA_DRIVER_MESH_FLAG_OPEN_AUTH is treated as default by nl80211 */
+ if (params->flags & WPA_DRIVER_MESH_FLAG_SAE_AUTH) {
+ if (nla_put_u8(msg, NL80211_MESH_SETUP_AUTH_PROTOCOL, 0x1) ||
+ nla_put_flag(msg, NL80211_MESH_SETUP_USERSPACE_AUTH))
+ goto fail;
+ }
+ if ((params->flags & WPA_DRIVER_MESH_FLAG_AMPE) &&
+ nla_put_flag(msg, NL80211_MESH_SETUP_USERSPACE_AMPE))
+ goto fail;
+ if ((params->flags & WPA_DRIVER_MESH_FLAG_USER_MPM) &&
+ nla_put_flag(msg, NL80211_MESH_SETUP_USERSPACE_MPM))
+ goto fail;
+ nla_nest_end(msg, container);
+
+ container = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG);
+ if (!container)
+ goto fail;
+
+ if (!(params->conf.flags & WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS) &&
+ nla_put_u32(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS, 0))
+ goto fail;
+ if ((params->conf.flags & WPA_DRIVER_MESH_FLAG_DRIVER_MPM) &&
+ nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
+ params->max_peer_links))
+ goto fail;
+
+ /*
+ * Set NL80211_MESHCONF_PLINK_TIMEOUT even if user mpm is used because
+ * the timer could disconnect stations even in that case.
+ *
+ * Set 0xffffffff instead of 0 because NL80211_MESHCONF_PLINK_TIMEOUT
+ * does not allow 0.
+ */
+ timeout = params->conf.peer_link_timeout;
+ if ((params->flags & WPA_DRIVER_MESH_FLAG_USER_MPM) || timeout == 0)
+ timeout = 0xffffffff;
+ if (nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT, timeout)) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to set PLINK_TIMEOUT");
+ goto fail;
+ }
+
+ nla_nest_end(msg, container);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: mesh join failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ goto fail;
+ }
+ ret = 0;
+ bss->freq = params->freq.freq;
+ wpa_printf(MSG_DEBUG, "nl80211: mesh join request send successfully");
+
+fail:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_leave_mesh(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "nl80211: mesh leave (ifindex=%d)", drv->ifindex);
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_LEAVE_MESH);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: mesh leave failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: mesh leave request send successfully");
+ }
+
+ if (wpa_driver_nl80211_set_mode(drv->first_bss,
+ NL80211_IFTYPE_STATION)) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Failed to set interface into station mode");
+ }
+ return ret;
+}
+
+#endif /* CONFIG_MESH */
+
+
+static int wpa_driver_br_add_ip_neigh(void *priv, u8 version,
+ const u8 *ipaddr, int prefixlen,
+ const u8 *addr)
+{
+#ifdef CONFIG_LIBNL3_ROUTE
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct rtnl_neigh *rn;
+ struct nl_addr *nl_ipaddr = NULL;
+ struct nl_addr *nl_lladdr = NULL;
+ int family, addrsize;
+ int res;
+
+ if (!ipaddr || prefixlen == 0 || !addr)
+ return -EINVAL;
+
+ if (bss->br_ifindex == 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: bridge must be set before adding an ip neigh to it");
+ return -1;
+ }
+
+ if (!drv->rtnl_sk) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: nl_sock for NETLINK_ROUTE is not initialized");
+ return -1;
+ }
+
+ if (version == 4) {
+ family = AF_INET;
+ addrsize = 4;
+ } else if (version == 6) {
+ family = AF_INET6;
+ addrsize = 16;
+ } else {
+ return -EINVAL;
+ }
+
+ rn = rtnl_neigh_alloc();
+ if (rn == NULL)
+ return -ENOMEM;
+
+ /* set the destination ip address for neigh */
+ nl_ipaddr = nl_addr_build(family, (void *) ipaddr, addrsize);
+ if (nl_ipaddr == NULL) {
+ wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed");
+ res = -ENOMEM;
+ goto errout;
+ }
+ nl_addr_set_prefixlen(nl_ipaddr, prefixlen);
+ res = rtnl_neigh_set_dst(rn, nl_ipaddr);
+ if (res) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: neigh set destination addr failed");
+ goto errout;
+ }
+
+ /* set the corresponding lladdr for neigh */
+ nl_lladdr = nl_addr_build(AF_BRIDGE, (u8 *) addr, ETH_ALEN);
+ if (nl_lladdr == NULL) {
+ wpa_printf(MSG_DEBUG, "nl80211: neigh set lladdr failed");
+ res = -ENOMEM;
+ goto errout;
+ }
+ rtnl_neigh_set_lladdr(rn, nl_lladdr);
+
+ rtnl_neigh_set_ifindex(rn, bss->br_ifindex);
+ rtnl_neigh_set_state(rn, NUD_PERMANENT);
+
+ res = rtnl_neigh_add(drv->rtnl_sk, rn, NLM_F_CREATE);
+ if (res) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Adding bridge ip neigh failed: %s",
+ strerror(errno));
+ }
+errout:
+ if (nl_lladdr)
+ nl_addr_put(nl_lladdr);
+ if (nl_ipaddr)
+ nl_addr_put(nl_ipaddr);
+ if (rn)
+ rtnl_neigh_put(rn);
+ return res;
+#else /* CONFIG_LIBNL3_ROUTE */
+ return -1;
+#endif /* CONFIG_LIBNL3_ROUTE */
+}
+
+
+static int wpa_driver_br_delete_ip_neigh(void *priv, u8 version,
+ const u8 *ipaddr)
+{
+#ifdef CONFIG_LIBNL3_ROUTE
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct rtnl_neigh *rn;
+ struct nl_addr *nl_ipaddr;
+ int family, addrsize;
+ int res;
+
+ if (!ipaddr)
+ return -EINVAL;
+
+ if (version == 4) {
+ family = AF_INET;
+ addrsize = 4;
+ } else if (version == 6) {
+ family = AF_INET6;
+ addrsize = 16;
+ } else {
+ return -EINVAL;
+ }
+
+ if (bss->br_ifindex == 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: bridge must be set to delete an ip neigh");
+ return -1;
+ }
+
+ if (!drv->rtnl_sk) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: nl_sock for NETLINK_ROUTE is not initialized");
+ return -1;
+ }
+
+ rn = rtnl_neigh_alloc();
+ if (rn == NULL)
+ return -ENOMEM;
+
+ /* set the destination ip address for neigh */
+ nl_ipaddr = nl_addr_build(family, (void *) ipaddr, addrsize);
+ if (nl_ipaddr == NULL) {
+ wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed");
+ res = -ENOMEM;
+ goto errout;
+ }
+ res = rtnl_neigh_set_dst(rn, nl_ipaddr);
+ if (res) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: neigh set destination addr failed");
+ goto errout;
+ }
+
+ rtnl_neigh_set_ifindex(rn, bss->br_ifindex);
+
+ res = rtnl_neigh_delete(drv->rtnl_sk, rn, 0);
+ if (res) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Deleting bridge ip neigh failed: %s",
+ strerror(errno));
+ }
+errout:
+ if (nl_ipaddr)
+ nl_addr_put(nl_ipaddr);
+ if (rn)
+ rtnl_neigh_put(rn);
+ return res;
+#else /* CONFIG_LIBNL3_ROUTE */
+ return -1;
+#endif /* CONFIG_LIBNL3_ROUTE */
+}
+
+
+static int linux_write_system_file(const char *path, unsigned int val)
+{
+ char buf[50];
+ int fd, len;
+
+ len = os_snprintf(buf, sizeof(buf), "%u\n", val);
+ if (os_snprintf_error(sizeof(buf), len))
+ return -1;
+
+ fd = open(path, O_WRONLY);
+ if (fd < 0)
+ return -1;
+
+ if (write(fd, buf, len) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to write Linux system file: %s with the value of %d",
+ path, val);
+ close(fd);
+ return -1;
+ }
+ close(fd);
+
+ return 0;
+}
+
+
+static const char * drv_br_port_attr_str(enum drv_br_port_attr attr)
+{
+ switch (attr) {
+ case DRV_BR_PORT_ATTR_PROXYARP:
+ return "proxyarp";
+ case DRV_BR_PORT_ATTR_HAIRPIN_MODE:
+ return "hairpin_mode";
+ }
+
+ return NULL;
+}
+
+
+static int wpa_driver_br_port_set_attr(void *priv, enum drv_br_port_attr attr,
+ unsigned int val)
+{
+ struct i802_bss *bss = priv;
+ char path[128];
+ const char *attr_txt;
+
+ attr_txt = drv_br_port_attr_str(attr);
+ if (attr_txt == NULL)
+ return -EINVAL;
+
+ os_snprintf(path, sizeof(path), "/sys/class/net/%s/brport/%s",
+ bss->ifname, attr_txt);
+
+ if (linux_write_system_file(path, val))
+ return -1;
+
+ return 0;
+}
+
+
+static const char * drv_br_net_param_str(enum drv_br_net_param param)
+{
+ switch (param) {
+ case DRV_BR_NET_PARAM_GARP_ACCEPT:
+ return "arp_accept";
+ }
+
+ return NULL;
+}
+
+
+static int wpa_driver_br_set_net_param(void *priv, enum drv_br_net_param param,
+ unsigned int val)
+{
+ struct i802_bss *bss = priv;
+ char path[128];
+ const char *param_txt;
+ int ip_version = 4;
+
+ param_txt = drv_br_net_param_str(param);
+ if (param_txt == NULL)
+ return -EINVAL;
+
+ switch (param) {
+ case DRV_BR_NET_PARAM_GARP_ACCEPT:
+ ip_version = 4;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ os_snprintf(path, sizeof(path), "/proc/sys/net/ipv%d/conf/%s/%s",
+ ip_version, bss->brname, param_txt);
+
+ if (linux_write_system_file(path, val))
+ return -1;
+
+ return 0;
+}
+
+
+static int hw_mode_to_qca_acs(enum hostapd_hw_mode hw_mode)
+{
+ switch (hw_mode) {
+ case HOSTAPD_MODE_IEEE80211B:
+ return QCA_ACS_MODE_IEEE80211B;
+ case HOSTAPD_MODE_IEEE80211G:
+ return QCA_ACS_MODE_IEEE80211G;
+ case HOSTAPD_MODE_IEEE80211A:
+ return QCA_ACS_MODE_IEEE80211A;
+ case HOSTAPD_MODE_IEEE80211AD:
+ return QCA_ACS_MODE_IEEE80211AD;
+ default:
+ return -1;
+ }
+}
+
+
+static int wpa_driver_do_acs(void *priv, struct drv_acs_params *params)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *data;
+ int ret;
+ int mode;
+
+ mode = hw_mode_to_qca_acs(params->hw_mode);
+ if (mode < 0)
+ return -1;
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_DO_ACS) ||
+ !(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+ nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE, mode) ||
+ (params->ht_enabled &&
+ nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED)) ||
+ (params->ht40_enabled &&
+ nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED))) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+ nla_nest_end(msg, data);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to invoke driver ACS function: %s",
+ strerror(errno));
+ }
+ return ret;
+}
+
+
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.name = "nl80211",
.desc = "Linux nl80211/cfg80211",
@@ -12628,7 +8316,7 @@
.if_add = wpa_driver_nl80211_if_add,
.if_remove = driver_nl80211_if_remove,
.send_mlme = driver_nl80211_send_mlme,
- .get_hw_feature_data = wpa_driver_nl80211_get_hw_feature_data,
+ .get_hw_feature_data = nl80211_get_hw_feature_data,
.sta_add = wpa_driver_nl80211_sta_add,
.sta_remove = driver_nl80211_sta_remove,
.hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,
@@ -12657,7 +8345,6 @@
.deinit_ap = wpa_driver_nl80211_deinit_ap,
.deinit_p2p_cli = wpa_driver_nl80211_deinit_p2p_cli,
.resume = wpa_driver_nl80211_resume,
- .send_ft_action = nl80211_send_ft_action,
.signal_monitor = nl80211_signal_monitor,
.signal_poll = nl80211_signal_poll,
.send_frame = nl80211_send_frame,
@@ -12675,6 +8362,8 @@
#ifdef CONFIG_TDLS
.send_tdls_mgmt = nl80211_send_tdls_mgmt,
.tdls_oper = nl80211_tdls_oper,
+ .tdls_enable_channel_switch = nl80211_tdls_enable_channel_switch,
+ .tdls_disable_channel_switch = nl80211_tdls_disable_channel_switch,
#endif /* CONFIG_TDLS */
.update_ft_ies = wpa_driver_nl80211_update_ft_ies,
.get_mac_addr = wpa_driver_nl80211_get_macaddr,
@@ -12694,4 +8383,16 @@
.set_wowlan = nl80211_set_wowlan,
.roaming = nl80211_roaming,
.set_mac_addr = nl80211_set_mac_addr,
+#ifdef CONFIG_MESH
+ .init_mesh = wpa_driver_nl80211_init_mesh,
+ .join_mesh = wpa_driver_nl80211_join_mesh,
+ .leave_mesh = wpa_driver_nl80211_leave_mesh,
+#endif /* CONFIG_MESH */
+ .br_add_ip_neigh = wpa_driver_br_add_ip_neigh,
+ .br_delete_ip_neigh = wpa_driver_br_delete_ip_neigh,
+ .br_port_set_attr = wpa_driver_br_port_set_attr,
+ .br_set_net_param = wpa_driver_br_set_net_param,
+ .add_tx_ts = nl80211_add_ts,
+ .del_tx_ts = nl80211_del_ts,
+ .do_acs = wpa_driver_do_acs,
};
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
new file mode 100644
index 0000000..4567f42
--- /dev/null
+++ b/src/drivers/driver_nl80211.h
@@ -0,0 +1,272 @@
+/*
+ * Driver interaction with Linux nl80211/cfg80211 - definitions
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2004, Instant802 Networks, Inc.
+ * Copyright (c) 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DRIVER_NL80211_H
+#define DRIVER_NL80211_H
+
+#include "nl80211_copy.h"
+#include "utils/list.h"
+#include "driver.h"
+
+#ifdef CONFIG_LIBNL20
+/* libnl 2.0 compatibility code */
+#define nl_handle nl_sock
+#define nl80211_handle_alloc nl_socket_alloc_cb
+#define nl80211_handle_destroy nl_socket_free
+#endif /* CONFIG_LIBNL20 */
+
+struct nl80211_global {
+ struct dl_list interfaces;
+ int if_add_ifindex;
+ u64 if_add_wdevid;
+ int if_add_wdevid_set;
+ struct netlink_data *netlink;
+ struct nl_cb *nl_cb;
+ struct nl_handle *nl;
+ int nl80211_id;
+ int ioctl_sock; /* socket for ioctl() use */
+
+ struct nl_handle *nl_event;
+};
+
+struct nl80211_wiphy_data {
+ struct dl_list list;
+ struct dl_list bsss;
+ struct dl_list drvs;
+
+ struct nl_handle *nl_beacons;
+ struct nl_cb *nl_cb;
+
+ int wiphy_idx;
+};
+
+struct i802_bss {
+ struct wpa_driver_nl80211_data *drv;
+ struct i802_bss *next;
+ int ifindex;
+ int br_ifindex;
+ u64 wdev_id;
+ char ifname[IFNAMSIZ + 1];
+ char brname[IFNAMSIZ];
+ unsigned int beacon_set:1;
+ unsigned int added_if_into_bridge:1;
+ unsigned int added_bridge:1;
+ unsigned int in_deinit:1;
+ unsigned int wdev_id_set:1;
+ unsigned int added_if:1;
+ unsigned int static_ap:1;
+
+ u8 addr[ETH_ALEN];
+
+ int freq;
+ int bandwidth;
+ int if_dynamic;
+
+ void *ctx;
+ struct nl_handle *nl_preq, *nl_mgmt;
+ struct nl_cb *nl_cb;
+
+ struct nl80211_wiphy_data *wiphy_data;
+ struct dl_list wiphy_list;
+};
+
+struct wpa_driver_nl80211_data {
+ struct nl80211_global *global;
+ struct dl_list list;
+ struct dl_list wiphy_list;
+ char phyname[32];
+ u8 perm_addr[ETH_ALEN];
+ void *ctx;
+ int ifindex;
+ int if_removed;
+ int if_disabled;
+ int ignore_if_down_event;
+ struct rfkill_data *rfkill;
+ struct wpa_driver_capa capa;
+ u8 *extended_capa, *extended_capa_mask;
+ unsigned int extended_capa_len;
+ int has_capability;
+
+ int operstate;
+
+ int scan_complete_events;
+ enum scan_states {
+ NO_SCAN, SCAN_REQUESTED, SCAN_STARTED, SCAN_COMPLETED,
+ SCAN_ABORTED, SCHED_SCAN_STARTED, SCHED_SCAN_STOPPED,
+ SCHED_SCAN_RESULTS
+ } scan_state;
+
+ u8 auth_bssid[ETH_ALEN];
+ u8 auth_attempt_bssid[ETH_ALEN];
+ u8 bssid[ETH_ALEN];
+ u8 prev_bssid[ETH_ALEN];
+ int associated;
+ u8 ssid[32];
+ size_t ssid_len;
+ enum nl80211_iftype nlmode;
+ enum nl80211_iftype ap_scan_as_station;
+ unsigned int assoc_freq;
+
+ int monitor_sock;
+ int monitor_ifidx;
+ int monitor_refcount;
+
+ unsigned int disabled_11b_rates:1;
+ unsigned int pending_remain_on_chan:1;
+ unsigned int in_interface_list:1;
+ unsigned int device_ap_sme:1;
+ unsigned int poll_command_supported:1;
+ unsigned int data_tx_status:1;
+ unsigned int scan_for_auth:1;
+ unsigned int retry_auth:1;
+ unsigned int use_monitor:1;
+ unsigned int ignore_next_local_disconnect:1;
+ unsigned int ignore_next_local_deauth:1;
+ unsigned int hostapd:1;
+ unsigned int start_mode_ap:1;
+ unsigned int start_iface_up:1;
+ unsigned int test_use_roc_tx:1;
+ unsigned int ignore_deauth_event:1;
+ unsigned int roaming_vendor_cmd_avail:1;
+ unsigned int dfs_vendor_cmd_avail:1;
+ unsigned int have_low_prio_scan:1;
+ unsigned int force_connect_cmd:1;
+ unsigned int addr_changed:1;
+ unsigned int get_features_vendor_cmd_avail:1;
+ unsigned int set_rekey_offload:1;
+
+ u64 remain_on_chan_cookie;
+ u64 send_action_cookie;
+
+ unsigned int last_mgmt_freq;
+
+ struct wpa_driver_scan_filter *filter_ssids;
+ size_t num_filter_ssids;
+
+ struct i802_bss *first_bss;
+
+ int eapol_tx_sock;
+
+ int eapol_sock; /* socket for EAPOL frames */
+
+ struct nl_handle *rtnl_sk; /* nl_sock for NETLINK_ROUTE */
+
+ int default_if_indices[16];
+ int *if_indices;
+ int num_if_indices;
+
+ /* From failed authentication command */
+ int auth_freq;
+ u8 auth_bssid_[ETH_ALEN];
+ u8 auth_ssid[32];
+ size_t auth_ssid_len;
+ int auth_alg;
+ u8 *auth_ie;
+ size_t auth_ie_len;
+ u8 auth_wep_key[4][16];
+ size_t auth_wep_key_len[4];
+ int auth_wep_tx_keyidx;
+ int auth_local_state_change;
+ int auth_p2p;
+};
+
+struct nl_msg;
+
+void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
+ struct nl_msg *msg, int flags, uint8_t cmd);
+struct nl_msg * nl80211_cmd_msg(struct i802_bss *bss, int flags, uint8_t cmd);
+struct nl_msg * nl80211_drv_msg(struct wpa_driver_nl80211_data *drv, int flags,
+ uint8_t cmd);
+struct nl_msg * nl80211_bss_msg(struct i802_bss *bss, int flags, uint8_t cmd);
+int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv, struct nl_msg *msg,
+ int (*valid_handler)(struct nl_msg *, void *),
+ void *valid_data);
+int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
+ const char *ifname, enum nl80211_iftype iftype,
+ const u8 *addr, int wds,
+ int (*handler)(struct nl_msg *, void *),
+ void *arg, int use_existing);
+void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv, int ifidx);
+unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv);
+enum chan_width convert2width(int width);
+void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv);
+struct i802_bss * get_bss_ifindex(struct wpa_driver_nl80211_data *drv,
+ int ifindex);
+int is_ap_interface(enum nl80211_iftype nlmode);
+int is_sta_interface(enum nl80211_iftype nlmode);
+int wpa_driver_nl80211_authenticate_retry(struct wpa_driver_nl80211_data *drv);
+int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv,
+ struct wpa_signal_info *sig);
+int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv,
+ struct wpa_signal_info *sig_change);
+int nl80211_get_wiphy_index(struct i802_bss *bss);
+int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
+ enum nl80211_iftype nlmode);
+int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
+ const u8 *addr, int cmd, u16 reason_code,
+ int local_state_change);
+
+int nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv);
+void nl80211_remove_monitor_interface(struct wpa_driver_nl80211_data *drv);
+int nl80211_send_monitor(struct wpa_driver_nl80211_data *drv,
+ const void *data, size_t len,
+ int encrypt, int noack);
+
+int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv);
+struct hostapd_hw_modes *
+nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags);
+
+int process_global_event(struct nl_msg *msg, void *arg);
+int process_bss_event(struct nl_msg *msg, void *arg);
+
+#ifdef ANDROID
+int android_nl_socket_set_nonblocking(struct nl_handle *handle);
+int android_genl_ctrl_resolve(struct nl_handle *handle, const char *name);
+int android_pno_start(struct i802_bss *bss,
+ struct wpa_driver_scan_params *params);
+int android_pno_stop(struct i802_bss *bss);
+extern int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf,
+ size_t buf_len);
+
+#ifdef ANDROID_P2P
+int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration);
+int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len);
+int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow);
+int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
+ const struct wpabuf *proberesp,
+ const struct wpabuf *assocresp);
+#endif /* ANDROID_P2P */
+#endif /* ANDROID */
+
+
+/* driver_nl80211_scan.c */
+
+struct nl80211_bss_info_arg {
+ struct wpa_driver_nl80211_data *drv;
+ struct wpa_scan_results *res;
+ unsigned int assoc_freq;
+ unsigned int ibss_freq;
+ u8 assoc_bssid[ETH_ALEN];
+};
+
+int bss_info_handler(struct nl_msg *msg, void *arg);
+void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx);
+int wpa_driver_nl80211_scan(struct i802_bss *bss,
+ struct wpa_driver_scan_params *params);
+int wpa_driver_nl80211_sched_scan(void *priv,
+ struct wpa_driver_scan_params *params,
+ u32 interval);
+int wpa_driver_nl80211_stop_sched_scan(void *priv);
+struct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv);
+void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv);
+
+#endif /* DRIVER_NL80211_H */
diff --git a/src/drivers/driver_nl80211_android.c b/src/drivers/driver_nl80211_android.c
new file mode 100644
index 0000000..3cc9a65
--- /dev/null
+++ b/src/drivers/driver_nl80211_android.c
@@ -0,0 +1,220 @@
+/*
+ * Driver interaction with Linux nl80211/cfg80211 - Android specific
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <fcntl.h>
+
+#include "utils/common.h"
+#include "driver_nl80211.h"
+#include "android_drv.h"
+
+
+typedef struct android_wifi_priv_cmd {
+ char *buf;
+ int used_len;
+ int total_len;
+} android_wifi_priv_cmd;
+
+static int drv_errors = 0;
+
+static void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv)
+{
+ drv_errors++;
+ if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
+ drv_errors = 0;
+ wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
+ }
+}
+
+
+static int android_priv_cmd(struct i802_bss *bss, const char *cmd)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct ifreq ifr;
+ android_wifi_priv_cmd priv_cmd;
+ char buf[MAX_DRV_CMD_SIZE];
+ int ret;
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_memset(&priv_cmd, 0, sizeof(priv_cmd));
+ os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
+
+ os_memset(buf, 0, sizeof(buf));
+ os_strlcpy(buf, cmd, sizeof(buf));
+
+ priv_cmd.buf = buf;
+ priv_cmd.used_len = sizeof(buf);
+ priv_cmd.total_len = sizeof(buf);
+ ifr.ifr_data = &priv_cmd;
+
+ ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "%s: failed to issue private commands",
+ __func__);
+ wpa_driver_send_hang_msg(drv);
+ return ret;
+ }
+
+ drv_errors = 0;
+ return 0;
+}
+
+
+int android_pno_start(struct i802_bss *bss,
+ struct wpa_driver_scan_params *params)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct ifreq ifr;
+ android_wifi_priv_cmd priv_cmd;
+ int ret = 0, i = 0, bp;
+ char buf[WEXT_PNO_MAX_COMMAND_SIZE];
+
+ bp = WEXT_PNOSETUP_HEADER_SIZE;
+ os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp);
+ buf[bp++] = WEXT_PNO_TLV_PREFIX;
+ buf[bp++] = WEXT_PNO_TLV_VERSION;
+ buf[bp++] = WEXT_PNO_TLV_SUBVERSION;
+ buf[bp++] = WEXT_PNO_TLV_RESERVED;
+
+ while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) {
+ /* Check that there is enough space needed for 1 more SSID, the
+ * other sections and null termination */
+ if ((bp + WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN +
+ WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf))
+ break;
+ wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan",
+ params->ssids[i].ssid,
+ params->ssids[i].ssid_len);
+ buf[bp++] = WEXT_PNO_SSID_SECTION;
+ buf[bp++] = params->ssids[i].ssid_len;
+ os_memcpy(&buf[bp], params->ssids[i].ssid,
+ params->ssids[i].ssid_len);
+ bp += params->ssids[i].ssid_len;
+ i++;
+ }
+
+ buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION;
+ os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x",
+ WEXT_PNO_SCAN_INTERVAL);
+ bp += WEXT_PNO_SCAN_INTERVAL_LENGTH;
+
+ buf[bp++] = WEXT_PNO_REPEAT_SECTION;
+ os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x",
+ WEXT_PNO_REPEAT);
+ bp += WEXT_PNO_REPEAT_LENGTH;
+
+ buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION;
+ os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x",
+ WEXT_PNO_MAX_REPEAT);
+ bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1;
+
+ memset(&ifr, 0, sizeof(ifr));
+ memset(&priv_cmd, 0, sizeof(priv_cmd));
+ os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
+
+ priv_cmd.buf = buf;
+ priv_cmd.used_len = bp;
+ priv_cmd.total_len = bp;
+ ifr.ifr_data = &priv_cmd;
+
+ ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
+
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d",
+ ret);
+ wpa_driver_send_hang_msg(drv);
+ return ret;
+ }
+
+ drv_errors = 0;
+
+ return android_priv_cmd(bss, "PNOFORCE 1");
+}
+
+
+int android_pno_stop(struct i802_bss *bss)
+{
+ return android_priv_cmd(bss, "PNOFORCE 0");
+}
+
+
+#ifdef ANDROID_P2P
+#ifdef ANDROID_P2P_STUB
+
+int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration)
+{
+ return 0;
+}
+
+
+int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len)
+{
+ return 0;
+}
+
+
+int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow)
+{
+ return -1;
+}
+
+
+int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
+ const struct wpabuf *proberesp,
+ const struct wpabuf *assocresp)
+{
+ return 0;
+}
+
+#endif /* ANDROID_P2P_STUB */
+#endif /* ANDROID_P2P */
+
+
+int android_nl_socket_set_nonblocking(struct nl_handle *handle)
+{
+ return fcntl(nl_socket_get_fd(handle), F_SETFL, O_NONBLOCK);
+}
+
+
+int android_genl_ctrl_resolve(struct nl_handle *handle, const char *name)
+{
+ /*
+ * Android ICS has very minimal genl_ctrl_resolve() implementation, so
+ * need to work around that.
+ */
+ struct nl_cache *cache = NULL;
+ struct genl_family *nl80211 = NULL;
+ int id = -1;
+
+ if (genl_ctrl_alloc_cache(handle, &cache) < 0) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
+ "netlink cache");
+ goto fail;
+ }
+
+ nl80211 = genl_ctrl_search_by_name(cache, name);
+ if (nl80211 == NULL)
+ goto fail;
+
+ id = genl_family_get_id(nl80211);
+
+fail:
+ if (nl80211)
+ genl_family_put(nl80211);
+ if (cache)
+ nl_cache_free(cache);
+
+ return id;
+}
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
new file mode 100644
index 0000000..36c8ce2
--- /dev/null
+++ b/src/drivers/driver_nl80211_capa.c
@@ -0,0 +1,1524 @@
+/*
+ * Driver interaction with Linux nl80211/cfg80211 - Capabilities
+ * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <netlink/genl/genl.h>
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "common/qca-vendor.h"
+#include "common/qca-vendor-attr.h"
+#include "driver_nl80211.h"
+
+
+static int protocol_feature_handler(struct nl_msg *msg, void *arg)
+{
+ u32 *feat = arg;
+ struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+
+ nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (tb_msg[NL80211_ATTR_PROTOCOL_FEATURES])
+ *feat = nla_get_u32(tb_msg[NL80211_ATTR_PROTOCOL_FEATURES]);
+
+ return NL_SKIP;
+}
+
+
+static u32 get_nl80211_protocol_features(struct wpa_driver_nl80211_data *drv)
+{
+ u32 feat = 0;
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return 0;
+
+ if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_PROTOCOL_FEATURES)) {
+ nlmsg_free(msg);
+ return 0;
+ }
+
+ if (send_and_recv_msgs(drv, msg, protocol_feature_handler, &feat) == 0)
+ return feat;
+
+ return 0;
+}
+
+
+struct wiphy_info_data {
+ struct wpa_driver_nl80211_data *drv;
+ struct wpa_driver_capa *capa;
+
+ unsigned int num_multichan_concurrent;
+
+ unsigned int error:1;
+ unsigned int device_ap_sme:1;
+ unsigned int poll_command_supported:1;
+ unsigned int data_tx_status:1;
+ unsigned int monitor_supported:1;
+ unsigned int auth_supported:1;
+ unsigned int connect_supported:1;
+ unsigned int p2p_go_supported:1;
+ unsigned int p2p_client_supported:1;
+ unsigned int p2p_concurrent:1;
+ unsigned int channel_switch_supported:1;
+ unsigned int set_qos_map_supported:1;
+ unsigned int have_low_prio_scan:1;
+ unsigned int wmm_ac_supported:1;
+ unsigned int mac_addr_rand_scan_supported:1;
+ unsigned int mac_addr_rand_sched_scan_supported:1;
+};
+
+
+static unsigned int probe_resp_offload_support(int supp_protocols)
+{
+ unsigned int prot = 0;
+
+ if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS)
+ prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS;
+ if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2)
+ prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2;
+ if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P)
+ prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P;
+ if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U)
+ prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING;
+
+ return prot;
+}
+
+
+static void wiphy_info_supported_iftypes(struct wiphy_info_data *info,
+ struct nlattr *tb)
+{
+ struct nlattr *nl_mode;
+ int i;
+
+ if (tb == NULL)
+ return;
+
+ nla_for_each_nested(nl_mode, tb, i) {
+ switch (nla_type(nl_mode)) {
+ case NL80211_IFTYPE_AP:
+ info->capa->flags |= WPA_DRIVER_FLAGS_AP;
+ break;
+ case NL80211_IFTYPE_MESH_POINT:
+ info->capa->flags |= WPA_DRIVER_FLAGS_MESH;
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ info->capa->flags |= WPA_DRIVER_FLAGS_IBSS;
+ break;
+ case NL80211_IFTYPE_P2P_DEVICE:
+ info->capa->flags |=
+ WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE;
+ break;
+ case NL80211_IFTYPE_P2P_GO:
+ info->p2p_go_supported = 1;
+ break;
+ case NL80211_IFTYPE_P2P_CLIENT:
+ info->p2p_client_supported = 1;
+ break;
+ case NL80211_IFTYPE_MONITOR:
+ info->monitor_supported = 1;
+ break;
+ }
+ }
+}
+
+
+static int wiphy_info_iface_comb_process(struct wiphy_info_data *info,
+ struct nlattr *nl_combi)
+{
+ struct nlattr *tb_comb[NUM_NL80211_IFACE_COMB];
+ struct nlattr *tb_limit[NUM_NL80211_IFACE_LIMIT];
+ struct nlattr *nl_limit, *nl_mode;
+ int err, rem_limit, rem_mode;
+ int combination_has_p2p = 0, combination_has_mgd = 0;
+ static struct nla_policy
+ iface_combination_policy[NUM_NL80211_IFACE_COMB] = {
+ [NL80211_IFACE_COMB_LIMITS] = { .type = NLA_NESTED },
+ [NL80211_IFACE_COMB_MAXNUM] = { .type = NLA_U32 },
+ [NL80211_IFACE_COMB_STA_AP_BI_MATCH] = { .type = NLA_FLAG },
+ [NL80211_IFACE_COMB_NUM_CHANNELS] = { .type = NLA_U32 },
+ [NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS] = { .type = NLA_U32 },
+ },
+ iface_limit_policy[NUM_NL80211_IFACE_LIMIT] = {
+ [NL80211_IFACE_LIMIT_TYPES] = { .type = NLA_NESTED },
+ [NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 },
+ };
+
+ err = nla_parse_nested(tb_comb, MAX_NL80211_IFACE_COMB,
+ nl_combi, iface_combination_policy);
+ if (err || !tb_comb[NL80211_IFACE_COMB_LIMITS] ||
+ !tb_comb[NL80211_IFACE_COMB_MAXNUM] ||
+ !tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS])
+ return 0; /* broken combination */
+
+ if (tb_comb[NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS])
+ info->capa->flags |= WPA_DRIVER_FLAGS_RADAR;
+
+ nla_for_each_nested(nl_limit, tb_comb[NL80211_IFACE_COMB_LIMITS],
+ rem_limit) {
+ err = nla_parse_nested(tb_limit, MAX_NL80211_IFACE_LIMIT,
+ nl_limit, iface_limit_policy);
+ if (err || !tb_limit[NL80211_IFACE_LIMIT_TYPES])
+ return 0; /* broken combination */
+
+ nla_for_each_nested(nl_mode,
+ tb_limit[NL80211_IFACE_LIMIT_TYPES],
+ rem_mode) {
+ int ift = nla_type(nl_mode);
+ if (ift == NL80211_IFTYPE_P2P_GO ||
+ ift == NL80211_IFTYPE_P2P_CLIENT)
+ combination_has_p2p = 1;
+ if (ift == NL80211_IFTYPE_STATION)
+ combination_has_mgd = 1;
+ }
+ if (combination_has_p2p && combination_has_mgd)
+ break;
+ }
+
+ if (combination_has_p2p && combination_has_mgd) {
+ unsigned int num_channels =
+ nla_get_u32(tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]);
+
+ info->p2p_concurrent = 1;
+ if (info->num_multichan_concurrent < num_channels)
+ info->num_multichan_concurrent = num_channels;
+ }
+
+ return 0;
+}
+
+
+static void wiphy_info_iface_comb(struct wiphy_info_data *info,
+ struct nlattr *tb)
+{
+ struct nlattr *nl_combi;
+ int rem_combi;
+
+ if (tb == NULL)
+ return;
+
+ nla_for_each_nested(nl_combi, tb, rem_combi) {
+ if (wiphy_info_iface_comb_process(info, nl_combi) > 0)
+ break;
+ }
+}
+
+
+static void wiphy_info_supp_cmds(struct wiphy_info_data *info,
+ struct nlattr *tb)
+{
+ struct nlattr *nl_cmd;
+ int i;
+
+ if (tb == NULL)
+ return;
+
+ nla_for_each_nested(nl_cmd, tb, i) {
+ switch (nla_get_u32(nl_cmd)) {
+ case NL80211_CMD_AUTHENTICATE:
+ info->auth_supported = 1;
+ break;
+ case NL80211_CMD_CONNECT:
+ info->connect_supported = 1;
+ break;
+ case NL80211_CMD_START_SCHED_SCAN:
+ info->capa->sched_scan_supported = 1;
+ break;
+ case NL80211_CMD_PROBE_CLIENT:
+ info->poll_command_supported = 1;
+ break;
+ case NL80211_CMD_CHANNEL_SWITCH:
+ info->channel_switch_supported = 1;
+ break;
+ case NL80211_CMD_SET_QOS_MAP:
+ info->set_qos_map_supported = 1;
+ break;
+ }
+ }
+}
+
+
+static void wiphy_info_cipher_suites(struct wiphy_info_data *info,
+ struct nlattr *tb)
+{
+ int i, num;
+ u32 *ciphers;
+
+ if (tb == NULL)
+ return;
+
+ num = nla_len(tb) / sizeof(u32);
+ ciphers = nla_data(tb);
+ for (i = 0; i < num; i++) {
+ u32 c = ciphers[i];
+
+ wpa_printf(MSG_DEBUG, "nl80211: Supported cipher %02x-%02x-%02x:%d",
+ c >> 24, (c >> 16) & 0xff,
+ (c >> 8) & 0xff, c & 0xff);
+ switch (c) {
+ case WLAN_CIPHER_SUITE_CCMP_256:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_CCMP_256;
+ break;
+ case WLAN_CIPHER_SUITE_GCMP_256:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_GCMP_256;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_CCMP;
+ break;
+ case WLAN_CIPHER_SUITE_GCMP:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_GCMP;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_TKIP;
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_WEP104;
+ break;
+ case WLAN_CIPHER_SUITE_WEP40:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_WEP40;
+ break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP;
+ break;
+ case WLAN_CIPHER_SUITE_BIP_GMAC_128:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_GMAC_128;
+ break;
+ case WLAN_CIPHER_SUITE_BIP_GMAC_256:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_GMAC_256;
+ break;
+ case WLAN_CIPHER_SUITE_BIP_CMAC_256:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_CMAC_256;
+ break;
+ case WLAN_CIPHER_SUITE_NO_GROUP_ADDR:
+ info->capa->enc |= WPA_DRIVER_CAPA_ENC_GTK_NOT_USED;
+ break;
+ }
+ }
+}
+
+
+static void wiphy_info_max_roc(struct wpa_driver_capa *capa,
+ struct nlattr *tb)
+{
+ if (tb)
+ capa->max_remain_on_chan = nla_get_u32(tb);
+}
+
+
+static void wiphy_info_tdls(struct wpa_driver_capa *capa, struct nlattr *tdls,
+ struct nlattr *ext_setup)
+{
+ if (tdls == NULL)
+ return;
+
+ wpa_printf(MSG_DEBUG, "nl80211: TDLS supported");
+ capa->flags |= WPA_DRIVER_FLAGS_TDLS_SUPPORT;
+
+ if (ext_setup) {
+ wpa_printf(MSG_DEBUG, "nl80211: TDLS external setup");
+ capa->flags |= WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP;
+ }
+}
+
+
+static void wiphy_info_feature_flags(struct wiphy_info_data *info,
+ struct nlattr *tb)
+{
+ u32 flags;
+ struct wpa_driver_capa *capa = info->capa;
+
+ if (tb == NULL)
+ return;
+
+ flags = nla_get_u32(tb);
+
+ if (flags & NL80211_FEATURE_SK_TX_STATUS)
+ info->data_tx_status = 1;
+
+ if (flags & NL80211_FEATURE_INACTIVITY_TIMER)
+ capa->flags |= WPA_DRIVER_FLAGS_INACTIVITY_TIMER;
+
+ if (flags & NL80211_FEATURE_SAE)
+ capa->flags |= WPA_DRIVER_FLAGS_SAE;
+
+ if (flags & NL80211_FEATURE_NEED_OBSS_SCAN)
+ capa->flags |= WPA_DRIVER_FLAGS_OBSS_SCAN;
+
+ if (flags & NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE)
+ capa->flags |= WPA_DRIVER_FLAGS_HT_2040_COEX;
+
+ if (flags & NL80211_FEATURE_TDLS_CHANNEL_SWITCH) {
+ wpa_printf(MSG_DEBUG, "nl80211: TDLS channel switch");
+ capa->flags |= WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH;
+ }
+
+ if (flags & NL80211_FEATURE_LOW_PRIORITY_SCAN)
+ info->have_low_prio_scan = 1;
+
+ if (flags & NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR)
+ info->mac_addr_rand_scan_supported = 1;
+
+ if (flags & NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR)
+ info->mac_addr_rand_sched_scan_supported = 1;
+
+ if (flags & NL80211_FEATURE_STATIC_SMPS)
+ capa->smps_modes |= WPA_DRIVER_SMPS_MODE_STATIC;
+
+ if (flags & NL80211_FEATURE_DYNAMIC_SMPS)
+ capa->smps_modes |= WPA_DRIVER_SMPS_MODE_DYNAMIC;
+
+ if (flags & NL80211_FEATURE_SUPPORTS_WMM_ADMISSION)
+ info->wmm_ac_supported = 1;
+
+ if (flags & NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES)
+ capa->rrm_flags |= WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES;
+
+ if (flags & NL80211_FEATURE_WFA_TPC_IE_IN_PROBES)
+ capa->rrm_flags |= WPA_DRIVER_FLAGS_WFA_TPC_IE_IN_PROBES;
+
+ if (flags & NL80211_FEATURE_QUIET)
+ capa->rrm_flags |= WPA_DRIVER_FLAGS_QUIET;
+
+ if (flags & NL80211_FEATURE_TX_POWER_INSERTION)
+ capa->rrm_flags |= WPA_DRIVER_FLAGS_TX_POWER_INSERTION;
+
+ if (flags & NL80211_FEATURE_HT_IBSS)
+ capa->flags |= WPA_DRIVER_FLAGS_HT_IBSS;
+}
+
+
+static void wiphy_info_probe_resp_offload(struct wpa_driver_capa *capa,
+ struct nlattr *tb)
+{
+ u32 protocols;
+
+ if (tb == NULL)
+ return;
+
+ protocols = nla_get_u32(tb);
+ wpa_printf(MSG_DEBUG, "nl80211: Supports Probe Response offload in AP "
+ "mode");
+ capa->flags |= WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD;
+ capa->probe_resp_offloads = probe_resp_offload_support(protocols);
+}
+
+
+static void wiphy_info_wowlan_triggers(struct wpa_driver_capa *capa,
+ struct nlattr *tb)
+{
+ struct nlattr *triggers[MAX_NL80211_WOWLAN_TRIG + 1];
+
+ if (tb == NULL)
+ return;
+
+ if (nla_parse_nested(triggers, MAX_NL80211_WOWLAN_TRIG,
+ tb, NULL))
+ return;
+
+ if (triggers[NL80211_WOWLAN_TRIG_ANY])
+ capa->wowlan_triggers.any = 1;
+ if (triggers[NL80211_WOWLAN_TRIG_DISCONNECT])
+ capa->wowlan_triggers.disconnect = 1;
+ if (triggers[NL80211_WOWLAN_TRIG_MAGIC_PKT])
+ capa->wowlan_triggers.magic_pkt = 1;
+ if (triggers[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE])
+ capa->wowlan_triggers.gtk_rekey_failure = 1;
+ if (triggers[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST])
+ capa->wowlan_triggers.eap_identity_req = 1;
+ if (triggers[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE])
+ capa->wowlan_triggers.four_way_handshake = 1;
+ if (triggers[NL80211_WOWLAN_TRIG_RFKILL_RELEASE])
+ capa->wowlan_triggers.rfkill_release = 1;
+}
+
+
+static int wiphy_info_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct wiphy_info_data *info = arg;
+ struct wpa_driver_capa *capa = info->capa;
+ struct wpa_driver_nl80211_data *drv = info->drv;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (tb[NL80211_ATTR_WIPHY_NAME])
+ os_strlcpy(drv->phyname,
+ nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]),
+ sizeof(drv->phyname));
+ if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS])
+ capa->max_scan_ssids =
+ nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]);
+
+ if (tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS])
+ capa->max_sched_scan_ssids =
+ nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]);
+
+ if (tb[NL80211_ATTR_MAX_MATCH_SETS])
+ capa->max_match_sets =
+ nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]);
+
+ if (tb[NL80211_ATTR_MAC_ACL_MAX])
+ capa->max_acl_mac_addrs =
+ nla_get_u8(tb[NL80211_ATTR_MAC_ACL_MAX]);
+
+ wiphy_info_supported_iftypes(info, tb[NL80211_ATTR_SUPPORTED_IFTYPES]);
+ wiphy_info_iface_comb(info, tb[NL80211_ATTR_INTERFACE_COMBINATIONS]);
+ wiphy_info_supp_cmds(info, tb[NL80211_ATTR_SUPPORTED_COMMANDS]);
+ wiphy_info_cipher_suites(info, tb[NL80211_ATTR_CIPHER_SUITES]);
+
+ if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) {
+ wpa_printf(MSG_DEBUG, "nl80211: Using driver-based "
+ "off-channel TX");
+ capa->flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_TX;
+ }
+
+ if (tb[NL80211_ATTR_ROAM_SUPPORT]) {
+ wpa_printf(MSG_DEBUG, "nl80211: Using driver-based roaming");
+ capa->flags |= WPA_DRIVER_FLAGS_BSS_SELECTION;
+ }
+
+ wiphy_info_max_roc(capa,
+ tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]);
+
+ if (tb[NL80211_ATTR_SUPPORT_AP_UAPSD])
+ capa->flags |= WPA_DRIVER_FLAGS_AP_UAPSD;
+
+ wiphy_info_tdls(capa, tb[NL80211_ATTR_TDLS_SUPPORT],
+ tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]);
+
+ if (tb[NL80211_ATTR_DEVICE_AP_SME])
+ info->device_ap_sme = 1;
+
+ wiphy_info_feature_flags(info, tb[NL80211_ATTR_FEATURE_FLAGS]);
+ wiphy_info_probe_resp_offload(capa,
+ tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
+
+ if (tb[NL80211_ATTR_EXT_CAPA] && tb[NL80211_ATTR_EXT_CAPA_MASK] &&
+ drv->extended_capa == NULL) {
+ drv->extended_capa =
+ os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+ if (drv->extended_capa) {
+ os_memcpy(drv->extended_capa,
+ nla_data(tb[NL80211_ATTR_EXT_CAPA]),
+ nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+ drv->extended_capa_len =
+ nla_len(tb[NL80211_ATTR_EXT_CAPA]);
+ }
+ drv->extended_capa_mask =
+ os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA_MASK]));
+ if (drv->extended_capa_mask) {
+ os_memcpy(drv->extended_capa_mask,
+ nla_data(tb[NL80211_ATTR_EXT_CAPA_MASK]),
+ nla_len(tb[NL80211_ATTR_EXT_CAPA_MASK]));
+ } else {
+ os_free(drv->extended_capa);
+ drv->extended_capa = NULL;
+ drv->extended_capa_len = 0;
+ }
+ }
+
+ if (tb[NL80211_ATTR_VENDOR_DATA]) {
+ struct nlattr *nl;
+ int rem;
+
+ nla_for_each_nested(nl, tb[NL80211_ATTR_VENDOR_DATA], rem) {
+ struct nl80211_vendor_cmd_info *vinfo;
+ if (nla_len(nl) != sizeof(*vinfo)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Unexpected vendor data info");
+ continue;
+ }
+ vinfo = nla_data(nl);
+ switch (vinfo->subcmd) {
+ case QCA_NL80211_VENDOR_SUBCMD_ROAMING:
+ drv->roaming_vendor_cmd_avail = 1;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY:
+ drv->dfs_vendor_cmd_avail = 1;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES:
+ drv->get_features_vendor_cmd_avail = 1;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_DO_ACS:
+ drv->capa.flags |= WPA_DRIVER_FLAGS_ACS_OFFLOAD;
+ break;
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u",
+ vinfo->vendor_id, vinfo->subcmd);
+ }
+ }
+
+ if (tb[NL80211_ATTR_VENDOR_EVENTS]) {
+ struct nlattr *nl;
+ int rem;
+
+ nla_for_each_nested(nl, tb[NL80211_ATTR_VENDOR_EVENTS], rem) {
+ struct nl80211_vendor_cmd_info *vinfo;
+ if (nla_len(nl) != sizeof(*vinfo)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Unexpected vendor data info");
+ continue;
+ }
+ vinfo = nla_data(nl);
+ wpa_printf(MSG_DEBUG, "nl80211: Supported vendor event: vendor_id=0x%x subcmd=%u",
+ vinfo->vendor_id, vinfo->subcmd);
+ }
+ }
+
+ wiphy_info_wowlan_triggers(capa,
+ tb[NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED]);
+
+ if (tb[NL80211_ATTR_MAX_AP_ASSOC_STA])
+ capa->max_stations =
+ nla_get_u32(tb[NL80211_ATTR_MAX_AP_ASSOC_STA]);
+
+ return NL_SKIP;
+}
+
+
+static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
+ struct wiphy_info_data *info)
+{
+ u32 feat;
+ struct nl_msg *msg;
+ int flags = 0;
+
+ os_memset(info, 0, sizeof(*info));
+ info->capa = &drv->capa;
+ info->drv = drv;
+
+ feat = get_nl80211_protocol_features(drv);
+ if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
+ flags = NLM_F_DUMP;
+ msg = nl80211_cmd_msg(drv->first_bss, flags, NL80211_CMD_GET_WIPHY);
+ if (!msg || nla_put_flag(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP)) {
+ nlmsg_free(msg);
+ return -1;
+ }
+
+ if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info))
+ return -1;
+
+ if (info->auth_supported)
+ drv->capa.flags |= WPA_DRIVER_FLAGS_SME;
+ else if (!info->connect_supported) {
+ wpa_printf(MSG_INFO, "nl80211: Driver does not support "
+ "authentication/association or connect commands");
+ info->error = 1;
+ }
+
+ if (info->p2p_go_supported && info->p2p_client_supported)
+ drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE;
+ if (info->p2p_concurrent) {
+ wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
+ "interface (driver advertised support)");
+ drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
+ drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
+ }
+ if (info->num_multichan_concurrent > 1) {
+ wpa_printf(MSG_DEBUG, "nl80211: Enable multi-channel "
+ "concurrent (driver advertised support)");
+ drv->capa.num_multichan_concurrent =
+ info->num_multichan_concurrent;
+ }
+ if (drv->capa.flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)
+ wpa_printf(MSG_DEBUG, "nl80211: use P2P_DEVICE support");
+
+ /* default to 5000 since early versions of mac80211 don't set it */
+ if (!drv->capa.max_remain_on_chan)
+ drv->capa.max_remain_on_chan = 5000;
+
+ if (info->channel_switch_supported)
+ drv->capa.flags |= WPA_DRIVER_FLAGS_AP_CSA;
+ drv->capa.wmm_ac_supported = info->wmm_ac_supported;
+
+ drv->capa.mac_addr_rand_sched_scan_supported =
+ info->mac_addr_rand_sched_scan_supported;
+ drv->capa.mac_addr_rand_scan_supported =
+ info->mac_addr_rand_scan_supported;
+
+ return 0;
+}
+
+
+static int dfs_info_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ int *dfs_capability_ptr = arg;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (tb[NL80211_ATTR_VENDOR_DATA]) {
+ struct nlattr *nl_vend = tb[NL80211_ATTR_VENDOR_DATA];
+ struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1];
+
+ nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_MAX,
+ nla_data(nl_vend), nla_len(nl_vend), NULL);
+
+ if (tb_vendor[QCA_WLAN_VENDOR_ATTR_DFS]) {
+ u32 val;
+ val = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_DFS]);
+ wpa_printf(MSG_DEBUG, "nl80211: DFS offload capability: %u",
+ val);
+ *dfs_capability_ptr = val;
+ }
+ }
+
+ return NL_SKIP;
+}
+
+
+static void qca_nl80211_check_dfs_capa(struct wpa_driver_nl80211_data *drv)
+{
+ struct nl_msg *msg;
+ int dfs_capability = 0;
+ int ret;
+
+ if (!drv->dfs_vendor_cmd_avail)
+ return;
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY)) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, dfs_info_handler, &dfs_capability);
+ if (!ret && dfs_capability)
+ drv->capa.flags |= WPA_DRIVER_FLAGS_DFS_OFFLOAD;
+}
+
+
+struct features_info {
+ u8 *flags;
+ size_t flags_len;
+};
+
+
+static int features_info_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct features_info *info = arg;
+ struct nlattr *nl_vend, *attr;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ nl_vend = tb[NL80211_ATTR_VENDOR_DATA];
+ if (nl_vend) {
+ struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1];
+
+ nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_MAX,
+ nla_data(nl_vend), nla_len(nl_vend), NULL);
+
+ attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS];
+ if (attr) {
+ info->flags = nla_data(attr);
+ info->flags_len = nla_len(attr);
+ }
+ }
+
+ return NL_SKIP;
+}
+
+
+static int check_feature(enum qca_wlan_vendor_features feature,
+ struct features_info *info)
+{
+ size_t idx = feature / 8;
+
+ return (idx < info->flags_len) &&
+ (info->flags[idx] & BIT(feature % 8));
+}
+
+
+static void qca_nl80211_get_features(struct wpa_driver_nl80211_data *drv)
+{
+ struct nl_msg *msg;
+ struct features_info info;
+ int ret;
+
+ if (!drv->get_features_vendor_cmd_avail)
+ return;
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES)) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ os_memset(&info, 0, sizeof(info));
+ ret = send_and_recv_msgs(drv, msg, features_info_handler, &info);
+ if (ret || !info.flags)
+ return;
+
+ if (check_feature(QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD, &info))
+ drv->capa.flags |= WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD;
+}
+
+
+int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
+{
+ struct wiphy_info_data info;
+ if (wpa_driver_nl80211_get_info(drv, &info))
+ return -1;
+
+ if (info.error)
+ return -1;
+
+ drv->has_capability = 1;
+ drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK |
+ WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B |
+ WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192;
+ drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
+ WPA_DRIVER_AUTH_SHARED |
+ WPA_DRIVER_AUTH_LEAP;
+
+ drv->capa.flags |= WPA_DRIVER_FLAGS_SANE_ERROR_CODES;
+ drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE;
+ drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
+
+ /*
+ * As all cfg80211 drivers must support cases where the AP interface is
+ * removed without the knowledge of wpa_supplicant/hostapd, e.g., in
+ * case that the user space daemon has crashed, they must be able to
+ * cleanup all stations and key entries in the AP tear down flow. Thus,
+ * this flag can/should always be set for cfg80211 drivers.
+ */
+ drv->capa.flags |= WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT;
+
+ if (!info.device_ap_sme) {
+ drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS;
+
+ /*
+ * No AP SME is currently assumed to also indicate no AP MLME
+ * in the driver/firmware.
+ */
+ drv->capa.flags |= WPA_DRIVER_FLAGS_AP_MLME;
+ }
+
+ drv->device_ap_sme = info.device_ap_sme;
+ drv->poll_command_supported = info.poll_command_supported;
+ drv->data_tx_status = info.data_tx_status;
+ if (info.set_qos_map_supported)
+ drv->capa.flags |= WPA_DRIVER_FLAGS_QOS_MAPPING;
+ drv->have_low_prio_scan = info.have_low_prio_scan;
+
+ /*
+ * If poll command and tx status are supported, mac80211 is new enough
+ * to have everything we need to not need monitor interfaces.
+ */
+ drv->use_monitor = !info.poll_command_supported || !info.data_tx_status;
+
+ if (drv->device_ap_sme && drv->use_monitor) {
+ /*
+ * Non-mac80211 drivers may not support monitor interface.
+ * Make sure we do not get stuck with incorrect capability here
+ * by explicitly testing this.
+ */
+ if (!info.monitor_supported) {
+ wpa_printf(MSG_DEBUG, "nl80211: Disable use_monitor "
+ "with device_ap_sme since no monitor mode "
+ "support detected");
+ drv->use_monitor = 0;
+ }
+ }
+
+ /*
+ * If we aren't going to use monitor interfaces, but the
+ * driver doesn't support data TX status, we won't get TX
+ * status for EAPOL frames.
+ */
+ if (!drv->use_monitor && !info.data_tx_status)
+ drv->capa.flags &= ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
+
+ qca_nl80211_check_dfs_capa(drv);
+ qca_nl80211_get_features(drv);
+
+ return 0;
+}
+
+
+struct phy_info_arg {
+ u16 *num_modes;
+ struct hostapd_hw_modes *modes;
+ int last_mode, last_chan_idx;
+};
+
+static void phy_info_ht_capa(struct hostapd_hw_modes *mode, struct nlattr *capa,
+ struct nlattr *ampdu_factor,
+ struct nlattr *ampdu_density,
+ struct nlattr *mcs_set)
+{
+ if (capa)
+ mode->ht_capab = nla_get_u16(capa);
+
+ if (ampdu_factor)
+ mode->a_mpdu_params |= nla_get_u8(ampdu_factor) & 0x03;
+
+ if (ampdu_density)
+ mode->a_mpdu_params |= nla_get_u8(ampdu_density) << 2;
+
+ if (mcs_set && nla_len(mcs_set) >= 16) {
+ u8 *mcs;
+ mcs = nla_data(mcs_set);
+ os_memcpy(mode->mcs_set, mcs, 16);
+ }
+}
+
+
+static void phy_info_vht_capa(struct hostapd_hw_modes *mode,
+ struct nlattr *capa,
+ struct nlattr *mcs_set)
+{
+ if (capa)
+ mode->vht_capab = nla_get_u32(capa);
+
+ if (mcs_set && nla_len(mcs_set) >= 8) {
+ u8 *mcs;
+ mcs = nla_data(mcs_set);
+ os_memcpy(mode->vht_mcs_set, mcs, 8);
+ }
+}
+
+
+static void phy_info_freq(struct hostapd_hw_modes *mode,
+ struct hostapd_channel_data *chan,
+ struct nlattr *tb_freq[])
+{
+ u8 channel;
+ chan->freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
+ chan->flag = 0;
+ chan->dfs_cac_ms = 0;
+ if (ieee80211_freq_to_chan(chan->freq, &channel) != NUM_HOSTAPD_MODES)
+ chan->chan = channel;
+
+ if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
+ chan->flag |= HOSTAPD_CHAN_DISABLED;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IR])
+ chan->flag |= HOSTAPD_CHAN_NO_IR;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR])
+ chan->flag |= HOSTAPD_CHAN_RADAR;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_INDOOR_ONLY])
+ chan->flag |= HOSTAPD_CHAN_INDOOR_ONLY;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_GO_CONCURRENT])
+ chan->flag |= HOSTAPD_CHAN_GO_CONCURRENT;
+
+ if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]) {
+ enum nl80211_dfs_state state =
+ nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]);
+
+ switch (state) {
+ case NL80211_DFS_USABLE:
+ chan->flag |= HOSTAPD_CHAN_DFS_USABLE;
+ break;
+ case NL80211_DFS_AVAILABLE:
+ chan->flag |= HOSTAPD_CHAN_DFS_AVAILABLE;
+ break;
+ case NL80211_DFS_UNAVAILABLE:
+ chan->flag |= HOSTAPD_CHAN_DFS_UNAVAILABLE;
+ break;
+ }
+ }
+
+ if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME]) {
+ chan->dfs_cac_ms = nla_get_u32(
+ tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME]);
+ }
+}
+
+
+static int phy_info_freqs(struct phy_info_arg *phy_info,
+ struct hostapd_hw_modes *mode, struct nlattr *tb)
+{
+ static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
+ [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
+ [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_NO_IR] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
+ [NL80211_FREQUENCY_ATTR_DFS_STATE] = { .type = NLA_U32 },
+ };
+ int new_channels = 0;
+ struct hostapd_channel_data *channel;
+ struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
+ struct nlattr *nl_freq;
+ int rem_freq, idx;
+
+ if (tb == NULL)
+ return NL_OK;
+
+ nla_for_each_nested(nl_freq, tb, rem_freq) {
+ nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX,
+ nla_data(nl_freq), nla_len(nl_freq), freq_policy);
+ if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
+ continue;
+ new_channels++;
+ }
+
+ channel = os_realloc_array(mode->channels,
+ mode->num_channels + new_channels,
+ sizeof(struct hostapd_channel_data));
+ if (!channel)
+ return NL_SKIP;
+
+ mode->channels = channel;
+ mode->num_channels += new_channels;
+
+ idx = phy_info->last_chan_idx;
+
+ nla_for_each_nested(nl_freq, tb, rem_freq) {
+ nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX,
+ nla_data(nl_freq), nla_len(nl_freq), freq_policy);
+ if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
+ continue;
+ phy_info_freq(mode, &mode->channels[idx], tb_freq);
+ idx++;
+ }
+ phy_info->last_chan_idx = idx;
+
+ return NL_OK;
+}
+
+
+static int phy_info_rates(struct hostapd_hw_modes *mode, struct nlattr *tb)
+{
+ static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = {
+ [NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 },
+ [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] =
+ { .type = NLA_FLAG },
+ };
+ struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1];
+ struct nlattr *nl_rate;
+ int rem_rate, idx;
+
+ if (tb == NULL)
+ return NL_OK;
+
+ nla_for_each_nested(nl_rate, tb, rem_rate) {
+ nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX,
+ nla_data(nl_rate), nla_len(nl_rate),
+ rate_policy);
+ if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
+ continue;
+ mode->num_rates++;
+ }
+
+ mode->rates = os_calloc(mode->num_rates, sizeof(int));
+ if (!mode->rates)
+ return NL_SKIP;
+
+ idx = 0;
+
+ nla_for_each_nested(nl_rate, tb, rem_rate) {
+ nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX,
+ nla_data(nl_rate), nla_len(nl_rate),
+ rate_policy);
+ if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
+ continue;
+ mode->rates[idx] = nla_get_u32(
+ tb_rate[NL80211_BITRATE_ATTR_RATE]);
+ idx++;
+ }
+
+ return NL_OK;
+}
+
+
+static int phy_info_band(struct phy_info_arg *phy_info, struct nlattr *nl_band)
+{
+ struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
+ struct hostapd_hw_modes *mode;
+ int ret;
+
+ if (phy_info->last_mode != nl_band->nla_type) {
+ mode = os_realloc_array(phy_info->modes,
+ *phy_info->num_modes + 1,
+ sizeof(*mode));
+ if (!mode)
+ return NL_SKIP;
+ phy_info->modes = mode;
+
+ mode = &phy_info->modes[*(phy_info->num_modes)];
+ os_memset(mode, 0, sizeof(*mode));
+ mode->mode = NUM_HOSTAPD_MODES;
+ mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN |
+ HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN;
+
+ /*
+ * Unsupported VHT MCS stream is defined as value 3, so the VHT
+ * MCS RX/TX map must be initialized with 0xffff to mark all 8
+ * possible streams as unsupported. This will be overridden if
+ * driver advertises VHT support.
+ */
+ mode->vht_mcs_set[0] = 0xff;
+ mode->vht_mcs_set[1] = 0xff;
+ mode->vht_mcs_set[4] = 0xff;
+ mode->vht_mcs_set[5] = 0xff;
+
+ *(phy_info->num_modes) += 1;
+ phy_info->last_mode = nl_band->nla_type;
+ phy_info->last_chan_idx = 0;
+ } else
+ mode = &phy_info->modes[*(phy_info->num_modes) - 1];
+
+ nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
+ nla_len(nl_band), NULL);
+
+ phy_info_ht_capa(mode, tb_band[NL80211_BAND_ATTR_HT_CAPA],
+ tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR],
+ tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY],
+ tb_band[NL80211_BAND_ATTR_HT_MCS_SET]);
+ phy_info_vht_capa(mode, tb_band[NL80211_BAND_ATTR_VHT_CAPA],
+ tb_band[NL80211_BAND_ATTR_VHT_MCS_SET]);
+ ret = phy_info_freqs(phy_info, mode, tb_band[NL80211_BAND_ATTR_FREQS]);
+ if (ret != NL_OK)
+ return ret;
+ ret = phy_info_rates(mode, tb_band[NL80211_BAND_ATTR_RATES]);
+ if (ret != NL_OK)
+ return ret;
+
+ return NL_OK;
+}
+
+
+static int phy_info_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct phy_info_arg *phy_info = arg;
+ struct nlattr *nl_band;
+ int rem_band;
+
+ nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb_msg[NL80211_ATTR_WIPHY_BANDS])
+ return NL_SKIP;
+
+ nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band)
+ {
+ int res = phy_info_band(phy_info, nl_band);
+ if (res != NL_OK)
+ return res;
+ }
+
+ return NL_SKIP;
+}
+
+
+static struct hostapd_hw_modes *
+wpa_driver_nl80211_postprocess_modes(struct hostapd_hw_modes *modes,
+ u16 *num_modes)
+{
+ u16 m;
+ struct hostapd_hw_modes *mode11g = NULL, *nmodes, *mode;
+ int i, mode11g_idx = -1;
+
+ /* heuristic to set up modes */
+ for (m = 0; m < *num_modes; m++) {
+ if (!modes[m].num_channels)
+ continue;
+ if (modes[m].channels[0].freq < 4000) {
+ modes[m].mode = HOSTAPD_MODE_IEEE80211B;
+ for (i = 0; i < modes[m].num_rates; i++) {
+ if (modes[m].rates[i] > 200) {
+ modes[m].mode = HOSTAPD_MODE_IEEE80211G;
+ break;
+ }
+ }
+ } else if (modes[m].channels[0].freq > 50000)
+ modes[m].mode = HOSTAPD_MODE_IEEE80211AD;
+ else
+ modes[m].mode = HOSTAPD_MODE_IEEE80211A;
+ }
+
+ /* If only 802.11g mode is included, use it to construct matching
+ * 802.11b mode data. */
+
+ for (m = 0; m < *num_modes; m++) {
+ if (modes[m].mode == HOSTAPD_MODE_IEEE80211B)
+ return modes; /* 802.11b already included */
+ if (modes[m].mode == HOSTAPD_MODE_IEEE80211G)
+ mode11g_idx = m;
+ }
+
+ if (mode11g_idx < 0)
+ return modes; /* 2.4 GHz band not supported at all */
+
+ nmodes = os_realloc_array(modes, *num_modes + 1, sizeof(*nmodes));
+ if (nmodes == NULL)
+ return modes; /* Could not add 802.11b mode */
+
+ mode = &nmodes[*num_modes];
+ os_memset(mode, 0, sizeof(*mode));
+ (*num_modes)++;
+ modes = nmodes;
+
+ mode->mode = HOSTAPD_MODE_IEEE80211B;
+
+ mode11g = &modes[mode11g_idx];
+ mode->num_channels = mode11g->num_channels;
+ mode->channels = os_malloc(mode11g->num_channels *
+ sizeof(struct hostapd_channel_data));
+ if (mode->channels == NULL) {
+ (*num_modes)--;
+ return modes; /* Could not add 802.11b mode */
+ }
+ os_memcpy(mode->channels, mode11g->channels,
+ mode11g->num_channels * sizeof(struct hostapd_channel_data));
+
+ mode->num_rates = 0;
+ mode->rates = os_malloc(4 * sizeof(int));
+ if (mode->rates == NULL) {
+ os_free(mode->channels);
+ (*num_modes)--;
+ return modes; /* Could not add 802.11b mode */
+ }
+
+ for (i = 0; i < mode11g->num_rates; i++) {
+ if (mode11g->rates[i] != 10 && mode11g->rates[i] != 20 &&
+ mode11g->rates[i] != 55 && mode11g->rates[i] != 110)
+ continue;
+ mode->rates[mode->num_rates] = mode11g->rates[i];
+ mode->num_rates++;
+ if (mode->num_rates == 4)
+ break;
+ }
+
+ if (mode->num_rates == 0) {
+ os_free(mode->channels);
+ os_free(mode->rates);
+ (*num_modes)--;
+ return modes; /* No 802.11b rates */
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Added 802.11b mode based on 802.11g "
+ "information");
+
+ return modes;
+}
+
+
+static void nl80211_set_ht40_mode(struct hostapd_hw_modes *mode, int start,
+ int end)
+{
+ int c;
+
+ for (c = 0; c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+ if (chan->freq - 10 >= start && chan->freq + 10 <= end)
+ chan->flag |= HOSTAPD_CHAN_HT40;
+ }
+}
+
+
+static void nl80211_set_ht40_mode_sec(struct hostapd_hw_modes *mode, int start,
+ int end)
+{
+ int c;
+
+ for (c = 0; c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+ if (!(chan->flag & HOSTAPD_CHAN_HT40))
+ continue;
+ if (chan->freq - 30 >= start && chan->freq - 10 <= end)
+ chan->flag |= HOSTAPD_CHAN_HT40MINUS;
+ if (chan->freq + 10 >= start && chan->freq + 30 <= end)
+ chan->flag |= HOSTAPD_CHAN_HT40PLUS;
+ }
+}
+
+
+static void nl80211_reg_rule_max_eirp(u32 start, u32 end, u32 max_eirp,
+ struct phy_info_arg *results)
+{
+ u16 m;
+
+ for (m = 0; m < *results->num_modes; m++) {
+ int c;
+ struct hostapd_hw_modes *mode = &results->modes[m];
+
+ for (c = 0; c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+ if ((u32) chan->freq - 10 >= start &&
+ (u32) chan->freq + 10 <= end)
+ chan->max_tx_power = max_eirp;
+ }
+ }
+}
+
+
+static void nl80211_reg_rule_ht40(u32 start, u32 end,
+ struct phy_info_arg *results)
+{
+ u16 m;
+
+ for (m = 0; m < *results->num_modes; m++) {
+ if (!(results->modes[m].ht_capab &
+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+ continue;
+ nl80211_set_ht40_mode(&results->modes[m], start, end);
+ }
+}
+
+
+static void nl80211_reg_rule_sec(struct nlattr *tb[],
+ struct phy_info_arg *results)
+{
+ u32 start, end, max_bw;
+ u16 m;
+
+ if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
+ tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
+ tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
+ return;
+
+ start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
+ end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
+ max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
+
+ if (max_bw < 20)
+ return;
+
+ for (m = 0; m < *results->num_modes; m++) {
+ if (!(results->modes[m].ht_capab &
+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+ continue;
+ nl80211_set_ht40_mode_sec(&results->modes[m], start, end);
+ }
+}
+
+
+static void nl80211_set_vht_mode(struct hostapd_hw_modes *mode, int start,
+ int end)
+{
+ int c;
+
+ for (c = 0; c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+ if (chan->freq - 10 >= start && chan->freq + 70 <= end)
+ chan->flag |= HOSTAPD_CHAN_VHT_10_70;
+
+ if (chan->freq - 30 >= start && chan->freq + 50 <= end)
+ chan->flag |= HOSTAPD_CHAN_VHT_30_50;
+
+ if (chan->freq - 50 >= start && chan->freq + 30 <= end)
+ chan->flag |= HOSTAPD_CHAN_VHT_50_30;
+
+ if (chan->freq - 70 >= start && chan->freq + 10 <= end)
+ chan->flag |= HOSTAPD_CHAN_VHT_70_10;
+ }
+}
+
+
+static void nl80211_reg_rule_vht(struct nlattr *tb[],
+ struct phy_info_arg *results)
+{
+ u32 start, end, max_bw;
+ u16 m;
+
+ if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
+ tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
+ tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
+ return;
+
+ start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
+ end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
+ max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
+
+ if (max_bw < 80)
+ return;
+
+ for (m = 0; m < *results->num_modes; m++) {
+ if (!(results->modes[m].ht_capab &
+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+ continue;
+ /* TODO: use a real VHT support indication */
+ if (!results->modes[m].vht_capab)
+ continue;
+
+ nl80211_set_vht_mode(&results->modes[m], start, end);
+ }
+}
+
+
+static const char * dfs_domain_name(enum nl80211_dfs_regions region)
+{
+ switch (region) {
+ case NL80211_DFS_UNSET:
+ return "DFS-UNSET";
+ case NL80211_DFS_FCC:
+ return "DFS-FCC";
+ case NL80211_DFS_ETSI:
+ return "DFS-ETSI";
+ case NL80211_DFS_JP:
+ return "DFS-JP";
+ default:
+ return "DFS-invalid";
+ }
+}
+
+
+static int nl80211_get_reg(struct nl_msg *msg, void *arg)
+{
+ struct phy_info_arg *results = arg;
+ struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *nl_rule;
+ struct nlattr *tb_rule[NL80211_FREQUENCY_ATTR_MAX + 1];
+ int rem_rule;
+ static struct nla_policy reg_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
+ [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 },
+ [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 },
+ [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 },
+ [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 },
+ [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 },
+ [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
+ };
+
+ nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+ if (!tb_msg[NL80211_ATTR_REG_ALPHA2] ||
+ !tb_msg[NL80211_ATTR_REG_RULES]) {
+ wpa_printf(MSG_DEBUG, "nl80211: No regulatory information "
+ "available");
+ return NL_SKIP;
+ }
+
+ if (tb_msg[NL80211_ATTR_DFS_REGION]) {
+ enum nl80211_dfs_regions dfs_domain;
+ dfs_domain = nla_get_u8(tb_msg[NL80211_ATTR_DFS_REGION]);
+ wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s (%s)",
+ (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]),
+ dfs_domain_name(dfs_domain));
+ } else {
+ wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s",
+ (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]));
+ }
+
+ nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
+ {
+ u32 start, end, max_eirp = 0, max_bw = 0, flags = 0;
+ nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
+ nla_data(nl_rule), nla_len(nl_rule), reg_policy);
+ if (tb_rule[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
+ tb_rule[NL80211_ATTR_FREQ_RANGE_END] == NULL)
+ continue;
+ start = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
+ end = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
+ if (tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP])
+ max_eirp = nla_get_u32(tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP]) / 100;
+ if (tb_rule[NL80211_ATTR_FREQ_RANGE_MAX_BW])
+ max_bw = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
+ if (tb_rule[NL80211_ATTR_REG_RULE_FLAGS])
+ flags = nla_get_u32(tb_rule[NL80211_ATTR_REG_RULE_FLAGS]);
+
+ wpa_printf(MSG_DEBUG, "nl80211: %u-%u @ %u MHz %u mBm%s%s%s%s%s%s%s%s",
+ start, end, max_bw, max_eirp,
+ flags & NL80211_RRF_NO_OFDM ? " (no OFDM)" : "",
+ flags & NL80211_RRF_NO_CCK ? " (no CCK)" : "",
+ flags & NL80211_RRF_NO_INDOOR ? " (no indoor)" : "",
+ flags & NL80211_RRF_NO_OUTDOOR ? " (no outdoor)" :
+ "",
+ flags & NL80211_RRF_DFS ? " (DFS)" : "",
+ flags & NL80211_RRF_PTP_ONLY ? " (PTP only)" : "",
+ flags & NL80211_RRF_PTMP_ONLY ? " (PTMP only)" : "",
+ flags & NL80211_RRF_NO_IR ? " (no IR)" : "");
+ if (max_bw >= 40)
+ nl80211_reg_rule_ht40(start, end, results);
+ if (tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP])
+ nl80211_reg_rule_max_eirp(start, end, max_eirp,
+ results);
+ }
+
+ nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
+ {
+ nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
+ nla_data(nl_rule), nla_len(nl_rule), reg_policy);
+ nl80211_reg_rule_sec(tb_rule, results);
+ }
+
+ nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
+ {
+ nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
+ nla_data(nl_rule), nla_len(nl_rule), reg_policy);
+ nl80211_reg_rule_vht(tb_rule, results);
+ }
+
+ return NL_SKIP;
+}
+
+
+static int nl80211_set_regulatory_flags(struct wpa_driver_nl80211_data *drv,
+ struct phy_info_arg *results)
+{
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
+ return send_and_recv_msgs(drv, msg, nl80211_get_reg, results);
+}
+
+
+struct hostapd_hw_modes *
+nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
+{
+ u32 feat;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int nl_flags = 0;
+ struct nl_msg *msg;
+ struct phy_info_arg result = {
+ .num_modes = num_modes,
+ .modes = NULL,
+ .last_mode = -1,
+ };
+
+ *num_modes = 0;
+ *flags = 0;
+
+ feat = get_nl80211_protocol_features(drv);
+ if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
+ nl_flags = NLM_F_DUMP;
+ if (!(msg = nl80211_cmd_msg(bss, nl_flags, NL80211_CMD_GET_WIPHY)) ||
+ nla_put_flag(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP)) {
+ nlmsg_free(msg);
+ return NULL;
+ }
+
+ if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) {
+ nl80211_set_regulatory_flags(drv, &result);
+ return wpa_driver_nl80211_postprocess_modes(result.modes,
+ num_modes);
+ }
+
+ return NULL;
+}
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
new file mode 100644
index 0000000..d555033
--- /dev/null
+++ b/src/drivers/driver_nl80211_event.c
@@ -0,0 +1,1927 @@
+/*
+ * Driver interaction with Linux nl80211/cfg80211 - Event processing
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <netlink/genl/genl.h>
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/qca-vendor.h"
+#include "common/qca-vendor-attr.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "driver_nl80211.h"
+
+
+static const char * nl80211_command_to_string(enum nl80211_commands cmd)
+{
+#define C2S(x) case x: return #x;
+ switch (cmd) {
+ C2S(NL80211_CMD_UNSPEC)
+ C2S(NL80211_CMD_GET_WIPHY)
+ C2S(NL80211_CMD_SET_WIPHY)
+ C2S(NL80211_CMD_NEW_WIPHY)
+ C2S(NL80211_CMD_DEL_WIPHY)
+ C2S(NL80211_CMD_GET_INTERFACE)
+ C2S(NL80211_CMD_SET_INTERFACE)
+ C2S(NL80211_CMD_NEW_INTERFACE)
+ C2S(NL80211_CMD_DEL_INTERFACE)
+ C2S(NL80211_CMD_GET_KEY)
+ C2S(NL80211_CMD_SET_KEY)
+ C2S(NL80211_CMD_NEW_KEY)
+ C2S(NL80211_CMD_DEL_KEY)
+ C2S(NL80211_CMD_GET_BEACON)
+ C2S(NL80211_CMD_SET_BEACON)
+ C2S(NL80211_CMD_START_AP)
+ C2S(NL80211_CMD_STOP_AP)
+ C2S(NL80211_CMD_GET_STATION)
+ C2S(NL80211_CMD_SET_STATION)
+ C2S(NL80211_CMD_NEW_STATION)
+ C2S(NL80211_CMD_DEL_STATION)
+ C2S(NL80211_CMD_GET_MPATH)
+ C2S(NL80211_CMD_SET_MPATH)
+ C2S(NL80211_CMD_NEW_MPATH)
+ C2S(NL80211_CMD_DEL_MPATH)
+ C2S(NL80211_CMD_SET_BSS)
+ C2S(NL80211_CMD_SET_REG)
+ C2S(NL80211_CMD_REQ_SET_REG)
+ C2S(NL80211_CMD_GET_MESH_CONFIG)
+ C2S(NL80211_CMD_SET_MESH_CONFIG)
+ C2S(NL80211_CMD_SET_MGMT_EXTRA_IE)
+ C2S(NL80211_CMD_GET_REG)
+ C2S(NL80211_CMD_GET_SCAN)
+ C2S(NL80211_CMD_TRIGGER_SCAN)
+ C2S(NL80211_CMD_NEW_SCAN_RESULTS)
+ C2S(NL80211_CMD_SCAN_ABORTED)
+ C2S(NL80211_CMD_REG_CHANGE)
+ C2S(NL80211_CMD_AUTHENTICATE)
+ C2S(NL80211_CMD_ASSOCIATE)
+ C2S(NL80211_CMD_DEAUTHENTICATE)
+ C2S(NL80211_CMD_DISASSOCIATE)
+ C2S(NL80211_CMD_MICHAEL_MIC_FAILURE)
+ C2S(NL80211_CMD_REG_BEACON_HINT)
+ C2S(NL80211_CMD_JOIN_IBSS)
+ C2S(NL80211_CMD_LEAVE_IBSS)
+ C2S(NL80211_CMD_TESTMODE)
+ C2S(NL80211_CMD_CONNECT)
+ C2S(NL80211_CMD_ROAM)
+ C2S(NL80211_CMD_DISCONNECT)
+ C2S(NL80211_CMD_SET_WIPHY_NETNS)
+ C2S(NL80211_CMD_GET_SURVEY)
+ C2S(NL80211_CMD_NEW_SURVEY_RESULTS)
+ C2S(NL80211_CMD_SET_PMKSA)
+ C2S(NL80211_CMD_DEL_PMKSA)
+ C2S(NL80211_CMD_FLUSH_PMKSA)
+ C2S(NL80211_CMD_REMAIN_ON_CHANNEL)
+ C2S(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL)
+ C2S(NL80211_CMD_SET_TX_BITRATE_MASK)
+ C2S(NL80211_CMD_REGISTER_FRAME)
+ C2S(NL80211_CMD_FRAME)
+ C2S(NL80211_CMD_FRAME_TX_STATUS)
+ C2S(NL80211_CMD_SET_POWER_SAVE)
+ C2S(NL80211_CMD_GET_POWER_SAVE)
+ C2S(NL80211_CMD_SET_CQM)
+ C2S(NL80211_CMD_NOTIFY_CQM)
+ C2S(NL80211_CMD_SET_CHANNEL)
+ C2S(NL80211_CMD_SET_WDS_PEER)
+ C2S(NL80211_CMD_FRAME_WAIT_CANCEL)
+ C2S(NL80211_CMD_JOIN_MESH)
+ C2S(NL80211_CMD_LEAVE_MESH)
+ C2S(NL80211_CMD_UNPROT_DEAUTHENTICATE)
+ C2S(NL80211_CMD_UNPROT_DISASSOCIATE)
+ C2S(NL80211_CMD_NEW_PEER_CANDIDATE)
+ C2S(NL80211_CMD_GET_WOWLAN)
+ C2S(NL80211_CMD_SET_WOWLAN)
+ C2S(NL80211_CMD_START_SCHED_SCAN)
+ C2S(NL80211_CMD_STOP_SCHED_SCAN)
+ C2S(NL80211_CMD_SCHED_SCAN_RESULTS)
+ C2S(NL80211_CMD_SCHED_SCAN_STOPPED)
+ C2S(NL80211_CMD_SET_REKEY_OFFLOAD)
+ C2S(NL80211_CMD_PMKSA_CANDIDATE)
+ C2S(NL80211_CMD_TDLS_OPER)
+ C2S(NL80211_CMD_TDLS_MGMT)
+ C2S(NL80211_CMD_UNEXPECTED_FRAME)
+ C2S(NL80211_CMD_PROBE_CLIENT)
+ C2S(NL80211_CMD_REGISTER_BEACONS)
+ C2S(NL80211_CMD_UNEXPECTED_4ADDR_FRAME)
+ C2S(NL80211_CMD_SET_NOACK_MAP)
+ C2S(NL80211_CMD_CH_SWITCH_NOTIFY)
+ C2S(NL80211_CMD_START_P2P_DEVICE)
+ C2S(NL80211_CMD_STOP_P2P_DEVICE)
+ C2S(NL80211_CMD_CONN_FAILED)
+ C2S(NL80211_CMD_SET_MCAST_RATE)
+ C2S(NL80211_CMD_SET_MAC_ACL)
+ C2S(NL80211_CMD_RADAR_DETECT)
+ C2S(NL80211_CMD_GET_PROTOCOL_FEATURES)
+ C2S(NL80211_CMD_UPDATE_FT_IES)
+ C2S(NL80211_CMD_FT_EVENT)
+ C2S(NL80211_CMD_CRIT_PROTOCOL_START)
+ C2S(NL80211_CMD_CRIT_PROTOCOL_STOP)
+ C2S(NL80211_CMD_GET_COALESCE)
+ C2S(NL80211_CMD_SET_COALESCE)
+ C2S(NL80211_CMD_CHANNEL_SWITCH)
+ C2S(NL80211_CMD_VENDOR)
+ C2S(NL80211_CMD_SET_QOS_MAP)
+ C2S(NL80211_CMD_ADD_TX_TS)
+ C2S(NL80211_CMD_DEL_TX_TS)
+ default:
+ return "NL80211_CMD_UNKNOWN";
+ }
+#undef C2S
+}
+
+
+static void mlme_event_auth(struct wpa_driver_nl80211_data *drv,
+ const u8 *frame, size_t len)
+{
+ const struct ieee80211_mgmt *mgmt;
+ union wpa_event_data event;
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+ drv->force_connect_cmd) {
+ /*
+ * Avoid reporting two association events that would confuse
+ * the core code.
+ */
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignore auth event when using driver SME");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Authenticate event");
+ mgmt = (const struct ieee80211_mgmt *) frame;
+ if (len < 24 + sizeof(mgmt->u.auth)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
+ "frame");
+ return;
+ }
+
+ os_memcpy(drv->auth_bssid, mgmt->sa, ETH_ALEN);
+ os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN);
+ os_memset(&event, 0, sizeof(event));
+ os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN);
+ event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg);
+ event.auth.auth_transaction =
+ le_to_host16(mgmt->u.auth.auth_transaction);
+ event.auth.status_code = le_to_host16(mgmt->u.auth.status_code);
+ if (len > 24 + sizeof(mgmt->u.auth)) {
+ event.auth.ies = mgmt->u.auth.variable;
+ event.auth.ies_len = len - 24 - sizeof(mgmt->u.auth);
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_AUTH, &event);
+}
+
+
+static void nl80211_parse_wmm_params(struct nlattr *wmm_attr,
+ struct wmm_params *wmm_params)
+{
+ struct nlattr *wmm_info[NL80211_STA_WME_MAX + 1];
+ static struct nla_policy wme_policy[NL80211_STA_WME_MAX + 1] = {
+ [NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 },
+ };
+
+ if (!wmm_attr ||
+ nla_parse_nested(wmm_info, NL80211_STA_WME_MAX, wmm_attr,
+ wme_policy) ||
+ !wmm_info[NL80211_STA_WME_UAPSD_QUEUES])
+ return;
+
+ wmm_params->uapsd_queues =
+ nla_get_u8(wmm_info[NL80211_STA_WME_UAPSD_QUEUES]);
+ wmm_params->info_bitmap |= WMM_PARAMS_UAPSD_QUEUES_INFO;
+}
+
+
+static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
+ const u8 *frame, size_t len, struct nlattr *wmm)
+{
+ const struct ieee80211_mgmt *mgmt;
+ union wpa_event_data event;
+ u16 status;
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+ drv->force_connect_cmd) {
+ /*
+ * Avoid reporting two association events that would confuse
+ * the core code.
+ */
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignore assoc event when using driver SME");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Associate event");
+ mgmt = (const struct ieee80211_mgmt *) frame;
+ if (len < 24 + sizeof(mgmt->u.assoc_resp)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
+ "frame");
+ return;
+ }
+
+ status = le_to_host16(mgmt->u.assoc_resp.status_code);
+ if (status != WLAN_STATUS_SUCCESS) {
+ os_memset(&event, 0, sizeof(event));
+ event.assoc_reject.bssid = mgmt->bssid;
+ if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
+ event.assoc_reject.resp_ies =
+ (u8 *) mgmt->u.assoc_resp.variable;
+ event.assoc_reject.resp_ies_len =
+ len - 24 - sizeof(mgmt->u.assoc_resp);
+ }
+ event.assoc_reject.status_code = status;
+
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
+ return;
+ }
+
+ drv->associated = 1;
+ os_memcpy(drv->bssid, mgmt->sa, ETH_ALEN);
+ os_memcpy(drv->prev_bssid, mgmt->sa, ETH_ALEN);
+
+ os_memset(&event, 0, sizeof(event));
+ if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
+ event.assoc_info.resp_ies = (u8 *) mgmt->u.assoc_resp.variable;
+ event.assoc_info.resp_ies_len =
+ len - 24 - sizeof(mgmt->u.assoc_resp);
+ }
+
+ event.assoc_info.freq = drv->assoc_freq;
+
+ nl80211_parse_wmm_params(wmm, &event.assoc_info.wmm_params);
+
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
+}
+
+
+static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
+ enum nl80211_commands cmd, struct nlattr *status,
+ struct nlattr *addr, struct nlattr *req_ie,
+ struct nlattr *resp_ie,
+ struct nlattr *authorized,
+ struct nlattr *key_replay_ctr,
+ struct nlattr *ptk_kck,
+ struct nlattr *ptk_kek)
+{
+ union wpa_event_data event;
+ u16 status_code;
+
+ if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
+ /*
+ * Avoid reporting two association events that would confuse
+ * the core code.
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore connect event (cmd=%d) "
+ "when using userspace SME", cmd);
+ return;
+ }
+
+ status_code = status ? nla_get_u16(status) : WLAN_STATUS_SUCCESS;
+
+ if (cmd == NL80211_CMD_CONNECT) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Connect event (status=%u ignore_next_local_disconnect=%d)",
+ status_code, drv->ignore_next_local_disconnect);
+ } else if (cmd == NL80211_CMD_ROAM) {
+ wpa_printf(MSG_DEBUG, "nl80211: Roam event");
+ }
+
+ os_memset(&event, 0, sizeof(event));
+ if (cmd == NL80211_CMD_CONNECT && status_code != WLAN_STATUS_SUCCESS) {
+ if (addr)
+ event.assoc_reject.bssid = nla_data(addr);
+ if (drv->ignore_next_local_disconnect) {
+ drv->ignore_next_local_disconnect = 0;
+ if (!event.assoc_reject.bssid ||
+ (os_memcmp(event.assoc_reject.bssid,
+ drv->auth_attempt_bssid,
+ ETH_ALEN) != 0)) {
+ /*
+ * Ignore the event that came without a BSSID or
+ * for the old connection since this is likely
+ * not relevant to the new Connect command.
+ */
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignore connection failure event triggered during reassociation");
+ return;
+ }
+ }
+ if (resp_ie) {
+ event.assoc_reject.resp_ies = nla_data(resp_ie);
+ event.assoc_reject.resp_ies_len = nla_len(resp_ie);
+ }
+ event.assoc_reject.status_code = status_code;
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
+ return;
+ }
+
+ drv->associated = 1;
+ if (addr) {
+ os_memcpy(drv->bssid, nla_data(addr), ETH_ALEN);
+ os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN);
+ }
+
+ if (req_ie) {
+ event.assoc_info.req_ies = nla_data(req_ie);
+ event.assoc_info.req_ies_len = nla_len(req_ie);
+ }
+ if (resp_ie) {
+ event.assoc_info.resp_ies = nla_data(resp_ie);
+ event.assoc_info.resp_ies_len = nla_len(resp_ie);
+ }
+
+ event.assoc_info.freq = nl80211_get_assoc_freq(drv);
+
+ if (authorized && nla_get_u8(authorized)) {
+ event.assoc_info.authorized = 1;
+ wpa_printf(MSG_DEBUG, "nl80211: connection authorized");
+ }
+ if (key_replay_ctr) {
+ event.assoc_info.key_replay_ctr = nla_data(key_replay_ctr);
+ event.assoc_info.key_replay_ctr_len = nla_len(key_replay_ctr);
+ }
+ if (ptk_kck) {
+ event.assoc_info.ptk_kck = nla_data(ptk_kck);
+ event.assoc_info.ptk_kck_len = nla_len(ptk_kck);
+ }
+ if (ptk_kek) {
+ event.assoc_info.ptk_kek = nla_data(ptk_kek);
+ event.assoc_info.ptk_kek_len = nla_len(ptk_kek);
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
+}
+
+
+static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *reason, struct nlattr *addr,
+ struct nlattr *by_ap)
+{
+ union wpa_event_data data;
+ unsigned int locally_generated = by_ap == NULL;
+
+ if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
+ /*
+ * Avoid reporting two disassociation events that could
+ * confuse the core code.
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
+ "event when using userspace SME");
+ return;
+ }
+
+ if (drv->ignore_next_local_disconnect) {
+ drv->ignore_next_local_disconnect = 0;
+ if (locally_generated) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
+ "event triggered during reassociation");
+ return;
+ }
+ wpa_printf(MSG_WARNING, "nl80211: Was expecting local "
+ "disconnect but got another disconnect "
+ "event first");
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Disconnect event");
+ nl80211_mark_disconnected(drv);
+ os_memset(&data, 0, sizeof(data));
+ if (reason)
+ data.deauth_info.reason_code = nla_get_u16(reason);
+ data.deauth_info.locally_generated = by_ap == NULL;
+ wpa_supplicant_event(drv->ctx, EVENT_DEAUTH, &data);
+}
+
+
+static int calculate_chan_offset(int width, int freq, int cf1, int cf2)
+{
+ int freq1 = 0;
+
+ switch (convert2width(width)) {
+ case CHAN_WIDTH_20_NOHT:
+ case CHAN_WIDTH_20:
+ return 0;
+ case CHAN_WIDTH_40:
+ freq1 = cf1 - 10;
+ break;
+ case CHAN_WIDTH_80:
+ freq1 = cf1 - 30;
+ break;
+ case CHAN_WIDTH_160:
+ freq1 = cf1 - 70;
+ break;
+ case CHAN_WIDTH_UNKNOWN:
+ case CHAN_WIDTH_80P80:
+ /* FIXME: implement this */
+ return 0;
+ }
+
+ return (abs(freq - freq1) / 20) % 2 == 0 ? 1 : -1;
+}
+
+
+static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *ifindex, struct nlattr *freq,
+ struct nlattr *type, struct nlattr *bw,
+ struct nlattr *cf1, struct nlattr *cf2)
+{
+ struct i802_bss *bss;
+ union wpa_event_data data;
+ int ht_enabled = 1;
+ int chan_offset = 0;
+ int ifidx;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Channel switch event");
+
+ if (!freq)
+ return;
+
+ ifidx = nla_get_u32(ifindex);
+ bss = get_bss_ifindex(drv, ifidx);
+ if (bss == NULL) {
+ wpa_printf(MSG_WARNING, "nl80211: Unknown ifindex (%d) for channel switch, ignoring",
+ ifidx);
+ return;
+ }
+
+ if (type) {
+ enum nl80211_channel_type ch_type = nla_get_u32(type);
+
+ wpa_printf(MSG_DEBUG, "nl80211: Channel type: %d", ch_type);
+ switch (ch_type) {
+ case NL80211_CHAN_NO_HT:
+ ht_enabled = 0;
+ break;
+ case NL80211_CHAN_HT20:
+ break;
+ case NL80211_CHAN_HT40PLUS:
+ chan_offset = 1;
+ break;
+ case NL80211_CHAN_HT40MINUS:
+ chan_offset = -1;
+ break;
+ }
+ } else if (bw && cf1) {
+ /* This can happen for example with VHT80 ch switch */
+ chan_offset = calculate_chan_offset(nla_get_u32(bw),
+ nla_get_u32(freq),
+ nla_get_u32(cf1),
+ cf2 ? nla_get_u32(cf2) : 0);
+ } else {
+ wpa_printf(MSG_WARNING, "nl80211: Unknown secondary channel information - following channel definition calculations may fail");
+ }
+
+ os_memset(&data, 0, sizeof(data));
+ data.ch_switch.freq = nla_get_u32(freq);
+ data.ch_switch.ht_enabled = ht_enabled;
+ data.ch_switch.ch_offset = chan_offset;
+ if (bw)
+ data.ch_switch.ch_width = convert2width(nla_get_u32(bw));
+ if (cf1)
+ data.ch_switch.cf1 = nla_get_u32(cf1);
+ if (cf2)
+ data.ch_switch.cf2 = nla_get_u32(cf2);
+
+ bss->freq = data.ch_switch.freq;
+
+ wpa_supplicant_event(bss->ctx, EVENT_CH_SWITCH, &data);
+}
+
+
+static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv,
+ enum nl80211_commands cmd, struct nlattr *addr)
+{
+ union wpa_event_data event;
+ enum wpa_event_type ev;
+
+ if (nla_len(addr) != ETH_ALEN)
+ return;
+
+ wpa_printf(MSG_DEBUG, "nl80211: MLME event %d; timeout with " MACSTR,
+ cmd, MAC2STR((u8 *) nla_data(addr)));
+
+ if (cmd == NL80211_CMD_AUTHENTICATE)
+ ev = EVENT_AUTH_TIMED_OUT;
+ else if (cmd == NL80211_CMD_ASSOCIATE)
+ ev = EVENT_ASSOC_TIMED_OUT;
+ else
+ return;
+
+ os_memset(&event, 0, sizeof(event));
+ os_memcpy(event.timeout_event.addr, nla_data(addr), ETH_ALEN);
+ wpa_supplicant_event(drv->ctx, ev, &event);
+}
+
+
+static void mlme_event_mgmt(struct i802_bss *bss,
+ struct nlattr *freq, struct nlattr *sig,
+ const u8 *frame, size_t len)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ const struct ieee80211_mgmt *mgmt;
+ union wpa_event_data event;
+ u16 fc, stype;
+ int ssi_signal = 0;
+ int rx_freq = 0;
+
+ wpa_printf(MSG_MSGDUMP, "nl80211: Frame event");
+ mgmt = (const struct ieee80211_mgmt *) frame;
+ if (len < 24) {
+ wpa_printf(MSG_DEBUG, "nl80211: Too short management frame");
+ return;
+ }
+
+ fc = le_to_host16(mgmt->frame_control);
+ stype = WLAN_FC_GET_STYPE(fc);
+
+ if (sig)
+ ssi_signal = (s32) nla_get_u32(sig);
+
+ os_memset(&event, 0, sizeof(event));
+ if (freq) {
+ event.rx_mgmt.freq = nla_get_u32(freq);
+ rx_freq = drv->last_mgmt_freq = event.rx_mgmt.freq;
+ }
+ wpa_printf(MSG_DEBUG,
+ "nl80211: RX frame sa=" MACSTR
+ " freq=%d ssi_signal=%d fc=0x%x seq_ctrl=0x%x stype=%u (%s) len=%u",
+ MAC2STR(mgmt->sa), rx_freq, ssi_signal, fc,
+ le_to_host16(mgmt->seq_ctrl), stype, fc2str(fc),
+ (unsigned int) len);
+ event.rx_mgmt.frame = frame;
+ event.rx_mgmt.frame_len = len;
+ event.rx_mgmt.ssi_signal = ssi_signal;
+ event.rx_mgmt.drv_priv = bss;
+ wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
+}
+
+
+static void mlme_event_mgmt_tx_status(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *cookie, const u8 *frame,
+ size_t len, struct nlattr *ack)
+{
+ union wpa_event_data event;
+ const struct ieee80211_hdr *hdr;
+ u16 fc;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Frame TX status event");
+ if (!is_ap_interface(drv->nlmode)) {
+ u64 cookie_val;
+
+ if (!cookie)
+ return;
+
+ cookie_val = nla_get_u64(cookie);
+ wpa_printf(MSG_DEBUG, "nl80211: Action TX status:"
+ " cookie=0%llx%s (ack=%d)",
+ (long long unsigned int) cookie_val,
+ cookie_val == drv->send_action_cookie ?
+ " (match)" : " (unknown)", ack != NULL);
+ if (cookie_val != drv->send_action_cookie)
+ return;
+ }
+
+ hdr = (const struct ieee80211_hdr *) frame;
+ fc = le_to_host16(hdr->frame_control);
+
+ os_memset(&event, 0, sizeof(event));
+ event.tx_status.type = WLAN_FC_GET_TYPE(fc);
+ event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
+ event.tx_status.dst = hdr->addr1;
+ event.tx_status.data = frame;
+ event.tx_status.data_len = len;
+ event.tx_status.ack = ack != NULL;
+ wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event);
+}
+
+
+static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
+ enum wpa_event_type type,
+ const u8 *frame, size_t len)
+{
+ const struct ieee80211_mgmt *mgmt;
+ union wpa_event_data event;
+ const u8 *bssid = NULL;
+ u16 reason_code = 0;
+
+ if (type == EVENT_DEAUTH)
+ wpa_printf(MSG_DEBUG, "nl80211: Deauthenticate event");
+ else
+ wpa_printf(MSG_DEBUG, "nl80211: Disassociate event");
+
+ mgmt = (const struct ieee80211_mgmt *) frame;
+ if (len >= 24) {
+ bssid = mgmt->bssid;
+
+ if ((drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+ !drv->associated &&
+ os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0 &&
+ os_memcmp(bssid, drv->auth_attempt_bssid, ETH_ALEN) != 0 &&
+ os_memcmp(bssid, drv->prev_bssid, ETH_ALEN) == 0) {
+ /*
+ * Avoid issues with some roaming cases where
+ * disconnection event for the old AP may show up after
+ * we have started connection with the new AP.
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth/disassoc event from old AP " MACSTR " when already authenticating with " MACSTR,
+ MAC2STR(bssid),
+ MAC2STR(drv->auth_attempt_bssid));
+ return;
+ }
+
+ if (drv->associated != 0 &&
+ os_memcmp(bssid, drv->bssid, ETH_ALEN) != 0 &&
+ os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0) {
+ /*
+ * We have presumably received this deauth as a
+ * response to a clear_state_mismatch() outgoing
+ * deauth. Don't let it take us offline!
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Deauth received "
+ "from Unknown BSSID " MACSTR " -- ignoring",
+ MAC2STR(bssid));
+ return;
+ }
+ }
+
+ nl80211_mark_disconnected(drv);
+ os_memset(&event, 0, sizeof(event));
+
+ /* Note: Same offset for Reason Code in both frame subtypes */
+ if (len >= 24 + sizeof(mgmt->u.deauth))
+ reason_code = le_to_host16(mgmt->u.deauth.reason_code);
+
+ if (type == EVENT_DISASSOC) {
+ event.disassoc_info.locally_generated =
+ !os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN);
+ event.disassoc_info.addr = bssid;
+ event.disassoc_info.reason_code = reason_code;
+ if (frame + len > mgmt->u.disassoc.variable) {
+ event.disassoc_info.ie = mgmt->u.disassoc.variable;
+ event.disassoc_info.ie_len = frame + len -
+ mgmt->u.disassoc.variable;
+ }
+ } else {
+ if (drv->ignore_deauth_event) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth event due to previous forced deauth-during-auth");
+ drv->ignore_deauth_event = 0;
+ return;
+ }
+ event.deauth_info.locally_generated =
+ !os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN);
+ if (drv->ignore_next_local_deauth) {
+ drv->ignore_next_local_deauth = 0;
+ if (event.deauth_info.locally_generated) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth event triggered due to own deauth request");
+ return;
+ }
+ wpa_printf(MSG_WARNING, "nl80211: Was expecting local deauth but got another disconnect event first");
+ }
+ event.deauth_info.addr = bssid;
+ event.deauth_info.reason_code = reason_code;
+ if (frame + len > mgmt->u.deauth.variable) {
+ event.deauth_info.ie = mgmt->u.deauth.variable;
+ event.deauth_info.ie_len = frame + len -
+ mgmt->u.deauth.variable;
+ }
+ }
+
+ wpa_supplicant_event(drv->ctx, type, &event);
+}
+
+
+static void mlme_event_unprot_disconnect(struct wpa_driver_nl80211_data *drv,
+ enum wpa_event_type type,
+ const u8 *frame, size_t len)
+{
+ const struct ieee80211_mgmt *mgmt;
+ union wpa_event_data event;
+ u16 reason_code = 0;
+
+ if (type == EVENT_UNPROT_DEAUTH)
+ wpa_printf(MSG_DEBUG, "nl80211: Unprot Deauthenticate event");
+ else
+ wpa_printf(MSG_DEBUG, "nl80211: Unprot Disassociate event");
+
+ if (len < 24)
+ return;
+
+ mgmt = (const struct ieee80211_mgmt *) frame;
+
+ os_memset(&event, 0, sizeof(event));
+ /* Note: Same offset for Reason Code in both frame subtypes */
+ if (len >= 24 + sizeof(mgmt->u.deauth))
+ reason_code = le_to_host16(mgmt->u.deauth.reason_code);
+
+ if (type == EVENT_UNPROT_DISASSOC) {
+ event.unprot_disassoc.sa = mgmt->sa;
+ event.unprot_disassoc.da = mgmt->da;
+ event.unprot_disassoc.reason_code = reason_code;
+ } else {
+ event.unprot_deauth.sa = mgmt->sa;
+ event.unprot_deauth.da = mgmt->da;
+ event.unprot_deauth.reason_code = reason_code;
+ }
+
+ wpa_supplicant_event(drv->ctx, type, &event);
+}
+
+
+static void mlme_event(struct i802_bss *bss,
+ enum nl80211_commands cmd, struct nlattr *frame,
+ struct nlattr *addr, struct nlattr *timed_out,
+ struct nlattr *freq, struct nlattr *ack,
+ struct nlattr *cookie, struct nlattr *sig,
+ struct nlattr *wmm)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ const u8 *data;
+ size_t len;
+
+ if (timed_out && addr) {
+ mlme_timeout_event(drv, cmd, addr);
+ return;
+ }
+
+ if (frame == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: MLME event %d (%s) without frame data",
+ cmd, nl80211_command_to_string(cmd));
+ return;
+ }
+
+ data = nla_data(frame);
+ len = nla_len(frame);
+ if (len < 4 + 2 * ETH_ALEN) {
+ wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s("
+ MACSTR ") - too short",
+ cmd, nl80211_command_to_string(cmd), bss->ifname,
+ MAC2STR(bss->addr));
+ return;
+ }
+ wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s(" MACSTR
+ ") A1=" MACSTR " A2=" MACSTR, cmd,
+ nl80211_command_to_string(cmd), bss->ifname,
+ MAC2STR(bss->addr), MAC2STR(data + 4),
+ MAC2STR(data + 4 + ETH_ALEN));
+ if (cmd != NL80211_CMD_FRAME_TX_STATUS && !(data[4] & 0x01) &&
+ os_memcmp(bss->addr, data + 4, ETH_ALEN) != 0 &&
+ os_memcmp(bss->addr, data + 4 + ETH_ALEN, ETH_ALEN) != 0) {
+ wpa_printf(MSG_MSGDUMP, "nl80211: %s: Ignore MLME frame event "
+ "for foreign address", bss->ifname);
+ return;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "nl80211: MLME event frame",
+ nla_data(frame), nla_len(frame));
+
+ switch (cmd) {
+ case NL80211_CMD_AUTHENTICATE:
+ mlme_event_auth(drv, nla_data(frame), nla_len(frame));
+ break;
+ case NL80211_CMD_ASSOCIATE:
+ mlme_event_assoc(drv, nla_data(frame), nla_len(frame), wmm);
+ break;
+ case NL80211_CMD_DEAUTHENTICATE:
+ mlme_event_deauth_disassoc(drv, EVENT_DEAUTH,
+ nla_data(frame), nla_len(frame));
+ break;
+ case NL80211_CMD_DISASSOCIATE:
+ mlme_event_deauth_disassoc(drv, EVENT_DISASSOC,
+ nla_data(frame), nla_len(frame));
+ break;
+ case NL80211_CMD_FRAME:
+ mlme_event_mgmt(bss, freq, sig, nla_data(frame),
+ nla_len(frame));
+ break;
+ case NL80211_CMD_FRAME_TX_STATUS:
+ mlme_event_mgmt_tx_status(drv, cookie, nla_data(frame),
+ nla_len(frame), ack);
+ break;
+ case NL80211_CMD_UNPROT_DEAUTHENTICATE:
+ mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DEAUTH,
+ nla_data(frame), nla_len(frame));
+ break;
+ case NL80211_CMD_UNPROT_DISASSOCIATE:
+ mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DISASSOC,
+ nla_data(frame), nla_len(frame));
+ break;
+ default:
+ break;
+ }
+}
+
+
+static void mlme_event_michael_mic_failure(struct i802_bss *bss,
+ struct nlattr *tb[])
+{
+ union wpa_event_data data;
+
+ wpa_printf(MSG_DEBUG, "nl80211: MLME event Michael MIC failure");
+ os_memset(&data, 0, sizeof(data));
+ if (tb[NL80211_ATTR_MAC]) {
+ wpa_hexdump(MSG_DEBUG, "nl80211: Source MAC address",
+ nla_data(tb[NL80211_ATTR_MAC]),
+ nla_len(tb[NL80211_ATTR_MAC]));
+ data.michael_mic_failure.src = nla_data(tb[NL80211_ATTR_MAC]);
+ }
+ if (tb[NL80211_ATTR_KEY_SEQ]) {
+ wpa_hexdump(MSG_DEBUG, "nl80211: TSC",
+ nla_data(tb[NL80211_ATTR_KEY_SEQ]),
+ nla_len(tb[NL80211_ATTR_KEY_SEQ]));
+ }
+ if (tb[NL80211_ATTR_KEY_TYPE]) {
+ enum nl80211_key_type key_type =
+ nla_get_u32(tb[NL80211_ATTR_KEY_TYPE]);
+ wpa_printf(MSG_DEBUG, "nl80211: Key Type %d", key_type);
+ if (key_type == NL80211_KEYTYPE_PAIRWISE)
+ data.michael_mic_failure.unicast = 1;
+ } else
+ data.michael_mic_failure.unicast = 1;
+
+ if (tb[NL80211_ATTR_KEY_IDX]) {
+ u8 key_id = nla_get_u8(tb[NL80211_ATTR_KEY_IDX]);
+ wpa_printf(MSG_DEBUG, "nl80211: Key Id %d", key_id);
+ }
+
+ wpa_supplicant_event(bss->ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+}
+
+
+static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *tb[])
+{
+ unsigned int freq;
+
+ if (tb[NL80211_ATTR_MAC] == NULL) {
+ wpa_printf(MSG_DEBUG, "nl80211: No address in IBSS joined "
+ "event");
+ return;
+ }
+ os_memcpy(drv->bssid, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+
+ drv->associated = 1;
+ wpa_printf(MSG_DEBUG, "nl80211: IBSS " MACSTR " joined",
+ MAC2STR(drv->bssid));
+
+ freq = nl80211_get_assoc_freq(drv);
+ if (freq) {
+ wpa_printf(MSG_DEBUG, "nl80211: IBSS on frequency %u MHz",
+ freq);
+ drv->first_bss->freq = freq;
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
+}
+
+
+static void mlme_event_remain_on_channel(struct wpa_driver_nl80211_data *drv,
+ int cancel_event, struct nlattr *tb[])
+{
+ unsigned int freq, chan_type, duration;
+ union wpa_event_data data;
+ u64 cookie;
+
+ if (tb[NL80211_ATTR_WIPHY_FREQ])
+ freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
+ else
+ freq = 0;
+
+ if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE])
+ chan_type = nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
+ else
+ chan_type = 0;
+
+ if (tb[NL80211_ATTR_DURATION])
+ duration = nla_get_u32(tb[NL80211_ATTR_DURATION]);
+ else
+ duration = 0;
+
+ if (tb[NL80211_ATTR_COOKIE])
+ cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
+ else
+ cookie = 0;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel event (cancel=%d "
+ "freq=%u channel_type=%u duration=%u cookie=0x%llx (%s))",
+ cancel_event, freq, chan_type, duration,
+ (long long unsigned int) cookie,
+ cookie == drv->remain_on_chan_cookie ? "match" : "unknown");
+
+ if (cookie != drv->remain_on_chan_cookie)
+ return; /* not for us */
+
+ if (cancel_event)
+ drv->pending_remain_on_chan = 0;
+
+ os_memset(&data, 0, sizeof(data));
+ data.remain_on_channel.freq = freq;
+ data.remain_on_channel.duration = duration;
+ wpa_supplicant_event(drv->ctx, cancel_event ?
+ EVENT_CANCEL_REMAIN_ON_CHANNEL :
+ EVENT_REMAIN_ON_CHANNEL, &data);
+}
+
+
+static void mlme_event_ft_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *tb[])
+{
+ union wpa_event_data data;
+
+ os_memset(&data, 0, sizeof(data));
+
+ if (tb[NL80211_ATTR_IE]) {
+ data.ft_ies.ies = nla_data(tb[NL80211_ATTR_IE]);
+ data.ft_ies.ies_len = nla_len(tb[NL80211_ATTR_IE]);
+ }
+
+ if (tb[NL80211_ATTR_IE_RIC]) {
+ data.ft_ies.ric_ies = nla_data(tb[NL80211_ATTR_IE_RIC]);
+ data.ft_ies.ric_ies_len = nla_len(tb[NL80211_ATTR_IE_RIC]);
+ }
+
+ if (tb[NL80211_ATTR_MAC])
+ os_memcpy(data.ft_ies.target_ap,
+ nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+
+ wpa_printf(MSG_DEBUG, "nl80211: FT event target_ap " MACSTR,
+ MAC2STR(data.ft_ies.target_ap));
+
+ wpa_supplicant_event(drv->ctx, EVENT_FT_RESPONSE, &data);
+}
+
+
+static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
+ struct nlattr *tb[])
+{
+ union wpa_event_data event;
+ struct nlattr *nl;
+ int rem;
+ struct scan_info *info;
+#define MAX_REPORT_FREQS 50
+ int freqs[MAX_REPORT_FREQS];
+ int num_freqs = 0;
+
+ if (drv->scan_for_auth) {
+ drv->scan_for_auth = 0;
+ wpa_printf(MSG_DEBUG, "nl80211: Scan results for missing "
+ "cfg80211 BSS entry");
+ wpa_driver_nl80211_authenticate_retry(drv);
+ return;
+ }
+
+ os_memset(&event, 0, sizeof(event));
+ info = &event.scan_info;
+ info->aborted = aborted;
+
+ if (tb[NL80211_ATTR_SCAN_SSIDS]) {
+ nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_SSIDS], rem) {
+ struct wpa_driver_scan_ssid *s =
+ &info->ssids[info->num_ssids];
+ s->ssid = nla_data(nl);
+ s->ssid_len = nla_len(nl);
+ wpa_printf(MSG_DEBUG, "nl80211: Scan probed for SSID '%s'",
+ wpa_ssid_txt(s->ssid, s->ssid_len));
+ info->num_ssids++;
+ if (info->num_ssids == WPAS_MAX_SCAN_SSIDS)
+ break;
+ }
+ }
+ if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) {
+ char msg[200], *pos, *end;
+ int res;
+
+ pos = msg;
+ end = pos + sizeof(msg);
+ *pos = '\0';
+
+ nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem)
+ {
+ freqs[num_freqs] = nla_get_u32(nl);
+ res = os_snprintf(pos, end - pos, " %d",
+ freqs[num_freqs]);
+ if (!os_snprintf_error(end - pos, res))
+ pos += res;
+ num_freqs++;
+ if (num_freqs == MAX_REPORT_FREQS - 1)
+ break;
+ }
+ info->freqs = freqs;
+ info->num_freqs = num_freqs;
+ wpa_printf(MSG_DEBUG, "nl80211: Scan included frequencies:%s",
+ msg);
+ }
+ wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event);
+}
+
+
+static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *tb[])
+{
+ static struct nla_policy cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
+ [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
+ [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U8 },
+ [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
+ [NL80211_ATTR_CQM_PKT_LOSS_EVENT] = { .type = NLA_U32 },
+ };
+ struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1];
+ enum nl80211_cqm_rssi_threshold_event event;
+ union wpa_event_data ed;
+ struct wpa_signal_info sig;
+ int res;
+
+ if (tb[NL80211_ATTR_CQM] == NULL ||
+ nla_parse_nested(cqm, NL80211_ATTR_CQM_MAX, tb[NL80211_ATTR_CQM],
+ cqm_policy)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore invalid CQM event");
+ return;
+ }
+
+ os_memset(&ed, 0, sizeof(ed));
+
+ if (cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]) {
+ if (!tb[NL80211_ATTR_MAC])
+ return;
+ os_memcpy(ed.low_ack.addr, nla_data(tb[NL80211_ATTR_MAC]),
+ ETH_ALEN);
+ wpa_supplicant_event(drv->ctx, EVENT_STATION_LOW_ACK, &ed);
+ return;
+ }
+
+ if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] == NULL)
+ return;
+ event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]);
+
+ if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH) {
+ wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
+ "event: RSSI high");
+ ed.signal_change.above_threshold = 1;
+ } else if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW) {
+ wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
+ "event: RSSI low");
+ ed.signal_change.above_threshold = 0;
+ } else
+ return;
+
+ res = nl80211_get_link_signal(drv, &sig);
+ if (res == 0) {
+ ed.signal_change.current_signal = sig.current_signal;
+ ed.signal_change.current_txrate = sig.current_txrate;
+ wpa_printf(MSG_DEBUG, "nl80211: Signal: %d dBm txrate: %d",
+ sig.current_signal, sig.current_txrate);
+ }
+
+ res = nl80211_get_link_noise(drv, &sig);
+ if (res == 0) {
+ ed.signal_change.current_noise = sig.current_noise;
+ wpa_printf(MSG_DEBUG, "nl80211: Noise: %d dBm",
+ sig.current_noise);
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_SIGNAL_CHANGE, &ed);
+}
+
+
+static void nl80211_new_peer_candidate(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ const u8 *addr;
+ union wpa_event_data data;
+
+ if (drv->nlmode != NL80211_IFTYPE_MESH_POINT ||
+ !tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_IE])
+ return;
+
+ addr = nla_data(tb[NL80211_ATTR_MAC]);
+ wpa_printf(MSG_DEBUG, "nl80211: New peer candidate" MACSTR,
+ MAC2STR(addr));
+
+ os_memset(&data, 0, sizeof(data));
+ data.mesh_peer.peer = addr;
+ data.mesh_peer.ies = nla_data(tb[NL80211_ATTR_IE]);
+ data.mesh_peer.ie_len = nla_len(tb[NL80211_ATTR_IE]);
+ wpa_supplicant_event(drv->ctx, EVENT_NEW_PEER_CANDIDATE, &data);
+}
+
+
+static void nl80211_new_station_event(struct wpa_driver_nl80211_data *drv,
+ struct i802_bss *bss,
+ struct nlattr **tb)
+{
+ u8 *addr;
+ union wpa_event_data data;
+
+ if (tb[NL80211_ATTR_MAC] == NULL)
+ return;
+ addr = nla_data(tb[NL80211_ATTR_MAC]);
+ wpa_printf(MSG_DEBUG, "nl80211: New station " MACSTR, MAC2STR(addr));
+
+ if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
+ u8 *ies = NULL;
+ size_t ies_len = 0;
+ if (tb[NL80211_ATTR_IE]) {
+ ies = nla_data(tb[NL80211_ATTR_IE]);
+ ies_len = nla_len(tb[NL80211_ATTR_IE]);
+ }
+ wpa_hexdump(MSG_DEBUG, "nl80211: Assoc Req IEs", ies, ies_len);
+ drv_event_assoc(bss->ctx, addr, ies, ies_len, 0);
+ return;
+ }
+
+ if (drv->nlmode != NL80211_IFTYPE_ADHOC)
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.ibss_rsn_start.peer, addr, ETH_ALEN);
+ wpa_supplicant_event(bss->ctx, EVENT_IBSS_RSN_START, &data);
+}
+
+
+static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ u8 *addr;
+ union wpa_event_data data;
+
+ if (tb[NL80211_ATTR_MAC] == NULL)
+ return;
+ addr = nla_data(tb[NL80211_ATTR_MAC]);
+ wpa_printf(MSG_DEBUG, "nl80211: Delete station " MACSTR,
+ MAC2STR(addr));
+
+ if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
+ drv_event_disassoc(drv->ctx, addr);
+ return;
+ }
+
+ if (drv->nlmode != NL80211_IFTYPE_ADHOC)
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.ibss_peer_lost.peer, addr, ETH_ALEN);
+ wpa_supplicant_event(drv->ctx, EVENT_IBSS_PEER_LOST, &data);
+}
+
+
+static void nl80211_rekey_offload_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ struct nlattr *rekey_info[NUM_NL80211_REKEY_DATA];
+ static struct nla_policy rekey_policy[NUM_NL80211_REKEY_DATA] = {
+ [NL80211_REKEY_DATA_KEK] = {
+ .minlen = NL80211_KEK_LEN,
+ .maxlen = NL80211_KEK_LEN,
+ },
+ [NL80211_REKEY_DATA_KCK] = {
+ .minlen = NL80211_KCK_LEN,
+ .maxlen = NL80211_KCK_LEN,
+ },
+ [NL80211_REKEY_DATA_REPLAY_CTR] = {
+ .minlen = NL80211_REPLAY_CTR_LEN,
+ .maxlen = NL80211_REPLAY_CTR_LEN,
+ },
+ };
+ union wpa_event_data data;
+
+ if (!tb[NL80211_ATTR_MAC] ||
+ !tb[NL80211_ATTR_REKEY_DATA] ||
+ nla_parse_nested(rekey_info, MAX_NL80211_REKEY_DATA,
+ tb[NL80211_ATTR_REKEY_DATA], rekey_policy) ||
+ !rekey_info[NL80211_REKEY_DATA_REPLAY_CTR])
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ data.driver_gtk_rekey.bssid = nla_data(tb[NL80211_ATTR_MAC]);
+ wpa_printf(MSG_DEBUG, "nl80211: Rekey offload event for BSSID " MACSTR,
+ MAC2STR(data.driver_gtk_rekey.bssid));
+ data.driver_gtk_rekey.replay_ctr =
+ nla_data(rekey_info[NL80211_REKEY_DATA_REPLAY_CTR]);
+ wpa_hexdump(MSG_DEBUG, "nl80211: Rekey offload - Replay Counter",
+ data.driver_gtk_rekey.replay_ctr, NL80211_REPLAY_CTR_LEN);
+ wpa_supplicant_event(drv->ctx, EVENT_DRIVER_GTK_REKEY, &data);
+}
+
+
+static void nl80211_pmksa_candidate_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ struct nlattr *cand[NUM_NL80211_PMKSA_CANDIDATE];
+ static struct nla_policy cand_policy[NUM_NL80211_PMKSA_CANDIDATE] = {
+ [NL80211_PMKSA_CANDIDATE_INDEX] = { .type = NLA_U32 },
+ [NL80211_PMKSA_CANDIDATE_BSSID] = {
+ .minlen = ETH_ALEN,
+ .maxlen = ETH_ALEN,
+ },
+ [NL80211_PMKSA_CANDIDATE_PREAUTH] = { .type = NLA_FLAG },
+ };
+ union wpa_event_data data;
+
+ wpa_printf(MSG_DEBUG, "nl80211: PMKSA candidate event");
+
+ if (!tb[NL80211_ATTR_PMKSA_CANDIDATE] ||
+ nla_parse_nested(cand, MAX_NL80211_PMKSA_CANDIDATE,
+ tb[NL80211_ATTR_PMKSA_CANDIDATE], cand_policy) ||
+ !cand[NL80211_PMKSA_CANDIDATE_INDEX] ||
+ !cand[NL80211_PMKSA_CANDIDATE_BSSID])
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.pmkid_candidate.bssid,
+ nla_data(cand[NL80211_PMKSA_CANDIDATE_BSSID]), ETH_ALEN);
+ data.pmkid_candidate.index =
+ nla_get_u32(cand[NL80211_PMKSA_CANDIDATE_INDEX]);
+ data.pmkid_candidate.preauth =
+ cand[NL80211_PMKSA_CANDIDATE_PREAUTH] != NULL;
+ wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data);
+}
+
+
+static void nl80211_client_probe_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ union wpa_event_data data;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Probe client event");
+
+ if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_ACK])
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.client_poll.addr,
+ nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+
+ wpa_supplicant_event(drv->ctx, EVENT_DRIVER_CLIENT_POLL_OK, &data);
+}
+
+
+static void nl80211_tdls_oper_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ union wpa_event_data data;
+
+ wpa_printf(MSG_DEBUG, "nl80211: TDLS operation event");
+
+ if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_TDLS_OPERATION])
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.tdls.peer, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+ switch (nla_get_u8(tb[NL80211_ATTR_TDLS_OPERATION])) {
+ case NL80211_TDLS_SETUP:
+ wpa_printf(MSG_DEBUG, "nl80211: TDLS setup request for peer "
+ MACSTR, MAC2STR(data.tdls.peer));
+ data.tdls.oper = TDLS_REQUEST_SETUP;
+ break;
+ case NL80211_TDLS_TEARDOWN:
+ wpa_printf(MSG_DEBUG, "nl80211: TDLS teardown request for peer "
+ MACSTR, MAC2STR(data.tdls.peer));
+ data.tdls.oper = TDLS_REQUEST_TEARDOWN;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "nl80211: Unsupported TDLS operatione "
+ "event");
+ return;
+ }
+ if (tb[NL80211_ATTR_REASON_CODE]) {
+ data.tdls.reason_code =
+ nla_get_u16(tb[NL80211_ATTR_REASON_CODE]);
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_TDLS, &data);
+}
+
+
+static void nl80211_stop_ap(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_UNAVAILABLE, NULL);
+}
+
+
+static void nl80211_connect_failed_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ union wpa_event_data data;
+ u32 reason;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Connect failed event");
+
+ if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_CONN_FAILED_REASON])
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.connect_failed_reason.addr,
+ nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+
+ reason = nla_get_u32(tb[NL80211_ATTR_CONN_FAILED_REASON]);
+ switch (reason) {
+ case NL80211_CONN_FAIL_MAX_CLIENTS:
+ wpa_printf(MSG_DEBUG, "nl80211: Max client reached");
+ data.connect_failed_reason.code = MAX_CLIENT_REACHED;
+ break;
+ case NL80211_CONN_FAIL_BLOCKED_CLIENT:
+ wpa_printf(MSG_DEBUG, "nl80211: Blocked client " MACSTR
+ " tried to connect",
+ MAC2STR(data.connect_failed_reason.addr));
+ data.connect_failed_reason.code = BLOCKED_CLIENT;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "nl8021l: Unknown connect failed reason "
+ "%u", reason);
+ return;
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_CONNECT_FAILED_REASON, &data);
+}
+
+
+static void nl80211_radar_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ union wpa_event_data data;
+ enum nl80211_radar_event event_type;
+
+ if (!tb[NL80211_ATTR_WIPHY_FREQ] || !tb[NL80211_ATTR_RADAR_EVENT])
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ data.dfs_event.freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
+ event_type = nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT]);
+
+ /* Check HT params */
+ if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
+ data.dfs_event.ht_enabled = 1;
+ data.dfs_event.chan_offset = 0;
+
+ switch (nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE])) {
+ case NL80211_CHAN_NO_HT:
+ data.dfs_event.ht_enabled = 0;
+ break;
+ case NL80211_CHAN_HT20:
+ break;
+ case NL80211_CHAN_HT40PLUS:
+ data.dfs_event.chan_offset = 1;
+ break;
+ case NL80211_CHAN_HT40MINUS:
+ data.dfs_event.chan_offset = -1;
+ break;
+ }
+ }
+
+ /* Get VHT params */
+ if (tb[NL80211_ATTR_CHANNEL_WIDTH])
+ data.dfs_event.chan_width =
+ convert2width(nla_get_u32(
+ tb[NL80211_ATTR_CHANNEL_WIDTH]));
+ if (tb[NL80211_ATTR_CENTER_FREQ1])
+ data.dfs_event.cf1 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
+ if (tb[NL80211_ATTR_CENTER_FREQ2])
+ data.dfs_event.cf2 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
+
+ wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz, ht: %d, offset: %d, width: %d, cf1: %dMHz, cf2: %dMHz",
+ data.dfs_event.freq, data.dfs_event.ht_enabled,
+ data.dfs_event.chan_offset, data.dfs_event.chan_width,
+ data.dfs_event.cf1, data.dfs_event.cf2);
+
+ switch (event_type) {
+ case NL80211_RADAR_DETECTED:
+ wpa_supplicant_event(drv->ctx, EVENT_DFS_RADAR_DETECTED, &data);
+ break;
+ case NL80211_RADAR_CAC_FINISHED:
+ wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_FINISHED, &data);
+ break;
+ case NL80211_RADAR_CAC_ABORTED:
+ wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_ABORTED, &data);
+ break;
+ case NL80211_RADAR_NOP_FINISHED:
+ wpa_supplicant_event(drv->ctx, EVENT_DFS_NOP_FINISHED, &data);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "nl80211: Unknown radar event %d "
+ "received", event_type);
+ break;
+ }
+}
+
+
+static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb,
+ int wds)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ union wpa_event_data event;
+
+ if (!tb[NL80211_ATTR_MAC])
+ return;
+
+ os_memset(&event, 0, sizeof(event));
+ event.rx_from_unknown.bssid = bss->addr;
+ event.rx_from_unknown.addr = nla_data(tb[NL80211_ATTR_MAC]);
+ event.rx_from_unknown.wds = wds;
+
+ wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
+}
+
+
+static void qca_nl80211_avoid_freq(struct wpa_driver_nl80211_data *drv,
+ const u8 *data, size_t len)
+{
+ u32 i, count;
+ union wpa_event_data event;
+ struct wpa_freq_range *range = NULL;
+ const struct qca_avoid_freq_list *freq_range;
+
+ freq_range = (const struct qca_avoid_freq_list *) data;
+ if (len < sizeof(freq_range->count))
+ return;
+
+ count = freq_range->count;
+ if (len < sizeof(freq_range->count) +
+ count * sizeof(struct qca_avoid_freq_range)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignored too short avoid frequency list (len=%u)",
+ (unsigned int) len);
+ return;
+ }
+
+ if (count > 0) {
+ range = os_calloc(count, sizeof(struct wpa_freq_range));
+ if (range == NULL)
+ return;
+ }
+
+ os_memset(&event, 0, sizeof(event));
+ for (i = 0; i < count; i++) {
+ unsigned int idx = event.freq_range.num;
+ range[idx].min = freq_range->range[i].start_freq;
+ range[idx].max = freq_range->range[i].end_freq;
+ wpa_printf(MSG_DEBUG, "nl80211: Avoid frequency range: %u-%u",
+ range[idx].min, range[idx].max);
+ if (range[idx].min > range[idx].max) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore invalid frequency range");
+ continue;
+ }
+ event.freq_range.num++;
+ }
+ event.freq_range.range = range;
+
+ wpa_supplicant_event(drv->ctx, EVENT_AVOID_FREQUENCIES, &event);
+
+ os_free(range);
+}
+
+
+static void qca_nl80211_acs_select_ch(struct wpa_driver_nl80211_data *drv,
+ const u8 *data, size_t len)
+{
+ struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ACS_MAX + 1];
+ union wpa_event_data event;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: ACS channel selection vendor event received");
+
+ if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ACS_MAX,
+ (struct nlattr *) data, len, NULL) ||
+ !tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL] ||
+ !tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL])
+ return;
+
+ os_memset(&event, 0, sizeof(event));
+ event.acs_selected_channels.pri_channel =
+ nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL]);
+ event.acs_selected_channels.sec_channel =
+ nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL]);
+
+ wpa_supplicant_event(drv->ctx, EVENT_ACS_CHANNEL_SELECTED, &event);
+}
+
+
+static void qca_nl80211_key_mgmt_auth(struct wpa_driver_nl80211_data *drv,
+ const u8 *data, size_t len)
+{
+ struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MAX + 1];
+ u8 *bssid;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Key management roam+auth vendor event received");
+
+ if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MAX,
+ (struct nlattr *) data, len, NULL) ||
+ !tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID] ||
+ nla_len(tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID]) != ETH_ALEN ||
+ !tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE] ||
+ !tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE] ||
+ !tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED])
+ return;
+
+ bssid = nla_data(tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID]);
+ wpa_printf(MSG_DEBUG, " * roam BSSID " MACSTR, MAC2STR(bssid));
+
+ mlme_event_connect(drv, NL80211_CMD_ROAM, NULL,
+ tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID],
+ tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE],
+ tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE],
+ tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED],
+ tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_KEY_REPLAY_CTR],
+ tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KCK],
+ tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KEK]);
+}
+
+
+static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv,
+ u32 subcmd, u8 *data, size_t len)
+{
+ switch (subcmd) {
+ case QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY:
+ qca_nl80211_avoid_freq(drv, data, len);
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH:
+ qca_nl80211_key_mgmt_auth(drv, data, len);
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_DO_ACS:
+ qca_nl80211_acs_select_ch(drv, data, len);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignore unsupported QCA vendor event %u",
+ subcmd);
+ break;
+ }
+}
+
+
+static void nl80211_vendor_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr **tb)
+{
+ u32 vendor_id, subcmd, wiphy = 0;
+ int wiphy_idx;
+ u8 *data = NULL;
+ size_t len = 0;
+
+ if (!tb[NL80211_ATTR_VENDOR_ID] ||
+ !tb[NL80211_ATTR_VENDOR_SUBCMD])
+ return;
+
+ vendor_id = nla_get_u32(tb[NL80211_ATTR_VENDOR_ID]);
+ subcmd = nla_get_u32(tb[NL80211_ATTR_VENDOR_SUBCMD]);
+
+ if (tb[NL80211_ATTR_WIPHY])
+ wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
+
+ wpa_printf(MSG_DEBUG, "nl80211: Vendor event: wiphy=%u vendor_id=0x%x subcmd=%u",
+ wiphy, vendor_id, subcmd);
+
+ if (tb[NL80211_ATTR_VENDOR_DATA]) {
+ data = nla_data(tb[NL80211_ATTR_VENDOR_DATA]);
+ len = nla_len(tb[NL80211_ATTR_VENDOR_DATA]);
+ wpa_hexdump(MSG_MSGDUMP, "nl80211: Vendor data", data, len);
+ }
+
+ wiphy_idx = nl80211_get_wiphy_index(drv->first_bss);
+ if (wiphy_idx >= 0 && wiphy_idx != (int) wiphy) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore vendor event for foreign wiphy %u (own: %d)",
+ wiphy, wiphy_idx);
+ return;
+ }
+
+ switch (vendor_id) {
+ case OUI_QCA:
+ nl80211_vendor_event_qca(drv, subcmd, data, len);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore unsupported vendor event");
+ break;
+ }
+}
+
+
+static void nl80211_reg_change_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *tb[])
+{
+ union wpa_event_data data;
+ enum nl80211_reg_initiator init;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Regulatory domain change");
+
+ if (tb[NL80211_ATTR_REG_INITIATOR] == NULL)
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ init = nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR]);
+ wpa_printf(MSG_DEBUG, " * initiator=%d", init);
+ switch (init) {
+ case NL80211_REGDOM_SET_BY_CORE:
+ data.channel_list_changed.initiator = REGDOM_SET_BY_CORE;
+ break;
+ case NL80211_REGDOM_SET_BY_USER:
+ data.channel_list_changed.initiator = REGDOM_SET_BY_USER;
+ break;
+ case NL80211_REGDOM_SET_BY_DRIVER:
+ data.channel_list_changed.initiator = REGDOM_SET_BY_DRIVER;
+ break;
+ case NL80211_REGDOM_SET_BY_COUNTRY_IE:
+ data.channel_list_changed.initiator = REGDOM_SET_BY_COUNTRY_IE;
+ break;
+ }
+
+ if (tb[NL80211_ATTR_REG_TYPE]) {
+ enum nl80211_reg_type type;
+ type = nla_get_u8(tb[NL80211_ATTR_REG_TYPE]);
+ wpa_printf(MSG_DEBUG, " * type=%d", type);
+ switch (type) {
+ case NL80211_REGDOM_TYPE_COUNTRY:
+ data.channel_list_changed.type = REGDOM_TYPE_COUNTRY;
+ break;
+ case NL80211_REGDOM_TYPE_WORLD:
+ data.channel_list_changed.type = REGDOM_TYPE_WORLD;
+ break;
+ case NL80211_REGDOM_TYPE_CUSTOM_WORLD:
+ data.channel_list_changed.type =
+ REGDOM_TYPE_CUSTOM_WORLD;
+ break;
+ case NL80211_REGDOM_TYPE_INTERSECTION:
+ data.channel_list_changed.type =
+ REGDOM_TYPE_INTERSECTION;
+ break;
+ }
+ }
+
+ if (tb[NL80211_ATTR_REG_ALPHA2]) {
+ os_strlcpy(data.channel_list_changed.alpha2,
+ nla_get_string(tb[NL80211_ATTR_REG_ALPHA2]),
+ sizeof(data.channel_list_changed.alpha2));
+ wpa_printf(MSG_DEBUG, " * alpha2=%s",
+ data.channel_list_changed.alpha2);
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED, &data);
+}
+
+
+static void do_process_drv_event(struct i802_bss *bss, int cmd,
+ struct nlattr **tb)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ union wpa_event_data data;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s",
+ cmd, nl80211_command_to_string(cmd), bss->ifname);
+
+ if (cmd == NL80211_CMD_ROAM &&
+ (drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD)) {
+ /*
+ * Device will use roam+auth vendor event to indicate
+ * roaming, so ignore the regular roam event.
+ */
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignore roam event (cmd=%d), device will use vendor event roam+auth",
+ cmd);
+ return;
+ }
+
+ if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
+ (cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
+ cmd == NL80211_CMD_SCAN_ABORTED)) {
+ wpa_driver_nl80211_set_mode(drv->first_bss,
+ drv->ap_scan_as_station);
+ drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
+ }
+
+ switch (cmd) {
+ case NL80211_CMD_TRIGGER_SCAN:
+ wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan trigger");
+ drv->scan_state = SCAN_STARTED;
+ if (drv->scan_for_auth) {
+ /*
+ * Cannot indicate EVENT_SCAN_STARTED here since we skip
+ * EVENT_SCAN_RESULTS in scan_for_auth case and the
+ * upper layer implementation could get confused about
+ * scanning state.
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Do not indicate scan-start event due to internal scan_for_auth");
+ break;
+ }
+ wpa_supplicant_event(drv->ctx, EVENT_SCAN_STARTED, NULL);
+ break;
+ case NL80211_CMD_START_SCHED_SCAN:
+ wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan started");
+ drv->scan_state = SCHED_SCAN_STARTED;
+ break;
+ case NL80211_CMD_SCHED_SCAN_STOPPED:
+ wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan stopped");
+ drv->scan_state = SCHED_SCAN_STOPPED;
+ wpa_supplicant_event(drv->ctx, EVENT_SCHED_SCAN_STOPPED, NULL);
+ break;
+ case NL80211_CMD_NEW_SCAN_RESULTS:
+ wpa_dbg(drv->ctx, MSG_DEBUG,
+ "nl80211: New scan results available");
+ drv->scan_state = SCAN_COMPLETED;
+ drv->scan_complete_events = 1;
+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
+ drv->ctx);
+ send_scan_event(drv, 0, tb);
+ break;
+ case NL80211_CMD_SCHED_SCAN_RESULTS:
+ wpa_dbg(drv->ctx, MSG_DEBUG,
+ "nl80211: New sched scan results available");
+ drv->scan_state = SCHED_SCAN_RESULTS;
+ send_scan_event(drv, 0, tb);
+ break;
+ case NL80211_CMD_SCAN_ABORTED:
+ wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan aborted");
+ drv->scan_state = SCAN_ABORTED;
+ /*
+ * Need to indicate that scan results are available in order
+ * not to make wpa_supplicant stop its scanning.
+ */
+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
+ drv->ctx);
+ send_scan_event(drv, 1, tb);
+ break;
+ case NL80211_CMD_AUTHENTICATE:
+ case NL80211_CMD_ASSOCIATE:
+ case NL80211_CMD_DEAUTHENTICATE:
+ case NL80211_CMD_DISASSOCIATE:
+ case NL80211_CMD_FRAME_TX_STATUS:
+ case NL80211_CMD_UNPROT_DEAUTHENTICATE:
+ case NL80211_CMD_UNPROT_DISASSOCIATE:
+ mlme_event(bss, cmd, tb[NL80211_ATTR_FRAME],
+ tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
+ tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
+ tb[NL80211_ATTR_COOKIE],
+ tb[NL80211_ATTR_RX_SIGNAL_DBM],
+ tb[NL80211_ATTR_STA_WME]);
+ break;
+ case NL80211_CMD_CONNECT:
+ case NL80211_CMD_ROAM:
+ mlme_event_connect(drv, cmd,
+ tb[NL80211_ATTR_STATUS_CODE],
+ tb[NL80211_ATTR_MAC],
+ tb[NL80211_ATTR_REQ_IE],
+ tb[NL80211_ATTR_RESP_IE],
+ NULL, NULL, NULL, NULL);
+ break;
+ case NL80211_CMD_CH_SWITCH_NOTIFY:
+ mlme_event_ch_switch(drv,
+ tb[NL80211_ATTR_IFINDEX],
+ tb[NL80211_ATTR_WIPHY_FREQ],
+ tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE],
+ tb[NL80211_ATTR_CHANNEL_WIDTH],
+ tb[NL80211_ATTR_CENTER_FREQ1],
+ tb[NL80211_ATTR_CENTER_FREQ2]);
+ break;
+ case NL80211_CMD_DISCONNECT:
+ mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
+ tb[NL80211_ATTR_MAC],
+ tb[NL80211_ATTR_DISCONNECTED_BY_AP]);
+ break;
+ case NL80211_CMD_MICHAEL_MIC_FAILURE:
+ mlme_event_michael_mic_failure(bss, tb);
+ break;
+ case NL80211_CMD_JOIN_IBSS:
+ mlme_event_join_ibss(drv, tb);
+ break;
+ case NL80211_CMD_REMAIN_ON_CHANNEL:
+ mlme_event_remain_on_channel(drv, 0, tb);
+ break;
+ case NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL:
+ mlme_event_remain_on_channel(drv, 1, tb);
+ break;
+ case NL80211_CMD_NOTIFY_CQM:
+ nl80211_cqm_event(drv, tb);
+ break;
+ case NL80211_CMD_REG_CHANGE:
+ nl80211_reg_change_event(drv, tb);
+ break;
+ case NL80211_CMD_REG_BEACON_HINT:
+ wpa_printf(MSG_DEBUG, "nl80211: Regulatory beacon hint");
+ os_memset(&data, 0, sizeof(data));
+ data.channel_list_changed.initiator = REGDOM_BEACON_HINT;
+ wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED,
+ &data);
+ break;
+ case NL80211_CMD_NEW_STATION:
+ nl80211_new_station_event(drv, bss, tb);
+ break;
+ case NL80211_CMD_DEL_STATION:
+ nl80211_del_station_event(drv, tb);
+ break;
+ case NL80211_CMD_SET_REKEY_OFFLOAD:
+ nl80211_rekey_offload_event(drv, tb);
+ break;
+ case NL80211_CMD_PMKSA_CANDIDATE:
+ nl80211_pmksa_candidate_event(drv, tb);
+ break;
+ case NL80211_CMD_PROBE_CLIENT:
+ nl80211_client_probe_event(drv, tb);
+ break;
+ case NL80211_CMD_TDLS_OPER:
+ nl80211_tdls_oper_event(drv, tb);
+ break;
+ case NL80211_CMD_CONN_FAILED:
+ nl80211_connect_failed_event(drv, tb);
+ break;
+ case NL80211_CMD_FT_EVENT:
+ mlme_event_ft_event(drv, tb);
+ break;
+ case NL80211_CMD_RADAR_DETECT:
+ nl80211_radar_event(drv, tb);
+ break;
+ case NL80211_CMD_STOP_AP:
+ nl80211_stop_ap(drv, tb);
+ break;
+ case NL80211_CMD_VENDOR:
+ nl80211_vendor_event(drv, tb);
+ break;
+ case NL80211_CMD_NEW_PEER_CANDIDATE:
+ nl80211_new_peer_candidate(drv, tb);
+ break;
+ default:
+ wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
+ "(cmd=%d)", cmd);
+ break;
+ }
+}
+
+
+int process_global_event(struct nl_msg *msg, void *arg)
+{
+ struct nl80211_global *global = arg;
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct wpa_driver_nl80211_data *drv, *tmp;
+ int ifidx = -1;
+ struct i802_bss *bss;
+ u64 wdev_id = 0;
+ int wdev_id_set = 0;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (tb[NL80211_ATTR_IFINDEX])
+ ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
+ else if (tb[NL80211_ATTR_WDEV]) {
+ wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
+ wdev_id_set = 1;
+ }
+
+ dl_list_for_each_safe(drv, tmp, &global->interfaces,
+ struct wpa_driver_nl80211_data, list) {
+ for (bss = drv->first_bss; bss; bss = bss->next) {
+ if ((ifidx == -1 && !wdev_id_set) ||
+ ifidx == bss->ifindex ||
+ (wdev_id_set && bss->wdev_id_set &&
+ wdev_id == bss->wdev_id)) {
+ do_process_drv_event(bss, gnlh->cmd, tb);
+ return NL_SKIP;
+ }
+ }
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignored event (cmd=%d) for foreign interface (ifindex %d wdev 0x%llx)",
+ gnlh->cmd, ifidx, (long long unsigned int) wdev_id);
+ }
+
+ return NL_SKIP;
+}
+
+
+int process_bss_event(struct nl_msg *msg, void *arg)
+{
+ struct i802_bss *bss = arg;
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ wpa_printf(MSG_DEBUG, "nl80211: BSS Event %d (%s) received for %s",
+ gnlh->cmd, nl80211_command_to_string(gnlh->cmd),
+ bss->ifname);
+
+ switch (gnlh->cmd) {
+ case NL80211_CMD_FRAME:
+ case NL80211_CMD_FRAME_TX_STATUS:
+ mlme_event(bss, gnlh->cmd, tb[NL80211_ATTR_FRAME],
+ tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
+ tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
+ tb[NL80211_ATTR_COOKIE],
+ tb[NL80211_ATTR_RX_SIGNAL_DBM],
+ tb[NL80211_ATTR_STA_WME]);
+ break;
+ case NL80211_CMD_UNEXPECTED_FRAME:
+ nl80211_spurious_frame(bss, tb, 0);
+ break;
+ case NL80211_CMD_UNEXPECTED_4ADDR_FRAME:
+ nl80211_spurious_frame(bss, tb, 1);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
+ "(cmd=%d)", gnlh->cmd);
+ break;
+ }
+
+ return NL_SKIP;
+}
diff --git a/src/drivers/driver_nl80211_monitor.c b/src/drivers/driver_nl80211_monitor.c
new file mode 100644
index 0000000..45385da
--- /dev/null
+++ b/src/drivers/driver_nl80211_monitor.c
@@ -0,0 +1,491 @@
+/*
+ * Driver interaction with Linux nl80211/cfg80211 - AP monitor interface
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2004, Instant802 Networks, Inc.
+ * Copyright (c) 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "linux_ioctl.h"
+#include "radiotap_iter.h"
+#include "driver_nl80211.h"
+
+
+static void handle_tx_callback(void *ctx, u8 *buf, size_t len, int ok)
+{
+ struct ieee80211_hdr *hdr;
+ u16 fc;
+ union wpa_event_data event;
+
+ hdr = (struct ieee80211_hdr *) buf;
+ fc = le_to_host16(hdr->frame_control);
+
+ os_memset(&event, 0, sizeof(event));
+ event.tx_status.type = WLAN_FC_GET_TYPE(fc);
+ event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
+ event.tx_status.dst = hdr->addr1;
+ event.tx_status.data = buf;
+ event.tx_status.data_len = len;
+ event.tx_status.ack = ok;
+ wpa_supplicant_event(ctx, EVENT_TX_STATUS, &event);
+}
+
+
+static void from_unknown_sta(struct wpa_driver_nl80211_data *drv,
+ u8 *buf, size_t len)
+{
+ struct ieee80211_hdr *hdr = (void *)buf;
+ u16 fc;
+ union wpa_event_data event;
+
+ if (len < sizeof(*hdr))
+ return;
+
+ fc = le_to_host16(hdr->frame_control);
+
+ os_memset(&event, 0, sizeof(event));
+ event.rx_from_unknown.bssid = get_hdr_bssid(hdr, len);
+ event.rx_from_unknown.addr = hdr->addr2;
+ event.rx_from_unknown.wds = (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) ==
+ (WLAN_FC_FROMDS | WLAN_FC_TODS);
+ wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
+}
+
+
+static void handle_frame(struct wpa_driver_nl80211_data *drv,
+ u8 *buf, size_t len, int datarate, int ssi_signal)
+{
+ struct ieee80211_hdr *hdr;
+ u16 fc;
+ union wpa_event_data event;
+
+ hdr = (struct ieee80211_hdr *) buf;
+ fc = le_to_host16(hdr->frame_control);
+
+ switch (WLAN_FC_GET_TYPE(fc)) {
+ case WLAN_FC_TYPE_MGMT:
+ os_memset(&event, 0, sizeof(event));
+ event.rx_mgmt.frame = buf;
+ event.rx_mgmt.frame_len = len;
+ event.rx_mgmt.datarate = datarate;
+ event.rx_mgmt.ssi_signal = ssi_signal;
+ wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
+ break;
+ case WLAN_FC_TYPE_CTRL:
+ /* can only get here with PS-Poll frames */
+ wpa_printf(MSG_DEBUG, "CTRL");
+ from_unknown_sta(drv, buf, len);
+ break;
+ case WLAN_FC_TYPE_DATA:
+ from_unknown_sta(drv, buf, len);
+ break;
+ }
+}
+
+
+static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct wpa_driver_nl80211_data *drv = eloop_ctx;
+ int len;
+ unsigned char buf[3000];
+ struct ieee80211_radiotap_iterator iter;
+ int ret;
+ int datarate = 0, ssi_signal = 0;
+ int injected = 0, failed = 0, rxflags = 0;
+
+ len = recv(sock, buf, sizeof(buf), 0);
+ if (len < 0) {
+ wpa_printf(MSG_ERROR, "nl80211: Monitor socket recv failed: %s",
+ strerror(errno));
+ return;
+ }
+
+ if (ieee80211_radiotap_iterator_init(&iter, (void *) buf, len, NULL)) {
+ wpa_printf(MSG_INFO, "nl80211: received invalid radiotap frame");
+ return;
+ }
+
+ while (1) {
+ ret = ieee80211_radiotap_iterator_next(&iter);
+ if (ret == -ENOENT)
+ break;
+ if (ret) {
+ wpa_printf(MSG_INFO, "nl80211: received invalid radiotap frame (%d)",
+ ret);
+ return;
+ }
+ switch (iter.this_arg_index) {
+ case IEEE80211_RADIOTAP_FLAGS:
+ if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS)
+ len -= 4;
+ break;
+ case IEEE80211_RADIOTAP_RX_FLAGS:
+ rxflags = 1;
+ break;
+ case IEEE80211_RADIOTAP_TX_FLAGS:
+ injected = 1;
+ failed = le_to_host16((*(uint16_t *) iter.this_arg)) &
+ IEEE80211_RADIOTAP_F_TX_FAIL;
+ break;
+ case IEEE80211_RADIOTAP_DATA_RETRIES:
+ break;
+ case IEEE80211_RADIOTAP_CHANNEL:
+ /* TODO: convert from freq/flags to channel number */
+ break;
+ case IEEE80211_RADIOTAP_RATE:
+ datarate = *iter.this_arg * 5;
+ break;
+ case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:
+ ssi_signal = (s8) *iter.this_arg;
+ break;
+ }
+ }
+
+ if (rxflags && injected)
+ return;
+
+ if (!injected)
+ handle_frame(drv, buf + iter._max_length,
+ len - iter._max_length, datarate, ssi_signal);
+ else
+ handle_tx_callback(drv->ctx, buf + iter._max_length,
+ len - iter._max_length, !failed);
+}
+
+
+/*
+ * we post-process the filter code later and rewrite
+ * this to the offset to the last instruction
+ */
+#define PASS 0xFF
+#define FAIL 0xFE
+
+static struct sock_filter msock_filter_insns[] = {
+ /*
+ * do a little-endian load of the radiotap length field
+ */
+ /* load lower byte into A */
+ BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 2),
+ /* put it into X (== index register) */
+ BPF_STMT(BPF_MISC| BPF_TAX, 0),
+ /* load upper byte into A */
+ BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 3),
+ /* left-shift it by 8 */
+ BPF_STMT(BPF_ALU | BPF_LSH | BPF_K, 8),
+ /* or with X */
+ BPF_STMT(BPF_ALU | BPF_OR | BPF_X, 0),
+ /* put result into X */
+ BPF_STMT(BPF_MISC| BPF_TAX, 0),
+
+ /*
+ * Allow management frames through, this also gives us those
+ * management frames that we sent ourselves with status
+ */
+ /* load the lower byte of the IEEE 802.11 frame control field */
+ BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0),
+ /* mask off frame type and version */
+ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0xF),
+ /* accept frame if it's both 0, fall through otherwise */
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, PASS, 0),
+
+ /*
+ * TODO: add a bit to radiotap RX flags that indicates
+ * that the sending station is not associated, then
+ * add a filter here that filters on our DA and that flag
+ * to allow us to deauth frames to that bad station.
+ *
+ * For now allow all To DS data frames through.
+ */
+ /* load the IEEE 802.11 frame control field */
+ BPF_STMT(BPF_LD | BPF_H | BPF_IND, 0),
+ /* mask off frame type, version and DS status */
+ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0F03),
+ /* accept frame if version 0, type 2 and To DS, fall through otherwise
+ */
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0801, PASS, 0),
+
+#if 0
+ /*
+ * drop non-data frames
+ */
+ /* load the lower byte of the frame control field */
+ BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0),
+ /* mask off QoS bit */
+ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0c),
+ /* drop non-data frames */
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 8, 0, FAIL),
+#endif
+ /* load the upper byte of the frame control field */
+ BPF_STMT(BPF_LD | BPF_B | BPF_IND, 1),
+ /* mask off toDS/fromDS */
+ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x03),
+ /* accept WDS frames */
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 3, PASS, 0),
+
+ /*
+ * add header length to index
+ */
+ /* load the lower byte of the frame control field */
+ BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0),
+ /* mask off QoS bit */
+ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x80),
+ /* right shift it by 6 to give 0 or 2 */
+ BPF_STMT(BPF_ALU | BPF_RSH | BPF_K, 6),
+ /* add data frame header length */
+ BPF_STMT(BPF_ALU | BPF_ADD | BPF_K, 24),
+ /* add index, was start of 802.11 header */
+ BPF_STMT(BPF_ALU | BPF_ADD | BPF_X, 0),
+ /* move to index, now start of LL header */
+ BPF_STMT(BPF_MISC | BPF_TAX, 0),
+
+ /*
+ * Accept empty data frames, we use those for
+ * polling activity.
+ */
+ BPF_STMT(BPF_LD | BPF_W | BPF_LEN, 0),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_X, 0, PASS, 0),
+
+ /*
+ * Accept EAPOL frames
+ */
+ BPF_STMT(BPF_LD | BPF_W | BPF_IND, 0),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA0300, 0, FAIL),
+ BPF_STMT(BPF_LD | BPF_W | BPF_IND, 4),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0000888E, PASS, FAIL),
+
+ /* keep these last two statements or change the code below */
+ /* return 0 == "DROP" */
+ BPF_STMT(BPF_RET | BPF_K, 0),
+ /* return ~0 == "keep all" */
+ BPF_STMT(BPF_RET | BPF_K, ~0),
+};
+
+static struct sock_fprog msock_filter = {
+ .len = ARRAY_SIZE(msock_filter_insns),
+ .filter = msock_filter_insns,
+};
+
+
+static int add_monitor_filter(int s)
+{
+ int idx;
+
+ /* rewrite all PASS/FAIL jump offsets */
+ for (idx = 0; idx < msock_filter.len; idx++) {
+ struct sock_filter *insn = &msock_filter_insns[idx];
+
+ if (BPF_CLASS(insn->code) == BPF_JMP) {
+ if (insn->code == (BPF_JMP|BPF_JA)) {
+ if (insn->k == PASS)
+ insn->k = msock_filter.len - idx - 2;
+ else if (insn->k == FAIL)
+ insn->k = msock_filter.len - idx - 3;
+ }
+
+ if (insn->jt == PASS)
+ insn->jt = msock_filter.len - idx - 2;
+ else if (insn->jt == FAIL)
+ insn->jt = msock_filter.len - idx - 3;
+
+ if (insn->jf == PASS)
+ insn->jf = msock_filter.len - idx - 2;
+ else if (insn->jf == FAIL)
+ insn->jf = msock_filter.len - idx - 3;
+ }
+ }
+
+ if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER,
+ &msock_filter, sizeof(msock_filter))) {
+ wpa_printf(MSG_ERROR, "nl80211: setsockopt(SO_ATTACH_FILTER) failed: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void nl80211_remove_monitor_interface(struct wpa_driver_nl80211_data *drv)
+{
+ if (drv->monitor_refcount > 0)
+ drv->monitor_refcount--;
+ wpa_printf(MSG_DEBUG, "nl80211: Remove monitor interface: refcount=%d",
+ drv->monitor_refcount);
+ if (drv->monitor_refcount > 0)
+ return;
+
+ if (drv->monitor_ifidx >= 0) {
+ nl80211_remove_iface(drv, drv->monitor_ifidx);
+ drv->monitor_ifidx = -1;
+ }
+ if (drv->monitor_sock >= 0) {
+ eloop_unregister_read_sock(drv->monitor_sock);
+ close(drv->monitor_sock);
+ drv->monitor_sock = -1;
+ }
+}
+
+
+int nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
+{
+ char buf[IFNAMSIZ];
+ struct sockaddr_ll ll;
+ int optval;
+ socklen_t optlen;
+
+ if (drv->monitor_ifidx >= 0) {
+ drv->monitor_refcount++;
+ wpa_printf(MSG_DEBUG, "nl80211: Re-use existing monitor interface: refcount=%d",
+ drv->monitor_refcount);
+ return 0;
+ }
+
+ if (os_strncmp(drv->first_bss->ifname, "p2p-", 4) == 0) {
+ /*
+ * P2P interface name is of the format p2p-%s-%d. For monitor
+ * interface name corresponding to P2P GO, replace "p2p-" with
+ * "mon-" to retain the same interface name length and to
+ * indicate that it is a monitor interface.
+ */
+ snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss->ifname + 4);
+ } else {
+ /* Non-P2P interface with AP functionality. */
+ snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss->ifname);
+ }
+
+ buf[IFNAMSIZ - 1] = '\0';
+
+ drv->monitor_ifidx =
+ nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
+ 0, NULL, NULL, 0);
+
+ if (drv->monitor_ifidx == -EOPNOTSUPP) {
+ /*
+ * This is backward compatibility for a few versions of
+ * the kernel only that didn't advertise the right
+ * attributes for the only driver that then supported
+ * AP mode w/o monitor -- ath6kl.
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Driver does not support "
+ "monitor interface type - try to run without it");
+ drv->device_ap_sme = 1;
+ }
+
+ if (drv->monitor_ifidx < 0)
+ return -1;
+
+ if (linux_set_iface_flags(drv->global->ioctl_sock, buf, 1))
+ goto error;
+
+ memset(&ll, 0, sizeof(ll));
+ ll.sll_family = AF_PACKET;
+ ll.sll_ifindex = drv->monitor_ifidx;
+ drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+ if (drv->monitor_sock < 0) {
+ wpa_printf(MSG_ERROR, "nl80211: socket[PF_PACKET,SOCK_RAW] failed: %s",
+ strerror(errno));
+ goto error;
+ }
+
+ if (add_monitor_filter(drv->monitor_sock)) {
+ wpa_printf(MSG_INFO, "Failed to set socket filter for monitor "
+ "interface; do filtering in user space");
+ /* This works, but will cost in performance. */
+ }
+
+ if (bind(drv->monitor_sock, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
+ wpa_printf(MSG_ERROR, "nl80211: monitor socket bind failed: %s",
+ strerror(errno));
+ goto error;
+ }
+
+ optlen = sizeof(optval);
+ optval = 20;
+ if (setsockopt
+ (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to set socket priority: %s",
+ strerror(errno));
+ goto error;
+ }
+
+ if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read,
+ drv, NULL)) {
+ wpa_printf(MSG_INFO, "nl80211: Could not register monitor read socket");
+ goto error;
+ }
+
+ drv->monitor_refcount++;
+ return 0;
+ error:
+ nl80211_remove_monitor_interface(drv);
+ return -1;
+}
+
+
+int nl80211_send_monitor(struct wpa_driver_nl80211_data *drv,
+ const void *data, size_t len,
+ int encrypt, int noack)
+{
+ __u8 rtap_hdr[] = {
+ 0x00, 0x00, /* radiotap version */
+ 0x0e, 0x00, /* radiotap length */
+ 0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */
+ IEEE80211_RADIOTAP_F_FRAG, /* F_FRAG (fragment if required) */
+ 0x00, /* padding */
+ 0x00, 0x00, /* RX and TX flags to indicate that */
+ 0x00, 0x00, /* this is the injected frame directly */
+ };
+ struct iovec iov[2] = {
+ {
+ .iov_base = &rtap_hdr,
+ .iov_len = sizeof(rtap_hdr),
+ },
+ {
+ .iov_base = (void *) data,
+ .iov_len = len,
+ }
+ };
+ struct msghdr msg = {
+ .msg_name = NULL,
+ .msg_namelen = 0,
+ .msg_iov = iov,
+ .msg_iovlen = 2,
+ .msg_control = NULL,
+ .msg_controllen = 0,
+ .msg_flags = 0,
+ };
+ int res;
+ u16 txflags = 0;
+
+ if (encrypt)
+ rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP;
+
+ if (drv->monitor_sock < 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: No monitor socket available "
+ "for %s", __func__);
+ return -1;
+ }
+
+ if (noack)
+ txflags |= IEEE80211_RADIOTAP_F_TX_NOACK;
+ WPA_PUT_LE16(&rtap_hdr[12], txflags);
+
+ res = sendmsg(drv->monitor_sock, &msg, 0);
+ if (res < 0) {
+ wpa_printf(MSG_INFO, "nl80211: sendmsg: %s", strerror(errno));
+ return -1;
+ }
+ return 0;
+}
diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c
new file mode 100644
index 0000000..3911f48
--- /dev/null
+++ b/src/drivers/driver_nl80211_scan.c
@@ -0,0 +1,775 @@
+/*
+ * Driver interaction with Linux nl80211/cfg80211 - Scanning
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <netlink/genl/genl.h>
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "driver_nl80211.h"
+
+
+static int get_noise_for_scan_results(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
+ static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
+ [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
+ [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
+ };
+ struct wpa_scan_results *scan_results = arg;
+ struct wpa_scan_res *scan_res;
+ size_t i;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb[NL80211_ATTR_SURVEY_INFO]) {
+ wpa_printf(MSG_DEBUG, "nl80211: Survey data missing");
+ return NL_SKIP;
+ }
+
+ if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
+ tb[NL80211_ATTR_SURVEY_INFO],
+ survey_policy)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to parse nested "
+ "attributes");
+ return NL_SKIP;
+ }
+
+ if (!sinfo[NL80211_SURVEY_INFO_NOISE])
+ return NL_SKIP;
+
+ if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
+ return NL_SKIP;
+
+ for (i = 0; i < scan_results->num; ++i) {
+ scan_res = scan_results->res[i];
+ if (!scan_res)
+ continue;
+ if ((int) nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
+ scan_res->freq)
+ continue;
+ if (!(scan_res->flags & WPA_SCAN_NOISE_INVALID))
+ continue;
+ scan_res->noise = (s8)
+ nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
+ scan_res->flags &= ~WPA_SCAN_NOISE_INVALID;
+ }
+
+ return NL_SKIP;
+}
+
+
+static int nl80211_get_noise_for_scan_results(
+ struct wpa_driver_nl80211_data *drv,
+ struct wpa_scan_results *scan_res)
+{
+ struct nl_msg *msg;
+
+ msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
+ return send_and_recv_msgs(drv, msg, get_noise_for_scan_results,
+ scan_res);
+}
+
+
+/**
+ * wpa_driver_nl80211_scan_timeout - Scan timeout to report scan completion
+ * @eloop_ctx: Driver private data
+ * @timeout_ctx: ctx argument given to wpa_driver_nl80211_init()
+ *
+ * This function can be used as registered timeout when starting a scan to
+ * generate a scan completed event if the driver does not report this.
+ */
+void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_driver_nl80211_data *drv = eloop_ctx;
+ if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED) {
+ wpa_driver_nl80211_set_mode(drv->first_bss,
+ drv->ap_scan_as_station);
+ drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
+ }
+ wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
+ wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
+}
+
+
+static struct nl_msg *
+nl80211_scan_common(struct i802_bss *bss, u8 cmd,
+ struct wpa_driver_scan_params *params)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ size_t i;
+ u32 scan_flags = 0;
+
+ msg = nl80211_cmd_msg(bss, 0, cmd);
+ if (!msg)
+ return NULL;
+
+ if (params->num_ssids) {
+ struct nlattr *ssids;
+
+ ssids = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS);
+ if (ssids == NULL)
+ goto fail;
+ for (i = 0; i < params->num_ssids; i++) {
+ wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",
+ params->ssids[i].ssid,
+ params->ssids[i].ssid_len);
+ if (nla_put(msg, i + 1, params->ssids[i].ssid_len,
+ params->ssids[i].ssid))
+ goto fail;
+ }
+ nla_nest_end(msg, ssids);
+ }
+
+ if (params->extra_ies) {
+ wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs",
+ params->extra_ies, params->extra_ies_len);
+ if (nla_put(msg, NL80211_ATTR_IE, params->extra_ies_len,
+ params->extra_ies))
+ goto fail;
+ }
+
+ if (params->freqs) {
+ struct nlattr *freqs;
+ freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
+ if (freqs == NULL)
+ goto fail;
+ for (i = 0; params->freqs[i]; i++) {
+ wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
+ "MHz", params->freqs[i]);
+ if (nla_put_u32(msg, i + 1, params->freqs[i]))
+ goto fail;
+ }
+ nla_nest_end(msg, freqs);
+ }
+
+ os_free(drv->filter_ssids);
+ drv->filter_ssids = params->filter_ssids;
+ params->filter_ssids = NULL;
+ drv->num_filter_ssids = params->num_filter_ssids;
+
+ if (params->only_new_results) {
+ wpa_printf(MSG_DEBUG, "nl80211: Add NL80211_SCAN_FLAG_FLUSH");
+ scan_flags |= NL80211_SCAN_FLAG_FLUSH;
+ }
+
+ if (params->low_priority && drv->have_low_prio_scan) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Add NL80211_SCAN_FLAG_LOW_PRIORITY");
+ scan_flags |= NL80211_SCAN_FLAG_LOW_PRIORITY;
+ }
+
+ if (params->mac_addr_rand) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Add NL80211_SCAN_FLAG_RANDOM_ADDR");
+ scan_flags |= NL80211_SCAN_FLAG_RANDOM_ADDR;
+
+ if (params->mac_addr) {
+ wpa_printf(MSG_DEBUG, "nl80211: MAC address: " MACSTR,
+ MAC2STR(params->mac_addr));
+ if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN,
+ params->mac_addr))
+ goto fail;
+ }
+
+ if (params->mac_addr_mask) {
+ wpa_printf(MSG_DEBUG, "nl80211: MAC address mask: "
+ MACSTR, MAC2STR(params->mac_addr_mask));
+ if (nla_put(msg, NL80211_ATTR_MAC_MASK, ETH_ALEN,
+ params->mac_addr_mask))
+ goto fail;
+ }
+ }
+
+ if (scan_flags &&
+ nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, scan_flags))
+ goto fail;
+
+ return msg;
+
+fail:
+ nlmsg_free(msg);
+ return NULL;
+}
+
+
+/**
+ * wpa_driver_nl80211_scan - Request the driver to initiate scan
+ * @bss: Pointer to private driver data from wpa_driver_nl80211_init()
+ * @params: Scan parameters
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_driver_nl80211_scan(struct i802_bss *bss,
+ struct wpa_driver_scan_params *params)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int ret = -1, timeout;
+ struct nl_msg *msg = NULL;
+
+ wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: scan request");
+ drv->scan_for_auth = 0;
+
+ msg = nl80211_scan_common(bss, NL80211_CMD_TRIGGER_SCAN, params);
+ if (!msg)
+ return -1;
+
+ if (params->p2p_probe) {
+ struct nlattr *rates;
+
+ wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates");
+
+ rates = nla_nest_start(msg, NL80211_ATTR_SCAN_SUPP_RATES);
+ if (rates == NULL)
+ goto fail;
+
+ /*
+ * Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates
+ * by masking out everything else apart from the OFDM rates 6,
+ * 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz
+ * rates are left enabled.
+ */
+ if (nla_put(msg, NL80211_BAND_2GHZ, 8,
+ "\x0c\x12\x18\x24\x30\x48\x60\x6c"))
+ goto fail;
+ nla_nest_end(msg, rates);
+
+ if (nla_put_flag(msg, NL80211_ATTR_TX_NO_CCK_RATE))
+ goto fail;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
+ "(%s)", ret, strerror(-ret));
+ if (drv->hostapd && is_ap_interface(drv->nlmode)) {
+ enum nl80211_iftype old_mode = drv->nlmode;
+
+ /*
+ * mac80211 does not allow scan requests in AP mode, so
+ * try to do this in station mode.
+ */
+ if (wpa_driver_nl80211_set_mode(
+ bss, NL80211_IFTYPE_STATION))
+ goto fail;
+
+ if (wpa_driver_nl80211_scan(bss, params)) {
+ wpa_driver_nl80211_set_mode(bss, old_mode);
+ goto fail;
+ }
+
+ /* Restore AP mode when processing scan results */
+ drv->ap_scan_as_station = old_mode;
+ ret = 0;
+ } else
+ goto fail;
+ }
+
+ drv->scan_state = SCAN_REQUESTED;
+ /* Not all drivers generate "scan completed" wireless event, so try to
+ * read results after a timeout. */
+ timeout = 10;
+ if (drv->scan_complete_events) {
+ /*
+ * The driver seems to deliver events to notify when scan is
+ * complete, so use longer timeout to avoid race conditions
+ * with scanning and following association request.
+ */
+ timeout = 30;
+ }
+ wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
+ "seconds", ret, timeout);
+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
+ eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout,
+ drv, drv->ctx);
+
+fail:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+/**
+ * wpa_driver_nl80211_sched_scan - Initiate a scheduled scan
+ * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
+ * @params: Scan parameters
+ * @interval: Interval between scan cycles in milliseconds
+ * Returns: 0 on success, -1 on failure or if not supported
+ */
+int wpa_driver_nl80211_sched_scan(void *priv,
+ struct wpa_driver_scan_params *params,
+ u32 interval)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int ret = -1;
+ struct nl_msg *msg;
+ size_t i;
+
+ wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: sched_scan request");
+
+#ifdef ANDROID
+ if (!drv->capa.sched_scan_supported)
+ return android_pno_start(bss, params);
+#endif /* ANDROID */
+
+ msg = nl80211_scan_common(bss, NL80211_CMD_START_SCHED_SCAN, params);
+ if (!msg ||
+ nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, interval))
+ goto fail;
+
+ if ((drv->num_filter_ssids &&
+ (int) drv->num_filter_ssids <= drv->capa.max_match_sets) ||
+ params->filter_rssi) {
+ struct nlattr *match_sets;
+ match_sets = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_MATCH);
+ if (match_sets == NULL)
+ goto fail;
+
+ for (i = 0; i < drv->num_filter_ssids; i++) {
+ struct nlattr *match_set_ssid;
+ wpa_hexdump_ascii(MSG_MSGDUMP,
+ "nl80211: Sched scan filter SSID",
+ drv->filter_ssids[i].ssid,
+ drv->filter_ssids[i].ssid_len);
+
+ match_set_ssid = nla_nest_start(msg, i + 1);
+ if (match_set_ssid == NULL ||
+ nla_put(msg, NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
+ drv->filter_ssids[i].ssid_len,
+ drv->filter_ssids[i].ssid) ||
+ (params->filter_rssi &&
+ nla_put_u32(msg,
+ NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
+ params->filter_rssi)))
+ goto fail;
+
+ nla_nest_end(msg, match_set_ssid);
+ }
+
+ /*
+ * Due to backward compatibility code, newer kernels treat this
+ * matchset (with only an RSSI filter) as the default for all
+ * other matchsets, unless it's the only one, in which case the
+ * matchset will actually allow all SSIDs above the RSSI.
+ */
+ if (params->filter_rssi) {
+ struct nlattr *match_set_rssi;
+ match_set_rssi = nla_nest_start(msg, 0);
+ if (match_set_rssi == NULL ||
+ nla_put_u32(msg, NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
+ params->filter_rssi))
+ goto fail;
+ wpa_printf(MSG_MSGDUMP,
+ "nl80211: Sched scan RSSI filter %d dBm",
+ params->filter_rssi);
+ nla_nest_end(msg, match_set_rssi);
+ }
+
+ nla_nest_end(msg, match_sets);
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+
+ /* TODO: if we get an error here, we should fall back to normal scan */
+
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Sched scan start failed: "
+ "ret=%d (%s)", ret, strerror(-ret));
+ goto fail;
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Sched scan requested (ret=%d) - "
+ "scan interval %d msec", ret, interval);
+
+fail:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+/**
+ * wpa_driver_nl80211_stop_sched_scan - Stop a scheduled scan
+ * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
+ * Returns: 0 on success, -1 on failure or if not supported
+ */
+int wpa_driver_nl80211_stop_sched_scan(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int ret;
+ struct nl_msg *msg;
+
+#ifdef ANDROID
+ if (!drv->capa.sched_scan_supported)
+ return android_pno_stop(bss);
+#endif /* ANDROID */
+
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_STOP_SCHED_SCAN);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Sched scan stop failed: ret=%d (%s)",
+ ret, strerror(-ret));
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Sched scan stop sent");
+ }
+
+ return ret;
+}
+
+
+static const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie)
+{
+ const u8 *end, *pos;
+
+ if (ies == NULL)
+ return NULL;
+
+ pos = ies;
+ end = ies + ies_len;
+
+ while (pos + 1 < end) {
+ if (pos + 2 + pos[1] > end)
+ break;
+ if (pos[0] == ie)
+ return pos;
+ pos += 2 + pos[1];
+ }
+
+ return NULL;
+}
+
+
+static int nl80211_scan_filtered(struct wpa_driver_nl80211_data *drv,
+ const u8 *ie, size_t ie_len)
+{
+ const u8 *ssid;
+ size_t i;
+
+ if (drv->filter_ssids == NULL)
+ return 0;
+
+ ssid = nl80211_get_ie(ie, ie_len, WLAN_EID_SSID);
+ if (ssid == NULL)
+ return 1;
+
+ for (i = 0; i < drv->num_filter_ssids; i++) {
+ if (ssid[1] == drv->filter_ssids[i].ssid_len &&
+ os_memcmp(ssid + 2, drv->filter_ssids[i].ssid, ssid[1]) ==
+ 0)
+ return 0;
+ }
+
+ return 1;
+}
+
+
+int bss_info_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *bss[NL80211_BSS_MAX + 1];
+ static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
+ [NL80211_BSS_BSSID] = { .type = NLA_UNSPEC },
+ [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
+ [NL80211_BSS_TSF] = { .type = NLA_U64 },
+ [NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
+ [NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
+ [NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC },
+ [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
+ [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
+ [NL80211_BSS_STATUS] = { .type = NLA_U32 },
+ [NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
+ [NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC },
+ };
+ struct nl80211_bss_info_arg *_arg = arg;
+ struct wpa_scan_results *res = _arg->res;
+ struct wpa_scan_res **tmp;
+ struct wpa_scan_res *r;
+ const u8 *ie, *beacon_ie;
+ size_t ie_len, beacon_ie_len;
+ u8 *pos;
+ size_t i;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+ if (!tb[NL80211_ATTR_BSS])
+ return NL_SKIP;
+ if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
+ bss_policy))
+ return NL_SKIP;
+ if (bss[NL80211_BSS_STATUS]) {
+ enum nl80211_bss_status status;
+ status = nla_get_u32(bss[NL80211_BSS_STATUS]);
+ if (status == NL80211_BSS_STATUS_ASSOCIATED &&
+ bss[NL80211_BSS_FREQUENCY]) {
+ _arg->assoc_freq =
+ nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
+ wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz",
+ _arg->assoc_freq);
+ }
+ if (status == NL80211_BSS_STATUS_IBSS_JOINED &&
+ bss[NL80211_BSS_FREQUENCY]) {
+ _arg->ibss_freq =
+ nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
+ wpa_printf(MSG_DEBUG, "nl80211: IBSS-joined on %u MHz",
+ _arg->ibss_freq);
+ }
+ if (status == NL80211_BSS_STATUS_ASSOCIATED &&
+ bss[NL80211_BSS_BSSID]) {
+ os_memcpy(_arg->assoc_bssid,
+ nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN);
+ wpa_printf(MSG_DEBUG, "nl80211: Associated with "
+ MACSTR, MAC2STR(_arg->assoc_bssid));
+ }
+ }
+ if (!res)
+ return NL_SKIP;
+ if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
+ ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
+ ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
+ } else {
+ ie = NULL;
+ ie_len = 0;
+ }
+ if (bss[NL80211_BSS_BEACON_IES]) {
+ beacon_ie = nla_data(bss[NL80211_BSS_BEACON_IES]);
+ beacon_ie_len = nla_len(bss[NL80211_BSS_BEACON_IES]);
+ } else {
+ beacon_ie = NULL;
+ beacon_ie_len = 0;
+ }
+
+ if (nl80211_scan_filtered(_arg->drv, ie ? ie : beacon_ie,
+ ie ? ie_len : beacon_ie_len))
+ return NL_SKIP;
+
+ r = os_zalloc(sizeof(*r) + ie_len + beacon_ie_len);
+ if (r == NULL)
+ return NL_SKIP;
+ if (bss[NL80211_BSS_BSSID])
+ os_memcpy(r->bssid, nla_data(bss[NL80211_BSS_BSSID]),
+ ETH_ALEN);
+ if (bss[NL80211_BSS_FREQUENCY])
+ r->freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
+ if (bss[NL80211_BSS_BEACON_INTERVAL])
+ r->beacon_int = nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]);
+ if (bss[NL80211_BSS_CAPABILITY])
+ r->caps = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
+ r->flags |= WPA_SCAN_NOISE_INVALID;
+ if (bss[NL80211_BSS_SIGNAL_MBM]) {
+ r->level = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
+ r->level /= 100; /* mBm to dBm */
+ r->flags |= WPA_SCAN_LEVEL_DBM | WPA_SCAN_QUAL_INVALID;
+ } else if (bss[NL80211_BSS_SIGNAL_UNSPEC]) {
+ r->level = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
+ r->flags |= WPA_SCAN_QUAL_INVALID;
+ } else
+ r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID;
+ if (bss[NL80211_BSS_TSF])
+ r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]);
+ if (bss[NL80211_BSS_SEEN_MS_AGO])
+ r->age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]);
+ r->ie_len = ie_len;
+ pos = (u8 *) (r + 1);
+ if (ie) {
+ os_memcpy(pos, ie, ie_len);
+ pos += ie_len;
+ }
+ r->beacon_ie_len = beacon_ie_len;
+ if (beacon_ie)
+ os_memcpy(pos, beacon_ie, beacon_ie_len);
+
+ if (bss[NL80211_BSS_STATUS]) {
+ enum nl80211_bss_status status;
+ status = nla_get_u32(bss[NL80211_BSS_STATUS]);
+ switch (status) {
+ case NL80211_BSS_STATUS_ASSOCIATED:
+ r->flags |= WPA_SCAN_ASSOCIATED;
+ break;
+ default:
+ break;
+ }
+ }
+
+ /*
+ * cfg80211 maintains separate BSS table entries for APs if the same
+ * BSSID,SSID pair is seen on multiple channels. wpa_supplicant does
+ * not use frequency as a separate key in the BSS table, so filter out
+ * duplicated entries. Prefer associated BSS entry in such a case in
+ * order to get the correct frequency into the BSS table. Similarly,
+ * prefer newer entries over older.
+ */
+ for (i = 0; i < res->num; i++) {
+ const u8 *s1, *s2;
+ if (os_memcmp(res->res[i]->bssid, r->bssid, ETH_ALEN) != 0)
+ continue;
+
+ s1 = nl80211_get_ie((u8 *) (res->res[i] + 1),
+ res->res[i]->ie_len, WLAN_EID_SSID);
+ s2 = nl80211_get_ie((u8 *) (r + 1), r->ie_len, WLAN_EID_SSID);
+ if (s1 == NULL || s2 == NULL || s1[1] != s2[1] ||
+ os_memcmp(s1, s2, 2 + s1[1]) != 0)
+ continue;
+
+ /* Same BSSID,SSID was already included in scan results */
+ wpa_printf(MSG_DEBUG, "nl80211: Remove duplicated scan result "
+ "for " MACSTR, MAC2STR(r->bssid));
+
+ if (((r->flags & WPA_SCAN_ASSOCIATED) &&
+ !(res->res[i]->flags & WPA_SCAN_ASSOCIATED)) ||
+ r->age < res->res[i]->age) {
+ os_free(res->res[i]);
+ res->res[i] = r;
+ } else
+ os_free(r);
+ return NL_SKIP;
+ }
+
+ tmp = os_realloc_array(res->res, res->num + 1,
+ sizeof(struct wpa_scan_res *));
+ if (tmp == NULL) {
+ os_free(r);
+ return NL_SKIP;
+ }
+ tmp[res->num++] = r;
+ res->res = tmp;
+
+ return NL_SKIP;
+}
+
+
+static void clear_state_mismatch(struct wpa_driver_nl80211_data *drv,
+ const u8 *addr)
+{
+ if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
+ wpa_printf(MSG_DEBUG, "nl80211: Clear possible state "
+ "mismatch (" MACSTR ")", MAC2STR(addr));
+ wpa_driver_nl80211_mlme(drv, addr,
+ NL80211_CMD_DEAUTHENTICATE,
+ WLAN_REASON_PREV_AUTH_NOT_VALID, 1);
+ }
+}
+
+
+static void wpa_driver_nl80211_check_bss_status(
+ struct wpa_driver_nl80211_data *drv, struct wpa_scan_results *res)
+{
+ size_t i;
+
+ for (i = 0; i < res->num; i++) {
+ struct wpa_scan_res *r = res->res[i];
+
+ if (r->flags & WPA_SCAN_ASSOCIATED) {
+ wpa_printf(MSG_DEBUG, "nl80211: Scan results "
+ "indicate BSS status with " MACSTR
+ " as associated",
+ MAC2STR(r->bssid));
+ if (is_sta_interface(drv->nlmode) &&
+ !drv->associated) {
+ wpa_printf(MSG_DEBUG, "nl80211: Local state "
+ "(not associated) does not match "
+ "with BSS state");
+ clear_state_mismatch(drv, r->bssid);
+ } else if (is_sta_interface(drv->nlmode) &&
+ os_memcmp(drv->bssid, r->bssid, ETH_ALEN) !=
+ 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Local state "
+ "(associated with " MACSTR ") does "
+ "not match with BSS state",
+ MAC2STR(drv->bssid));
+ clear_state_mismatch(drv, r->bssid);
+ clear_state_mismatch(drv, drv->bssid);
+ }
+ }
+ }
+}
+
+
+static struct wpa_scan_results *
+nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
+{
+ struct nl_msg *msg;
+ struct wpa_scan_results *res;
+ int ret;
+ struct nl80211_bss_info_arg arg;
+
+ res = os_zalloc(sizeof(*res));
+ if (res == NULL)
+ return NULL;
+ if (!(msg = nl80211_cmd_msg(drv->first_bss, NLM_F_DUMP,
+ NL80211_CMD_GET_SCAN))) {
+ wpa_scan_results_free(res);
+ return NULL;
+ }
+
+ arg.drv = drv;
+ arg.res = res;
+ ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
+ if (ret == 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Received scan results (%lu "
+ "BSSes)", (unsigned long) res->num);
+ nl80211_get_noise_for_scan_results(drv, res);
+ return res;
+ }
+ wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
+ "(%s)", ret, strerror(-ret));
+ wpa_scan_results_free(res);
+ return NULL;
+}
+
+
+/**
+ * wpa_driver_nl80211_get_scan_results - Fetch the latest scan results
+ * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
+ * Returns: Scan results on success, -1 on failure
+ */
+struct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct wpa_scan_results *res;
+
+ res = nl80211_get_scan_results(drv);
+ if (res)
+ wpa_driver_nl80211_check_bss_status(drv, res);
+ return res;
+}
+
+
+void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv)
+{
+ struct wpa_scan_results *res;
+ size_t i;
+
+ res = nl80211_get_scan_results(drv);
+ if (res == NULL) {
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to get scan results");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Scan result dump");
+ for (i = 0; i < res->num; i++) {
+ struct wpa_scan_res *r = res->res[i];
+ wpa_printf(MSG_DEBUG, "nl80211: %d/%d " MACSTR "%s",
+ (int) i, (int) res->num, MAC2STR(r->bssid),
+ r->flags & WPA_SCAN_ASSOCIATED ? " [assoc]" : "");
+ }
+
+ wpa_scan_results_free(res);
+}
diff --git a/src/drivers/driver_none.c b/src/drivers/driver_none.c
index d75c14b..6ff3eae 100644
--- a/src/drivers/driver_none.c
+++ b/src/drivers/driver_none.c
@@ -74,13 +74,6 @@
}
-static int none_driver_send_eapol(void *priv, const u8 *dest, u16 proto,
- const u8 *data, size_t data_len)
-{
- return -1;
-}
-
-
const struct wpa_driver_ops wpa_driver_none_ops = {
.name = "none",
.desc = "no driver (RADIUS server/WPS ER)",
@@ -89,5 +82,4 @@
.send_ether = none_driver_send_ether,
.init = none_driver_init,
.deinit = none_driver_deinit,
- .send_eapol = none_driver_send_eapol,
};
diff --git a/src/drivers/driver_privsep.c b/src/drivers/driver_privsep.c
index ed88e71..de23fbd 100644
--- a/src/drivers/driver_privsep.c
+++ b/src/drivers/driver_privsep.c
@@ -35,7 +35,7 @@
(struct sockaddr *) &drv->priv_addr,
sizeof(drv->priv_addr));
if (res < 0)
- perror("sendto");
+ wpa_printf(MSG_ERROR, "sendto: %s", strerror(errno));
return res < 0 ? -1 : 0;
}
@@ -59,7 +59,8 @@
msg.msg_namelen = sizeof(drv->priv_addr);
if (sendmsg(drv->cmd_socket, &msg, 0) < 0) {
- perror("sendmsg(cmd_socket)");
+ wpa_printf(MSG_ERROR, "sendmsg(cmd_socket): %s",
+ strerror(errno));
return -1;
}
@@ -74,14 +75,15 @@
tv.tv_usec = 0;
res = select(drv->cmd_socket + 1, &rfds, NULL, NULL, &tv);
if (res < 0 && errno != EINTR) {
- perror("select");
+ wpa_printf(MSG_ERROR, "select: %s", strerror(errno));
return -1;
}
if (FD_ISSET(drv->cmd_socket, &rfds)) {
res = recv(drv->cmd_socket, reply, *reply_len, 0);
if (res < 0) {
- perror("recv");
+ wpa_printf(MSG_ERROR, "recv: %s",
+ strerror(errno));
return -1;
}
*reply_len = res;
@@ -228,7 +230,7 @@
wpa_printf(MSG_DEBUG, "%s: priv=%p freq=%d pairwise_suite=%d "
"group_suite=%d key_mgmt_suite=%d auth_alg=%d mode=%d",
- __func__, priv, params->freq, params->pairwise_suite,
+ __func__, priv, params->freq.freq, params->pairwise_suite,
params->group_suite, params->key_mgmt_suite,
params->auth_alg, params->mode);
@@ -241,7 +243,9 @@
os_memcpy(data->bssid, params->bssid, ETH_ALEN);
os_memcpy(data->ssid, params->ssid, params->ssid_len);
data->ssid_len = params->ssid_len;
- data->freq = params->freq;
+ data->hwmode = params->freq.mode;
+ data->freq = params->freq.freq;
+ data->channel = params->freq.channel;
data->pairwise_suite = params->pairwise_suite;
data->group_suite = params->group_suite;
data->key_mgmt_suite = params->key_mgmt_suite;
@@ -439,7 +443,8 @@
res = recvfrom(sock, buf, buflen, 0,
(struct sockaddr *) &from, &fromlen);
if (res < 0) {
- perror("recvfrom(priv_socket)");
+ wpa_printf(MSG_ERROR, "recvfrom(priv_socket): %s",
+ strerror(errno));
os_free(buf);
return;
}
@@ -629,7 +634,7 @@
drv->priv_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
if (drv->priv_socket < 0) {
- perror("socket(PF_UNIX)");
+ wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
os_free(drv->own_socket_path);
drv->own_socket_path = NULL;
return -1;
@@ -640,7 +645,9 @@
os_strlcpy(addr.sun_path, drv->own_socket_path, sizeof(addr.sun_path));
if (bind(drv->priv_socket, (struct sockaddr *) &addr, sizeof(addr)) <
0) {
- perror("privsep-set-params priv-sock: bind(PF_UNIX)");
+ wpa_printf(MSG_ERROR,
+ "privsep-set-params priv-sock: bind(PF_UNIX): %s",
+ strerror(errno));
close(drv->priv_socket);
drv->priv_socket = -1;
unlink(drv->own_socket_path);
@@ -654,7 +661,7 @@
drv->cmd_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
if (drv->cmd_socket < 0) {
- perror("socket(PF_UNIX)");
+ wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
os_free(drv->own_cmd_path);
drv->own_cmd_path = NULL;
return -1;
@@ -665,7 +672,9 @@
os_strlcpy(addr.sun_path, drv->own_cmd_path, sizeof(addr.sun_path));
if (bind(drv->cmd_socket, (struct sockaddr *) &addr, sizeof(addr)) < 0)
{
- perror("privsep-set-params cmd-sock: bind(PF_UNIX)");
+ wpa_printf(MSG_ERROR,
+ "privsep-set-params cmd-sock: bind(PF_UNIX): %s",
+ strerror(errno));
close(drv->cmd_socket);
drv->cmd_socket = -1;
unlink(drv->own_cmd_path);
diff --git a/src/drivers/driver_roboswitch.c b/src/drivers/driver_roboswitch.c
index 9ce3fa2..d3e0595 100644
--- a/src/drivers/driver_roboswitch.c
+++ b/src/drivers/driver_roboswitch.c
@@ -91,7 +91,8 @@
mii->reg_num = reg;
if (ioctl(drv->fd, SIOCGMIIREG, &drv->ifr) < 0) {
- perror("ioctl[SIOCGMIIREG]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGMIIREG]: %s",
+ strerror(errno));
return 0x00;
}
return mii->val_out;
@@ -108,7 +109,8 @@
mii->val_in = val;
if (ioctl(drv->fd, SIOCSMIIREG, &drv->ifr) < 0) {
- perror("ioctl[SIOCSMIIREG");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSMIIREG]: %s",
+ strerror(errno));
}
}
@@ -394,7 +396,8 @@
os_memset(&drv->ifr, 0, sizeof(drv->ifr));
os_strlcpy(drv->ifr.ifr_name, drv->ifname, IFNAMSIZ);
if (ioctl(drv->fd, SIOCGMIIPHY, &drv->ifr) < 0) {
- perror("ioctl[SIOCGMIIPHY]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGMIIPHY]: %s",
+ strerror(errno));
os_free(drv);
return NULL;
}
diff --git a/src/drivers/driver_test.c b/src/drivers/driver_test.c
deleted file mode 100644
index 66edfa7..0000000
--- a/src/drivers/driver_test.c
+++ /dev/null
@@ -1,2683 +0,0 @@
-/*
- * Testing driver interface for a simulated network driver
- * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-/* Make sure we get winsock2.h for Windows build to get sockaddr_storage */
-#include "build_config.h"
-#ifdef CONFIG_NATIVE_WINDOWS
-#include <winsock2.h>
-#endif /* CONFIG_NATIVE_WINDOWS */
-
-#include "utils/includes.h"
-
-#ifndef CONFIG_NATIVE_WINDOWS
-#include <sys/un.h>
-#include <dirent.h>
-#include <sys/stat.h>
-#define DRIVER_TEST_UNIX
-#endif /* CONFIG_NATIVE_WINDOWS */
-
-#include "utils/common.h"
-#include "utils/eloop.h"
-#include "utils/list.h"
-#include "utils/trace.h"
-#include "common/ieee802_11_defs.h"
-#include "crypto/sha1.h"
-#include "l2_packet/l2_packet.h"
-#include "wps/wps.h"
-#include "driver.h"
-
-
-struct test_client_socket {
- struct test_client_socket *next;
- u8 addr[ETH_ALEN];
- struct sockaddr_un un;
- socklen_t unlen;
- struct test_driver_bss *bss;
-};
-
-struct test_driver_bss {
- struct wpa_driver_test_data *drv;
- struct dl_list list;
- void *bss_ctx;
- char ifname[IFNAMSIZ];
- u8 bssid[ETH_ALEN];
- u8 *ie;
- size_t ielen;
- u8 *wps_beacon_ie;
- size_t wps_beacon_ie_len;
- u8 *wps_probe_resp_ie;
- size_t wps_probe_resp_ie_len;
- u8 ssid[32];
- size_t ssid_len;
- int privacy;
-};
-
-struct wpa_driver_test_global {
- int bss_add_used;
- u8 req_addr[ETH_ALEN];
-};
-
-struct wpa_driver_test_data {
- struct wpa_driver_test_global *global;
- void *ctx;
- WPA_TRACE_REF(ctx);
- u8 own_addr[ETH_ALEN];
- int test_socket;
-#ifdef DRIVER_TEST_UNIX
- struct sockaddr_un hostapd_addr;
-#endif /* DRIVER_TEST_UNIX */
- int hostapd_addr_set;
- struct sockaddr_in hostapd_addr_udp;
- int hostapd_addr_udp_set;
- char *own_socket_path;
- char *test_dir;
-#define MAX_SCAN_RESULTS 30
- struct wpa_scan_res *scanres[MAX_SCAN_RESULTS];
- size_t num_scanres;
- int use_associnfo;
- u8 assoc_wpa_ie[80];
- size_t assoc_wpa_ie_len;
- int associated;
- u8 *probe_req_ie;
- size_t probe_req_ie_len;
- u8 probe_req_ssid[32];
- size_t probe_req_ssid_len;
- int ibss;
- int ap;
-
- struct test_client_socket *cli;
- struct dl_list bss;
- int udp_port;
-
- int alloc_iface_idx;
-
- int probe_req_report;
- unsigned int remain_on_channel_freq;
- unsigned int remain_on_channel_duration;
-
- int current_freq;
-};
-
-
-static void wpa_driver_test_deinit(void *priv);
-static int wpa_driver_test_attach(struct wpa_driver_test_data *drv,
- const char *dir, int ap);
-static void wpa_driver_test_close_test_socket(
- struct wpa_driver_test_data *drv);
-static void test_remain_on_channel_timeout(void *eloop_ctx, void *timeout_ctx);
-
-
-static void test_driver_free_bss(struct test_driver_bss *bss)
-{
- os_free(bss->ie);
- os_free(bss->wps_beacon_ie);
- os_free(bss->wps_probe_resp_ie);
- os_free(bss);
-}
-
-
-static void test_driver_free_bsses(struct wpa_driver_test_data *drv)
-{
- struct test_driver_bss *bss, *tmp;
-
- dl_list_for_each_safe(bss, tmp, &drv->bss, struct test_driver_bss,
- list) {
- dl_list_del(&bss->list);
- test_driver_free_bss(bss);
- }
-}
-
-
-static struct test_client_socket *
-test_driver_get_cli(struct wpa_driver_test_data *drv, struct sockaddr_un *from,
- socklen_t fromlen)
-{
- struct test_client_socket *cli = drv->cli;
-
- while (cli) {
- if (cli->unlen == fromlen &&
- strncmp(cli->un.sun_path, from->sun_path,
- fromlen - sizeof(cli->un.sun_family)) == 0)
- return cli;
- cli = cli->next;
- }
-
- return NULL;
-}
-
-
-static int test_driver_send_eapol(void *priv, const u8 *addr, const u8 *data,
- size_t data_len, int encrypt,
- const u8 *own_addr, u32 flags)
-{
- struct test_driver_bss *dbss = priv;
- struct wpa_driver_test_data *drv = dbss->drv;
- struct test_client_socket *cli;
- struct msghdr msg;
- struct iovec io[3];
- struct l2_ethhdr eth;
-
- if (drv->test_socket < 0)
- return -1;
-
- cli = drv->cli;
- while (cli) {
- if (memcmp(cli->addr, addr, ETH_ALEN) == 0)
- break;
- cli = cli->next;
- }
-
- if (!cli) {
- wpa_printf(MSG_DEBUG, "%s: no destination client entry",
- __func__);
- return -1;
- }
-
- memcpy(eth.h_dest, addr, ETH_ALEN);
- memcpy(eth.h_source, own_addr, ETH_ALEN);
- eth.h_proto = host_to_be16(ETH_P_EAPOL);
-
- io[0].iov_base = "EAPOL ";
- io[0].iov_len = 6;
- io[1].iov_base = ð
- io[1].iov_len = sizeof(eth);
- io[2].iov_base = (u8 *) data;
- io[2].iov_len = data_len;
-
- memset(&msg, 0, sizeof(msg));
- msg.msg_iov = io;
- msg.msg_iovlen = 3;
- msg.msg_name = &cli->un;
- msg.msg_namelen = cli->unlen;
- return sendmsg(drv->test_socket, &msg, 0);
-}
-
-
-static int test_driver_send_ether(void *priv, const u8 *dst, const u8 *src,
- u16 proto, const u8 *data, size_t data_len)
-{
- struct test_driver_bss *dbss = priv;
- struct wpa_driver_test_data *drv = dbss->drv;
- struct msghdr msg;
- struct iovec io[3];
- struct l2_ethhdr eth;
- char desttxt[30];
- struct sockaddr_un addr;
- struct dirent *dent;
- DIR *dir;
- int ret = 0, broadcast = 0, count = 0;
-
- if (drv->test_socket < 0 || drv->test_dir == NULL) {
- wpa_printf(MSG_DEBUG, "%s: invalid parameters (sock=%d "
- "test_dir=%p)",
- __func__, drv->test_socket, drv->test_dir);
- return -1;
- }
-
- broadcast = memcmp(dst, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0;
- snprintf(desttxt, sizeof(desttxt), MACSTR, MAC2STR(dst));
-
- memcpy(eth.h_dest, dst, ETH_ALEN);
- memcpy(eth.h_source, src, ETH_ALEN);
- eth.h_proto = host_to_be16(proto);
-
- io[0].iov_base = "ETHER ";
- io[0].iov_len = 6;
- io[1].iov_base = ð
- io[1].iov_len = sizeof(eth);
- io[2].iov_base = (u8 *) data;
- io[2].iov_len = data_len;
-
- memset(&msg, 0, sizeof(msg));
- msg.msg_iov = io;
- msg.msg_iovlen = 3;
-
- dir = opendir(drv->test_dir);
- if (dir == NULL) {
- perror("test_driver: opendir");
- return -1;
- }
- while ((dent = readdir(dir))) {
-#ifdef _DIRENT_HAVE_D_TYPE
- /* Skip the file if it is not a socket. Also accept
- * DT_UNKNOWN (0) in case the C library or underlying file
- * system does not support d_type. */
- if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN)
- continue;
-#endif /* _DIRENT_HAVE_D_TYPE */
- if (strcmp(dent->d_name, ".") == 0 ||
- strcmp(dent->d_name, "..") == 0)
- continue;
-
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s",
- drv->test_dir, dent->d_name);
-
- if (strcmp(addr.sun_path, drv->own_socket_path) == 0)
- continue;
- if (!broadcast && strstr(dent->d_name, desttxt) == NULL)
- continue;
-
- wpa_printf(MSG_DEBUG, "%s: Send ether frame to %s",
- __func__, dent->d_name);
-
- msg.msg_name = &addr;
- msg.msg_namelen = sizeof(addr);
- ret = sendmsg(drv->test_socket, &msg, 0);
- if (ret < 0)
- perror("driver_test: sendmsg");
- count++;
- }
- closedir(dir);
-
- if (!broadcast && count == 0) {
- wpa_printf(MSG_DEBUG, "%s: Destination " MACSTR " not found",
- __func__, MAC2STR(dst));
- return -1;
- }
-
- return ret;
-}
-
-
-static int wpa_driver_test_send_mlme(void *priv, const u8 *data,
- size_t data_len, int noack)
-{
- struct test_driver_bss *dbss = priv;
- struct wpa_driver_test_data *drv = dbss->drv;
- struct msghdr msg;
- struct iovec io[2];
- const u8 *dest;
- struct sockaddr_un addr;
- struct dirent *dent;
- DIR *dir;
- int broadcast;
- int ret = 0;
- struct ieee80211_hdr *hdr;
- u16 fc;
- char cmd[50];
- int freq;
-#ifdef HOSTAPD
- char desttxt[30];
-#endif /* HOSTAPD */
- union wpa_event_data event;
-
- wpa_hexdump(MSG_MSGDUMP, "test_send_mlme", data, data_len);
- if (drv->test_socket < 0 || data_len < 10) {
- wpa_printf(MSG_DEBUG, "%s: invalid parameters (sock=%d len=%lu"
- " test_dir=%p)",
- __func__, drv->test_socket,
- (unsigned long) data_len,
- drv->test_dir);
- return -1;
- }
-
- dest = data + 4;
- broadcast = os_memcmp(dest, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0;
-
-#ifdef HOSTAPD
- snprintf(desttxt, sizeof(desttxt), MACSTR, MAC2STR(dest));
-#endif /* HOSTAPD */
-
- if (drv->remain_on_channel_freq)
- freq = drv->remain_on_channel_freq;
- else
- freq = drv->current_freq;
- wpa_printf(MSG_DEBUG, "test_driver(%s): MLME TX on freq %d MHz",
- dbss->ifname, freq);
- os_snprintf(cmd, sizeof(cmd), "MLME freq=%d ", freq);
- io[0].iov_base = cmd;
- io[0].iov_len = os_strlen(cmd);
- io[1].iov_base = (void *) data;
- io[1].iov_len = data_len;
-
- os_memset(&msg, 0, sizeof(msg));
- msg.msg_iov = io;
- msg.msg_iovlen = 2;
-
-#ifdef HOSTAPD
- if (drv->test_dir == NULL) {
- wpa_printf(MSG_DEBUG, "%s: test_dir == NULL", __func__);
- return -1;
- }
-
- dir = opendir(drv->test_dir);
- if (dir == NULL) {
- perror("test_driver: opendir");
- return -1;
- }
- while ((dent = readdir(dir))) {
-#ifdef _DIRENT_HAVE_D_TYPE
- /* Skip the file if it is not a socket. Also accept
- * DT_UNKNOWN (0) in case the C library or underlying file
- * system does not support d_type. */
- if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN)
- continue;
-#endif /* _DIRENT_HAVE_D_TYPE */
- if (os_strcmp(dent->d_name, ".") == 0 ||
- os_strcmp(dent->d_name, "..") == 0)
- continue;
-
- os_memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- os_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s",
- drv->test_dir, dent->d_name);
-
- if (os_strcmp(addr.sun_path, drv->own_socket_path) == 0)
- continue;
- if (!broadcast && os_strstr(dent->d_name, desttxt) == NULL)
- continue;
-
- wpa_printf(MSG_DEBUG, "%s: Send management frame to %s",
- __func__, dent->d_name);
-
- msg.msg_name = &addr;
- msg.msg_namelen = sizeof(addr);
- ret = sendmsg(drv->test_socket, &msg, 0);
- if (ret < 0)
- perror("driver_test: sendmsg(test_socket)");
- }
- closedir(dir);
-#else /* HOSTAPD */
-
- if (os_memcmp(dest, dbss->bssid, ETH_ALEN) == 0 ||
- drv->test_dir == NULL) {
- if (drv->hostapd_addr_udp_set) {
- msg.msg_name = &drv->hostapd_addr_udp;
- msg.msg_namelen = sizeof(drv->hostapd_addr_udp);
- } else {
-#ifdef DRIVER_TEST_UNIX
- msg.msg_name = &drv->hostapd_addr;
- msg.msg_namelen = sizeof(drv->hostapd_addr);
-#endif /* DRIVER_TEST_UNIX */
- }
- } else if (broadcast) {
- dir = opendir(drv->test_dir);
- if (dir == NULL)
- return -1;
- while ((dent = readdir(dir))) {
-#ifdef _DIRENT_HAVE_D_TYPE
- /* Skip the file if it is not a socket.
- * Also accept DT_UNKNOWN (0) in case
- * the C library or underlying file
- * system does not support d_type. */
- if (dent->d_type != DT_SOCK &&
- dent->d_type != DT_UNKNOWN)
- continue;
-#endif /* _DIRENT_HAVE_D_TYPE */
- if (os_strcmp(dent->d_name, ".") == 0 ||
- os_strcmp(dent->d_name, "..") == 0)
- continue;
- wpa_printf(MSG_DEBUG, "%s: Send broadcast MLME to %s",
- __func__, dent->d_name);
- os_memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- os_snprintf(addr.sun_path, sizeof(addr.sun_path),
- "%s/%s", drv->test_dir, dent->d_name);
-
- msg.msg_name = &addr;
- msg.msg_namelen = sizeof(addr);
-
- ret = sendmsg(drv->test_socket, &msg, 0);
- if (ret < 0)
- perror("driver_test: sendmsg(test_socket)");
- }
- closedir(dir);
- return ret;
- } else {
- struct stat st;
- os_memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- os_snprintf(addr.sun_path, sizeof(addr.sun_path),
- "%s/AP-" MACSTR, drv->test_dir, MAC2STR(dest));
- if (stat(addr.sun_path, &st) < 0) {
- os_snprintf(addr.sun_path, sizeof(addr.sun_path),
- "%s/STA-" MACSTR,
- drv->test_dir, MAC2STR(dest));
- }
- msg.msg_name = &addr;
- msg.msg_namelen = sizeof(addr);
- }
-
- if (sendmsg(drv->test_socket, &msg, 0) < 0) {
- perror("sendmsg(test_socket)");
- return -1;
- }
-#endif /* HOSTAPD */
-
- hdr = (struct ieee80211_hdr *) data;
- fc = le_to_host16(hdr->frame_control);
-
- os_memset(&event, 0, sizeof(event));
- event.tx_status.type = WLAN_FC_GET_TYPE(fc);
- event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
- event.tx_status.dst = hdr->addr1;
- event.tx_status.data = data;
- event.tx_status.data_len = data_len;
- event.tx_status.ack = ret >= 0;
- wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event);
-
- return ret;
-}
-
-
-static void test_driver_scan(struct wpa_driver_test_data *drv,
- struct sockaddr_un *from, socklen_t fromlen,
- char *data)
-{
- char buf[512], *pos, *end;
- int ret;
- struct test_driver_bss *bss;
- u8 sa[ETH_ALEN];
- u8 ie[512];
- size_t ielen;
- union wpa_event_data event;
-
- /* data: optional [ ' ' | STA-addr | ' ' | IEs(hex) ] */
-
- wpa_printf(MSG_DEBUG, "test_driver: SCAN");
-
- if (*data) {
- if (*data != ' ' ||
- hwaddr_aton(data + 1, sa)) {
- wpa_printf(MSG_DEBUG, "test_driver: Unexpected SCAN "
- "command format");
- return;
- }
-
- data += 18;
- while (*data == ' ')
- data++;
- ielen = os_strlen(data) / 2;
- if (ielen > sizeof(ie))
- ielen = sizeof(ie);
- if (hexstr2bin(data, ie, ielen) < 0)
- ielen = 0;
-
- wpa_printf(MSG_DEBUG, "test_driver: Scan from " MACSTR,
- MAC2STR(sa));
- wpa_hexdump(MSG_MSGDUMP, "test_driver: scan IEs", ie, ielen);
-
- os_memset(&event, 0, sizeof(event));
- event.rx_probe_req.sa = sa;
- event.rx_probe_req.ie = ie;
- event.rx_probe_req.ie_len = ielen;
- wpa_supplicant_event(drv->ctx, EVENT_RX_PROBE_REQ, &event);
- }
-
- dl_list_for_each(bss, &drv->bss, struct test_driver_bss, list) {
- pos = buf;
- end = buf + sizeof(buf);
-
- /* reply: SCANRESP BSSID SSID IEs */
- ret = snprintf(pos, end - pos, "SCANRESP " MACSTR " ",
- MAC2STR(bss->bssid));
- if (ret < 0 || ret >= end - pos)
- return;
- pos += ret;
- pos += wpa_snprintf_hex(pos, end - pos,
- bss->ssid, bss->ssid_len);
- ret = snprintf(pos, end - pos, " ");
- if (ret < 0 || ret >= end - pos)
- return;
- pos += ret;
- pos += wpa_snprintf_hex(pos, end - pos, bss->ie, bss->ielen);
- pos += wpa_snprintf_hex(pos, end - pos, bss->wps_probe_resp_ie,
- bss->wps_probe_resp_ie_len);
-
- if (bss->privacy) {
- ret = snprintf(pos, end - pos, " PRIVACY");
- if (ret < 0 || ret >= end - pos)
- return;
- pos += ret;
- }
-
- sendto(drv->test_socket, buf, pos - buf, 0,
- (struct sockaddr *) from, fromlen);
- }
-}
-
-
-static void test_driver_assoc(struct wpa_driver_test_data *drv,
- struct sockaddr_un *from, socklen_t fromlen,
- char *data)
-{
- struct test_client_socket *cli;
- u8 ie[256], ssid[32];
- size_t ielen, ssid_len = 0;
- char *pos, *pos2, cmd[50];
- struct test_driver_bss *bss, *tmp;
-
- /* data: STA-addr SSID(hex) IEs(hex) */
-
- cli = os_zalloc(sizeof(*cli));
- if (cli == NULL)
- return;
-
- if (hwaddr_aton(data, cli->addr)) {
- printf("test_socket: Invalid MAC address '%s' in ASSOC\n",
- data);
- os_free(cli);
- return;
- }
- pos = data + 17;
- while (*pos == ' ')
- pos++;
- pos2 = strchr(pos, ' ');
- ielen = 0;
- if (pos2) {
- ssid_len = (pos2 - pos) / 2;
- if (hexstr2bin(pos, ssid, ssid_len) < 0) {
- wpa_printf(MSG_DEBUG, "%s: Invalid SSID", __func__);
- os_free(cli);
- return;
- }
- wpa_hexdump_ascii(MSG_DEBUG, "test_driver_assoc: SSID",
- ssid, ssid_len);
-
- pos = pos2 + 1;
- ielen = strlen(pos) / 2;
- if (ielen > sizeof(ie))
- ielen = sizeof(ie);
- if (hexstr2bin(pos, ie, ielen) < 0)
- ielen = 0;
- }
-
- bss = NULL;
- dl_list_for_each(tmp, &drv->bss, struct test_driver_bss, list) {
- if (tmp->ssid_len == ssid_len &&
- os_memcmp(tmp->ssid, ssid, ssid_len) == 0) {
- bss = tmp;
- break;
- }
- }
- if (bss == NULL) {
- wpa_printf(MSG_DEBUG, "%s: No matching SSID found from "
- "configured BSSes", __func__);
- os_free(cli);
- return;
- }
-
- cli->bss = bss;
- memcpy(&cli->un, from, sizeof(cli->un));
- cli->unlen = fromlen;
- cli->next = drv->cli;
- drv->cli = cli;
- wpa_hexdump_ascii(MSG_DEBUG, "test_socket: ASSOC sun_path",
- (const u8 *) cli->un.sun_path,
- cli->unlen - sizeof(cli->un.sun_family));
-
- snprintf(cmd, sizeof(cmd), "ASSOCRESP " MACSTR " 0",
- MAC2STR(bss->bssid));
- sendto(drv->test_socket, cmd, strlen(cmd), 0,
- (struct sockaddr *) from, fromlen);
-
- drv_event_assoc(bss->bss_ctx, cli->addr, ie, ielen, 0);
-}
-
-
-static void test_driver_disassoc(struct wpa_driver_test_data *drv,
- struct sockaddr_un *from, socklen_t fromlen)
-{
- struct test_client_socket *cli;
-
- cli = test_driver_get_cli(drv, from, fromlen);
- if (!cli)
- return;
-
- drv_event_disassoc(drv->ctx, cli->addr);
-}
-
-
-static void test_driver_eapol(struct wpa_driver_test_data *drv,
- struct sockaddr_un *from, socklen_t fromlen,
- u8 *data, size_t datalen)
-{
-#ifdef HOSTAPD
- struct test_client_socket *cli;
-#endif /* HOSTAPD */
- const u8 *src = NULL;
-
- if (datalen > 14) {
- /* Skip Ethernet header */
- src = data + ETH_ALEN;
- wpa_printf(MSG_DEBUG, "test_driver: dst=" MACSTR " src="
- MACSTR " proto=%04x",
- MAC2STR(data), MAC2STR(src),
- WPA_GET_BE16(data + 2 * ETH_ALEN));
- data += 14;
- datalen -= 14;
- }
-
-#ifdef HOSTAPD
- cli = test_driver_get_cli(drv, from, fromlen);
- if (cli) {
- drv_event_eapol_rx(cli->bss->bss_ctx, cli->addr, data,
- datalen);
- } else {
- wpa_printf(MSG_DEBUG, "test_socket: EAPOL from unknown "
- "client");
- }
-#else /* HOSTAPD */
- if (src)
- drv_event_eapol_rx(drv->ctx, src, data, datalen);
-#endif /* HOSTAPD */
-}
-
-
-static void test_driver_ether(struct wpa_driver_test_data *drv,
- struct sockaddr_un *from, socklen_t fromlen,
- u8 *data, size_t datalen)
-{
- struct l2_ethhdr *eth;
-
- if (datalen < sizeof(*eth))
- return;
-
- eth = (struct l2_ethhdr *) data;
- wpa_printf(MSG_DEBUG, "test_driver: RX ETHER dst=" MACSTR " src="
- MACSTR " proto=%04x",
- MAC2STR(eth->h_dest), MAC2STR(eth->h_source),
- be_to_host16(eth->h_proto));
-
-#ifdef CONFIG_IEEE80211R
- if (be_to_host16(eth->h_proto) == ETH_P_RRB) {
- union wpa_event_data ev;
- os_memset(&ev, 0, sizeof(ev));
- ev.ft_rrb_rx.src = eth->h_source;
- ev.ft_rrb_rx.data = data + sizeof(*eth);
- ev.ft_rrb_rx.data_len = datalen - sizeof(*eth);
- }
-#endif /* CONFIG_IEEE80211R */
-}
-
-
-static void test_driver_mlme(struct wpa_driver_test_data *drv,
- struct sockaddr_un *from, socklen_t fromlen,
- u8 *data, size_t datalen)
-{
- struct ieee80211_hdr *hdr;
- u16 fc;
- union wpa_event_data event;
- int freq = 0, own_freq;
- struct test_driver_bss *bss;
-
- bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
-
- if (datalen > 6 && os_memcmp(data, "freq=", 5) == 0) {
- size_t pos;
- for (pos = 5; pos < datalen; pos++) {
- if (data[pos] == ' ')
- break;
- }
- if (pos < datalen) {
- freq = atoi((const char *) &data[5]);
- wpa_printf(MSG_DEBUG, "test_driver(%s): MLME RX on "
- "freq %d MHz", bss->ifname, freq);
- pos++;
- data += pos;
- datalen -= pos;
- }
- }
-
- if (drv->remain_on_channel_freq)
- own_freq = drv->remain_on_channel_freq;
- else
- own_freq = drv->current_freq;
-
- if (freq && own_freq && freq != own_freq) {
- wpa_printf(MSG_DEBUG, "test_driver(%s): Ignore MLME RX on "
- "another frequency %d MHz (own %d MHz)",
- bss->ifname, freq, own_freq);
- return;
- }
-
- hdr = (struct ieee80211_hdr *) data;
-
- if (test_driver_get_cli(drv, from, fromlen) == NULL && datalen >= 16) {
- struct test_client_socket *cli;
- cli = os_zalloc(sizeof(*cli));
- if (cli == NULL)
- return;
- wpa_printf(MSG_DEBUG, "Adding client entry for " MACSTR,
- MAC2STR(hdr->addr2));
- memcpy(cli->addr, hdr->addr2, ETH_ALEN);
- memcpy(&cli->un, from, sizeof(cli->un));
- cli->unlen = fromlen;
- cli->next = drv->cli;
- drv->cli = cli;
- }
-
- wpa_hexdump(MSG_MSGDUMP, "test_driver_mlme: received frame",
- data, datalen);
- fc = le_to_host16(hdr->frame_control);
- if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT) {
- wpa_printf(MSG_ERROR, "%s: received non-mgmt frame",
- __func__);
- return;
- }
-
- os_memset(&event, 0, sizeof(event));
- event.rx_mgmt.frame = data;
- event.rx_mgmt.frame_len = datalen;
- wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
-}
-
-
-static void test_driver_receive_unix(int sock, void *eloop_ctx, void *sock_ctx)
-{
- struct wpa_driver_test_data *drv = eloop_ctx;
- char buf[2000];
- int res;
- struct sockaddr_un from;
- socklen_t fromlen = sizeof(from);
-
- res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
- (struct sockaddr *) &from, &fromlen);
- if (res < 0) {
- perror("recvfrom(test_socket)");
- return;
- }
- buf[res] = '\0';
-
- wpa_printf(MSG_DEBUG, "test_driver: received %u bytes", res);
-
- if (strncmp(buf, "SCAN", 4) == 0) {
- test_driver_scan(drv, &from, fromlen, buf + 4);
- } else if (strncmp(buf, "ASSOC ", 6) == 0) {
- test_driver_assoc(drv, &from, fromlen, buf + 6);
- } else if (strcmp(buf, "DISASSOC") == 0) {
- test_driver_disassoc(drv, &from, fromlen);
- } else if (strncmp(buf, "EAPOL ", 6) == 0) {
- test_driver_eapol(drv, &from, fromlen, (u8 *) buf + 6,
- res - 6);
- } else if (strncmp(buf, "ETHER ", 6) == 0) {
- test_driver_ether(drv, &from, fromlen, (u8 *) buf + 6,
- res - 6);
- } else if (strncmp(buf, "MLME ", 5) == 0) {
- test_driver_mlme(drv, &from, fromlen, (u8 *) buf + 5, res - 5);
- } else {
- wpa_hexdump_ascii(MSG_DEBUG, "Unknown test_socket command",
- (u8 *) buf, res);
- }
-}
-
-
-static int test_driver_set_generic_elem(void *priv,
- const u8 *elem, size_t elem_len)
-{
- struct test_driver_bss *bss = priv;
-
- os_free(bss->ie);
-
- if (elem == NULL) {
- bss->ie = NULL;
- bss->ielen = 0;
- return 0;
- }
-
- bss->ie = os_malloc(elem_len);
- if (bss->ie == NULL) {
- bss->ielen = 0;
- return -1;
- }
-
- memcpy(bss->ie, elem, elem_len);
- bss->ielen = elem_len;
- return 0;
-}
-
-
-static int test_driver_set_ap_wps_ie(void *priv, const struct wpabuf *beacon,
- const struct wpabuf *proberesp,
- const struct wpabuf *assocresp)
-{
- struct test_driver_bss *bss = priv;
-
- if (beacon == NULL)
- wpa_printf(MSG_DEBUG, "test_driver: Clear Beacon WPS IE");
- else
- wpa_hexdump_buf(MSG_DEBUG, "test_driver: Beacon WPS IE",
- beacon);
-
- os_free(bss->wps_beacon_ie);
-
- if (beacon == NULL) {
- bss->wps_beacon_ie = NULL;
- bss->wps_beacon_ie_len = 0;
- } else {
- bss->wps_beacon_ie = os_malloc(wpabuf_len(beacon));
- if (bss->wps_beacon_ie == NULL) {
- bss->wps_beacon_ie_len = 0;
- return -1;
- }
-
- os_memcpy(bss->wps_beacon_ie, wpabuf_head(beacon),
- wpabuf_len(beacon));
- bss->wps_beacon_ie_len = wpabuf_len(beacon);
- }
-
- if (proberesp == NULL)
- wpa_printf(MSG_DEBUG, "test_driver: Clear Probe Response WPS "
- "IE");
- else
- wpa_hexdump_buf(MSG_DEBUG, "test_driver: Probe Response WPS "
- "IE", proberesp);
-
- os_free(bss->wps_probe_resp_ie);
-
- if (proberesp == NULL) {
- bss->wps_probe_resp_ie = NULL;
- bss->wps_probe_resp_ie_len = 0;
- } else {
- bss->wps_probe_resp_ie = os_malloc(wpabuf_len(proberesp));
- if (bss->wps_probe_resp_ie == NULL) {
- bss->wps_probe_resp_ie_len = 0;
- return -1;
- }
-
- os_memcpy(bss->wps_probe_resp_ie, wpabuf_head(proberesp),
- wpabuf_len(proberesp));
- bss->wps_probe_resp_ie_len = wpabuf_len(proberesp);
- }
-
- return 0;
-}
-
-
-static int test_driver_sta_deauth(void *priv, const u8 *own_addr,
- const u8 *addr, int reason)
-{
- struct test_driver_bss *dbss = priv;
- struct wpa_driver_test_data *drv = dbss->drv;
- struct test_client_socket *cli;
-
- if (drv->test_socket < 0)
- return -1;
-
- cli = drv->cli;
- while (cli) {
- if (memcmp(cli->addr, addr, ETH_ALEN) == 0)
- break;
- cli = cli->next;
- }
-
- if (!cli)
- return -1;
-
- return sendto(drv->test_socket, "DEAUTH", 6, 0,
- (struct sockaddr *) &cli->un, cli->unlen);
-}
-
-
-static int test_driver_sta_disassoc(void *priv, const u8 *own_addr,
- const u8 *addr, int reason)
-{
- struct test_driver_bss *dbss = priv;
- struct wpa_driver_test_data *drv = dbss->drv;
- struct test_client_socket *cli;
-
- if (drv->test_socket < 0)
- return -1;
-
- cli = drv->cli;
- while (cli) {
- if (memcmp(cli->addr, addr, ETH_ALEN) == 0)
- break;
- cli = cli->next;
- }
-
- if (!cli)
- return -1;
-
- return sendto(drv->test_socket, "DISASSOC", 8, 0,
- (struct sockaddr *) &cli->un, cli->unlen);
-}
-
-
-static int test_driver_bss_add(void *priv, const char *ifname, const u8 *bssid,
- void *bss_ctx, void **drv_priv)
-{
- struct test_driver_bss *dbss = priv;
- struct wpa_driver_test_data *drv = dbss->drv;
- struct test_driver_bss *bss;
-
- wpa_printf(MSG_DEBUG, "%s(ifname=%s bssid=" MACSTR ")",
- __func__, ifname, MAC2STR(bssid));
-
- bss = os_zalloc(sizeof(*bss));
- if (bss == NULL)
- return -1;
-
- bss->bss_ctx = bss_ctx;
- bss->drv = drv;
- os_strlcpy(bss->ifname, ifname, IFNAMSIZ);
- os_memcpy(bss->bssid, bssid, ETH_ALEN);
-
- dl_list_add(&drv->bss, &bss->list);
- if (drv->global) {
- drv->global->bss_add_used = 1;
- os_memcpy(drv->global->req_addr, bssid, ETH_ALEN);
- }
-
- if (drv_priv)
- *drv_priv = bss;
-
- return 0;
-}
-
-
-static int test_driver_bss_remove(void *priv, const char *ifname)
-{
- struct test_driver_bss *dbss = priv;
- struct wpa_driver_test_data *drv = dbss->drv;
- struct test_driver_bss *bss;
- struct test_client_socket *cli, *prev_c;
-
- wpa_printf(MSG_DEBUG, "%s(ifname=%s)", __func__, ifname);
-
- dl_list_for_each(bss, &drv->bss, struct test_driver_bss, list) {
- if (strcmp(bss->ifname, ifname) != 0)
- continue;
-
- for (prev_c = NULL, cli = drv->cli; cli;
- prev_c = cli, cli = cli->next) {
- if (cli->bss != bss)
- continue;
- if (prev_c)
- prev_c->next = cli->next;
- else
- drv->cli = cli->next;
- os_free(cli);
- break;
- }
-
- dl_list_del(&bss->list);
- test_driver_free_bss(bss);
- return 0;
- }
-
- return -1;
-}
-
-
-static int test_driver_if_add(void *priv, enum wpa_driver_if_type type,
- const char *ifname, const u8 *addr,
- void *bss_ctx, void **drv_priv,
- char *force_ifname, u8 *if_addr,
- const char *bridge, int use_existing)
-{
- struct test_driver_bss *dbss = priv;
- struct wpa_driver_test_data *drv = dbss->drv;
-
- wpa_printf(MSG_DEBUG, "%s(type=%d ifname=%s bss_ctx=%p)",
- __func__, type, ifname, bss_ctx);
- if (addr)
- os_memcpy(if_addr, addr, ETH_ALEN);
- else {
- drv->alloc_iface_idx++;
- if_addr[0] = 0x02; /* locally administered */
- sha1_prf(drv->own_addr, ETH_ALEN,
- "hostapd test addr generation",
- (const u8 *) &drv->alloc_iface_idx,
- sizeof(drv->alloc_iface_idx),
- if_addr + 1, ETH_ALEN - 1);
- }
- if (type == WPA_IF_AP_BSS || type == WPA_IF_P2P_GO ||
- type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP)
- return test_driver_bss_add(priv, ifname, if_addr, bss_ctx,
- drv_priv);
- return 0;
-}
-
-
-static int test_driver_if_remove(void *priv, enum wpa_driver_if_type type,
- const char *ifname)
-{
- wpa_printf(MSG_DEBUG, "%s(type=%d ifname=%s)", __func__, type, ifname);
- if (type == WPA_IF_AP_BSS || type == WPA_IF_P2P_GO ||
- type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP)
- return test_driver_bss_remove(priv, ifname);
- return 0;
-}
-
-
-static int test_driver_set_ssid(void *priv, const u8 *buf, int len)
-{
- struct test_driver_bss *bss = priv;
-
- wpa_printf(MSG_DEBUG, "%s(ifname=%s)", __func__, bss->ifname);
- if (len < 0)
- return -1;
- wpa_hexdump_ascii(MSG_DEBUG, "test_driver_set_ssid: SSID", buf, len);
-
- if ((size_t) len > sizeof(bss->ssid))
- return -1;
-
- os_memcpy(bss->ssid, buf, len);
- bss->ssid_len = len;
-
- return 0;
-}
-
-
-static int test_driver_set_privacy(void *priv, int enabled)
-{
- struct test_driver_bss *dbss = priv;
-
- wpa_printf(MSG_DEBUG, "%s(enabled=%d)", __func__, enabled);
- dbss->privacy = enabled;
-
- return 0;
-}
-
-
-static int test_driver_set_sta_vlan(void *priv, const u8 *addr,
- const char *ifname, int vlan_id)
-{
- wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " ifname=%s vlan_id=%d)",
- __func__, MAC2STR(addr), ifname, vlan_id);
- return 0;
-}
-
-
-static int test_driver_sta_add(void *priv,
- struct hostapd_sta_add_params *params)
-{
- struct test_driver_bss *bss = priv;
- struct wpa_driver_test_data *drv = bss->drv;
- struct test_client_socket *cli;
-
- wpa_printf(MSG_DEBUG, "%s(ifname=%s addr=" MACSTR " aid=%d "
- "capability=0x%x listen_interval=%d)",
- __func__, bss->ifname, MAC2STR(params->addr), params->aid,
- params->capability, params->listen_interval);
- wpa_hexdump(MSG_DEBUG, "test_driver_sta_add - supp_rates",
- params->supp_rates, params->supp_rates_len);
-
- cli = drv->cli;
- while (cli) {
- if (os_memcmp(cli->addr, params->addr, ETH_ALEN) == 0)
- break;
- cli = cli->next;
- }
- if (!cli) {
- wpa_printf(MSG_DEBUG, "%s: no matching client entry",
- __func__);
- return -1;
- }
-
- cli->bss = bss;
-
- return 0;
-}
-
-
-static struct wpa_driver_test_data * test_alloc_data(void *ctx,
- const char *ifname)
-{
- struct wpa_driver_test_data *drv;
- struct test_driver_bss *bss;
-
- drv = os_zalloc(sizeof(struct wpa_driver_test_data));
- if (drv == NULL) {
- wpa_printf(MSG_ERROR, "Could not allocate memory for test "
- "driver data");
- return NULL;
- }
-
- bss = os_zalloc(sizeof(struct test_driver_bss));
- if (bss == NULL) {
- os_free(drv);
- return NULL;
- }
-
- drv->ctx = ctx;
- wpa_trace_add_ref(drv, ctx, ctx);
- dl_list_init(&drv->bss);
- dl_list_add(&drv->bss, &bss->list);
- os_strlcpy(bss->ifname, ifname, IFNAMSIZ);
- bss->bss_ctx = ctx;
- bss->drv = drv;
-
- /* Generate a MAC address to help testing with multiple STAs */
- drv->own_addr[0] = 0x02; /* locally administered */
- sha1_prf((const u8 *) ifname, os_strlen(ifname),
- "test mac addr generation",
- NULL, 0, drv->own_addr + 1, ETH_ALEN - 1);
-
- return drv;
-}
-
-
-static void * test_driver_init(struct hostapd_data *hapd,
- struct wpa_init_params *params)
-{
- struct wpa_driver_test_data *drv;
- struct sockaddr_un addr_un;
- struct sockaddr_in addr_in;
- struct sockaddr *addr;
- socklen_t alen;
- struct test_driver_bss *bss;
-
- drv = test_alloc_data(hapd, params->ifname);
- if (drv == NULL)
- return NULL;
- drv->ap = 1;
- bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
- drv->global = params->global_priv;
-
- bss->bss_ctx = hapd;
- os_memcpy(bss->bssid, drv->own_addr, ETH_ALEN);
- os_memcpy(params->own_addr, drv->own_addr, ETH_ALEN);
-
- if (params->test_socket) {
- if (os_strlen(params->test_socket) >=
- sizeof(addr_un.sun_path)) {
- printf("Too long test_socket path\n");
- wpa_driver_test_deinit(bss);
- return NULL;
- }
- if (strncmp(params->test_socket, "DIR:", 4) == 0) {
- size_t len = strlen(params->test_socket) + 30;
- drv->test_dir = os_strdup(params->test_socket + 4);
- drv->own_socket_path = os_malloc(len);
- if (drv->own_socket_path) {
- snprintf(drv->own_socket_path, len,
- "%s/AP-" MACSTR,
- params->test_socket + 4,
- MAC2STR(params->own_addr));
- }
- } else if (strncmp(params->test_socket, "UDP:", 4) == 0) {
- drv->udp_port = atoi(params->test_socket + 4);
- } else {
- drv->own_socket_path = os_strdup(params->test_socket);
- }
- if (drv->own_socket_path == NULL && drv->udp_port == 0) {
- wpa_driver_test_deinit(bss);
- return NULL;
- }
-
- drv->test_socket = socket(drv->udp_port ? PF_INET : PF_UNIX,
- SOCK_DGRAM, 0);
- if (drv->test_socket < 0) {
- perror("socket");
- wpa_driver_test_deinit(bss);
- return NULL;
- }
-
- if (drv->udp_port) {
- os_memset(&addr_in, 0, sizeof(addr_in));
- addr_in.sin_family = AF_INET;
- addr_in.sin_port = htons(drv->udp_port);
- addr = (struct sockaddr *) &addr_in;
- alen = sizeof(addr_in);
- } else {
- os_memset(&addr_un, 0, sizeof(addr_un));
- addr_un.sun_family = AF_UNIX;
- os_strlcpy(addr_un.sun_path, drv->own_socket_path,
- sizeof(addr_un.sun_path));
- addr = (struct sockaddr *) &addr_un;
- alen = sizeof(addr_un);
- }
- if (bind(drv->test_socket, addr, alen) < 0) {
- perror("test-driver-init: bind(PF_UNIX)");
- close(drv->test_socket);
- if (drv->own_socket_path)
- unlink(drv->own_socket_path);
- wpa_driver_test_deinit(bss);
- return NULL;
- }
- eloop_register_read_sock(drv->test_socket,
- test_driver_receive_unix, drv, NULL);
- } else
- drv->test_socket = -1;
-
- return bss;
-}
-
-
-static void wpa_driver_test_poll(void *eloop_ctx, void *timeout_ctx)
-{
- struct wpa_driver_test_data *drv = eloop_ctx;
-
-#ifdef DRIVER_TEST_UNIX
- if (drv->associated && drv->hostapd_addr_set) {
- struct stat st;
- if (stat(drv->hostapd_addr.sun_path, &st) < 0) {
- wpa_printf(MSG_DEBUG, "%s: lost connection to AP: %s",
- __func__, strerror(errno));
- drv->associated = 0;
- wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
- }
- }
-#endif /* DRIVER_TEST_UNIX */
-
- eloop_register_timeout(1, 0, wpa_driver_test_poll, drv, NULL);
-}
-
-
-static void wpa_driver_test_scan_timeout(void *eloop_ctx, void *timeout_ctx)
-{
- wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
- wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
-}
-
-
-#ifdef DRIVER_TEST_UNIX
-static void wpa_driver_scan_dir(struct wpa_driver_test_data *drv,
- const char *path)
-{
- struct dirent *dent;
- DIR *dir;
- struct sockaddr_un addr;
- char cmd[512], *pos, *end;
- int ret;
-
- dir = opendir(path);
- if (dir == NULL)
- return;
-
- end = cmd + sizeof(cmd);
- pos = cmd;
- ret = os_snprintf(pos, end - pos, "SCAN " MACSTR,
- MAC2STR(drv->own_addr));
- if (ret >= 0 && ret < end - pos)
- pos += ret;
- if (drv->probe_req_ie) {
- ret = os_snprintf(pos, end - pos, " ");
- if (ret >= 0 && ret < end - pos)
- pos += ret;
- pos += wpa_snprintf_hex(pos, end - pos, drv->probe_req_ie,
- drv->probe_req_ie_len);
- }
- if (drv->probe_req_ssid_len) {
- /* Add SSID IE */
- ret = os_snprintf(pos, end - pos, "%02x%02x",
- WLAN_EID_SSID,
- (unsigned int) drv->probe_req_ssid_len);
- if (ret >= 0 && ret < end - pos)
- pos += ret;
- pos += wpa_snprintf_hex(pos, end - pos, drv->probe_req_ssid,
- drv->probe_req_ssid_len);
- }
- end[-1] = '\0';
-
- while ((dent = readdir(dir))) {
- if (os_strncmp(dent->d_name, "AP-", 3) != 0 &&
- os_strncmp(dent->d_name, "STA-", 4) != 0)
- continue;
- if (drv->own_socket_path) {
- size_t olen, dlen;
- olen = os_strlen(drv->own_socket_path);
- dlen = os_strlen(dent->d_name);
- if (olen >= dlen &&
- os_strcmp(dent->d_name,
- drv->own_socket_path + olen - dlen) == 0)
- continue;
- }
- wpa_printf(MSG_DEBUG, "%s: SCAN %s", __func__, dent->d_name);
-
- os_memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- os_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s",
- path, dent->d_name);
-
- if (sendto(drv->test_socket, cmd, os_strlen(cmd), 0,
- (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("sendto(test_socket)");
- }
- }
- closedir(dir);
-}
-#endif /* DRIVER_TEST_UNIX */
-
-
-static int wpa_driver_test_scan(void *priv,
- struct wpa_driver_scan_params *params)
-{
- struct test_driver_bss *dbss = priv;
- struct wpa_driver_test_data *drv = dbss->drv;
- size_t i;
-
- wpa_printf(MSG_DEBUG, "%s: priv=%p", __func__, priv);
-
- os_free(drv->probe_req_ie);
- if (params->extra_ies) {
- drv->probe_req_ie = os_malloc(params->extra_ies_len);
- if (drv->probe_req_ie == NULL) {
- drv->probe_req_ie_len = 0;
- return -1;
- }
- os_memcpy(drv->probe_req_ie, params->extra_ies,
- params->extra_ies_len);
- drv->probe_req_ie_len = params->extra_ies_len;
- } else {
- drv->probe_req_ie = NULL;
- drv->probe_req_ie_len = 0;
- }
-
- for (i = 0; i < params->num_ssids; i++)
- wpa_hexdump(MSG_DEBUG, "Scan SSID",
- params->ssids[i].ssid, params->ssids[i].ssid_len);
- drv->probe_req_ssid_len = 0;
- if (params->num_ssids) {
- os_memcpy(drv->probe_req_ssid, params->ssids[0].ssid,
- params->ssids[0].ssid_len);
- drv->probe_req_ssid_len = params->ssids[0].ssid_len;
- }
- wpa_hexdump(MSG_DEBUG, "Scan extra IE(s)",
- params->extra_ies, params->extra_ies_len);
-
- drv->num_scanres = 0;
-
-#ifdef DRIVER_TEST_UNIX
- if (drv->test_socket >= 0 && drv->test_dir)
- wpa_driver_scan_dir(drv, drv->test_dir);
-
- if (drv->test_socket >= 0 && drv->hostapd_addr_set &&
- sendto(drv->test_socket, "SCAN", 4, 0,
- (struct sockaddr *) &drv->hostapd_addr,
- sizeof(drv->hostapd_addr)) < 0) {
- perror("sendto(test_socket)");
- }
-#endif /* DRIVER_TEST_UNIX */
-
- if (drv->test_socket >= 0 && drv->hostapd_addr_udp_set &&
- sendto(drv->test_socket, "SCAN", 4, 0,
- (struct sockaddr *) &drv->hostapd_addr_udp,
- sizeof(drv->hostapd_addr_udp)) < 0) {
- perror("sendto(test_socket)");
- }
-
- eloop_cancel_timeout(wpa_driver_test_scan_timeout, drv, drv->ctx);
- eloop_register_timeout(1, 0, wpa_driver_test_scan_timeout, drv,
- drv->ctx);
- return 0;
-}
-
-
-static struct wpa_scan_results * wpa_driver_test_get_scan_results2(void *priv)
-{
- struct test_driver_bss *dbss = priv;
- struct wpa_driver_test_data *drv = dbss->drv;
- struct wpa_scan_results *res;
- size_t i;
-
- res = os_zalloc(sizeof(*res));
- if (res == NULL)
- return NULL;
-
- res->res = os_calloc(drv->num_scanres, sizeof(struct wpa_scan_res *));
- if (res->res == NULL) {
- os_free(res);
- return NULL;
- }
-
- for (i = 0; i < drv->num_scanres; i++) {
- struct wpa_scan_res *r;
- if (drv->scanres[i] == NULL)
- continue;
- r = os_malloc(sizeof(*r) + drv->scanres[i]->ie_len);
- if (r == NULL)
- break;
- os_memcpy(r, drv->scanres[i],
- sizeof(*r) + drv->scanres[i]->ie_len);
- res->res[res->num++] = r;
- }
-
- return res;
-}
-
-
-static int wpa_driver_test_set_key(const char *ifname, void *priv,
- enum wpa_alg alg, const u8 *addr,
- int key_idx, int set_tx,
- const u8 *seq, size_t seq_len,
- const u8 *key, size_t key_len)
-{
- wpa_printf(MSG_DEBUG, "%s: ifname=%s priv=%p alg=%d key_idx=%d "
- "set_tx=%d",
- __func__, ifname, priv, alg, key_idx, set_tx);
- if (addr)
- wpa_printf(MSG_DEBUG, " addr=" MACSTR, MAC2STR(addr));
- if (seq)
- wpa_hexdump(MSG_DEBUG, " seq", seq, seq_len);
- if (key)
- wpa_hexdump_key(MSG_DEBUG, " key", key, key_len);
- return 0;
-}
-
-
-static int wpa_driver_update_mode(struct wpa_driver_test_data *drv, int ap)
-{
- if (ap && !drv->ap) {
- wpa_driver_test_close_test_socket(drv);
- wpa_driver_test_attach(drv, drv->test_dir, 1);
- drv->ap = 1;
- } else if (!ap && drv->ap) {
- wpa_driver_test_close_test_socket(drv);
- wpa_driver_test_attach(drv, drv->test_dir, 0);
- drv->ap = 0;
- }
-
- return 0;
-}
-
-
-static int wpa_driver_test_associate(
- void *priv, struct wpa_driver_associate_params *params)
-{
- struct test_driver_bss *dbss = priv;
- struct wpa_driver_test_data *drv = dbss->drv;
- wpa_printf(MSG_DEBUG, "%s: priv=%p freq=%d pairwise_suite=%d "
- "group_suite=%d key_mgmt_suite=%d auth_alg=%d mode=%d",
- __func__, priv, params->freq.freq, params->pairwise_suite,
- params->group_suite, params->key_mgmt_suite,
- params->auth_alg, params->mode);
- wpa_driver_update_mode(drv, params->mode == IEEE80211_MODE_AP);
- if (params->bssid) {
- wpa_printf(MSG_DEBUG, " bssid=" MACSTR,
- MAC2STR(params->bssid));
- }
- if (params->ssid) {
- wpa_hexdump_ascii(MSG_DEBUG, " ssid",
- params->ssid, params->ssid_len);
- }
- if (params->wpa_ie) {
- wpa_hexdump(MSG_DEBUG, " wpa_ie",
- params->wpa_ie, params->wpa_ie_len);
- drv->assoc_wpa_ie_len = params->wpa_ie_len;
- if (drv->assoc_wpa_ie_len > sizeof(drv->assoc_wpa_ie))
- drv->assoc_wpa_ie_len = sizeof(drv->assoc_wpa_ie);
- os_memcpy(drv->assoc_wpa_ie, params->wpa_ie,
- drv->assoc_wpa_ie_len);
- } else
- drv->assoc_wpa_ie_len = 0;
-
- wpa_driver_update_mode(drv, params->mode == IEEE80211_MODE_AP);
-
- drv->ibss = params->mode == IEEE80211_MODE_IBSS;
- dbss->privacy = params->key_mgmt_suite &
- (WPA_KEY_MGMT_IEEE8021X |
- WPA_KEY_MGMT_PSK |
- WPA_KEY_MGMT_WPA_NONE |
- WPA_KEY_MGMT_FT_IEEE8021X |
- WPA_KEY_MGMT_FT_PSK |
- WPA_KEY_MGMT_IEEE8021X_SHA256 |
- WPA_KEY_MGMT_PSK_SHA256);
- if (params->wep_key_len[params->wep_tx_keyidx])
- dbss->privacy = 1;
-
-#ifdef DRIVER_TEST_UNIX
- if (drv->test_dir && params->bssid &&
- params->mode != IEEE80211_MODE_IBSS) {
- os_memset(&drv->hostapd_addr, 0, sizeof(drv->hostapd_addr));
- drv->hostapd_addr.sun_family = AF_UNIX;
- os_snprintf(drv->hostapd_addr.sun_path,
- sizeof(drv->hostapd_addr.sun_path),
- "%s/AP-" MACSTR,
- drv->test_dir, MAC2STR(params->bssid));
- drv->hostapd_addr_set = 1;
- }
-#endif /* DRIVER_TEST_UNIX */
-
- if (params->mode == IEEE80211_MODE_AP) {
- if (params->ssid)
- os_memcpy(dbss->ssid, params->ssid, params->ssid_len);
- dbss->ssid_len = params->ssid_len;
- os_memcpy(dbss->bssid, drv->own_addr, ETH_ALEN);
- if (params->wpa_ie && params->wpa_ie_len) {
- dbss->ie = os_malloc(params->wpa_ie_len);
- if (dbss->ie) {
- os_memcpy(dbss->ie, params->wpa_ie,
- params->wpa_ie_len);
- dbss->ielen = params->wpa_ie_len;
- }
- }
- } else if (drv->test_socket >= 0 &&
- (drv->hostapd_addr_set || drv->hostapd_addr_udp_set)) {
- char cmd[200], *pos, *end;
- int ret;
- end = cmd + sizeof(cmd);
- pos = cmd;
- ret = os_snprintf(pos, end - pos, "ASSOC " MACSTR " ",
- MAC2STR(drv->own_addr));
- if (ret >= 0 && ret < end - pos)
- pos += ret;
- if (params->ssid)
- pos += wpa_snprintf_hex(pos, end - pos, params->ssid,
- params->ssid_len);
- ret = os_snprintf(pos, end - pos, " ");
- if (ret >= 0 && ret < end - pos)
- pos += ret;
- pos += wpa_snprintf_hex(pos, end - pos, params->wpa_ie,
- params->wpa_ie_len);
- end[-1] = '\0';
-#ifdef DRIVER_TEST_UNIX
- if (drv->hostapd_addr_set &&
- sendto(drv->test_socket, cmd, os_strlen(cmd), 0,
- (struct sockaddr *) &drv->hostapd_addr,
- sizeof(drv->hostapd_addr)) < 0) {
- perror("sendto(test_socket)");
- return -1;
- }
-#endif /* DRIVER_TEST_UNIX */
- if (drv->hostapd_addr_udp_set &&
- sendto(drv->test_socket, cmd, os_strlen(cmd), 0,
- (struct sockaddr *) &drv->hostapd_addr_udp,
- sizeof(drv->hostapd_addr_udp)) < 0) {
- perror("sendto(test_socket)");
- return -1;
- }
-
- if (params->ssid)
- os_memcpy(dbss->ssid, params->ssid, params->ssid_len);
- dbss->ssid_len = params->ssid_len;
- } else {
- drv->associated = 1;
- if (params->mode == IEEE80211_MODE_IBSS) {
- if (params->ssid)
- os_memcpy(dbss->ssid, params->ssid,
- params->ssid_len);
- dbss->ssid_len = params->ssid_len;
- if (params->bssid)
- os_memcpy(dbss->bssid, params->bssid,
- ETH_ALEN);
- else {
- os_get_random(dbss->bssid, ETH_ALEN);
- dbss->bssid[0] &= ~0x01;
- dbss->bssid[0] |= 0x02;
- }
- }
- wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
- }
-
- return 0;
-}
-
-
-static int wpa_driver_test_get_bssid(void *priv, u8 *bssid)
-{
- struct test_driver_bss *dbss = priv;
- os_memcpy(bssid, dbss->bssid, ETH_ALEN);
- return 0;
-}
-
-
-static int wpa_driver_test_get_ssid(void *priv, u8 *ssid)
-{
- struct test_driver_bss *dbss = priv;
- os_memcpy(ssid, dbss->ssid, 32);
- return dbss->ssid_len;
-}
-
-
-static int wpa_driver_test_send_disassoc(struct wpa_driver_test_data *drv)
-{
-#ifdef DRIVER_TEST_UNIX
- if (drv->test_socket >= 0 &&
- sendto(drv->test_socket, "DISASSOC", 8, 0,
- (struct sockaddr *) &drv->hostapd_addr,
- sizeof(drv->hostapd_addr)) < 0) {
- perror("sendto(test_socket)");
- return -1;
- }
-#endif /* DRIVER_TEST_UNIX */
- if (drv->test_socket >= 0 && drv->hostapd_addr_udp_set &&
- sendto(drv->test_socket, "DISASSOC", 8, 0,
- (struct sockaddr *) &drv->hostapd_addr_udp,
- sizeof(drv->hostapd_addr_udp)) < 0) {
- perror("sendto(test_socket)");
- return -1;
- }
- return 0;
-}
-
-
-static int wpa_driver_test_deauthenticate(void *priv, const u8 *addr,
- int reason_code)
-{
- struct test_driver_bss *dbss = priv;
- struct wpa_driver_test_data *drv = dbss->drv;
- wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d",
- __func__, MAC2STR(addr), reason_code);
- os_memset(dbss->bssid, 0, ETH_ALEN);
- drv->associated = 0;
- wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
- return wpa_driver_test_send_disassoc(drv);
-}
-
-
-static const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie)
-{
- const u8 *end, *pos;
-
- pos = (const u8 *) (res + 1);
- end = pos + res->ie_len;
-
- while (pos + 1 < end) {
- if (pos + 2 + pos[1] > end)
- break;
- if (pos[0] == ie)
- return pos;
- pos += 2 + pos[1];
- }
-
- return NULL;
-}
-
-
-static void wpa_driver_test_scanresp(struct wpa_driver_test_data *drv,
- struct sockaddr *from,
- socklen_t fromlen,
- const char *data)
-{
- struct wpa_scan_res *res;
- const char *pos, *pos2;
- size_t len;
- u8 *ie_pos, *ie_start, *ie_end;
-#define MAX_IE_LEN 1000
- const u8 *ds_params;
-
- wpa_printf(MSG_DEBUG, "test_driver: SCANRESP %s", data);
- if (drv->num_scanres >= MAX_SCAN_RESULTS) {
- wpa_printf(MSG_DEBUG, "test_driver: No room for the new scan "
- "result");
- return;
- }
-
- /* SCANRESP BSSID SSID IEs */
-
- res = os_zalloc(sizeof(*res) + MAX_IE_LEN);
- if (res == NULL)
- return;
- ie_start = ie_pos = (u8 *) (res + 1);
- ie_end = ie_pos + MAX_IE_LEN;
-
- if (hwaddr_aton(data, res->bssid)) {
- wpa_printf(MSG_DEBUG, "test_driver: invalid BSSID in scanres");
- os_free(res);
- return;
- }
-
- pos = data + 17;
- while (*pos == ' ')
- pos++;
- pos2 = os_strchr(pos, ' ');
- if (pos2 == NULL) {
- wpa_printf(MSG_DEBUG, "test_driver: invalid SSID termination "
- "in scanres");
- os_free(res);
- return;
- }
- len = (pos2 - pos) / 2;
- if (len > 32)
- len = 32;
- /*
- * Generate SSID IE from the SSID field since this IE is not included
- * in the main IE field.
- */
- *ie_pos++ = WLAN_EID_SSID;
- *ie_pos++ = len;
- if (hexstr2bin(pos, ie_pos, len) < 0) {
- wpa_printf(MSG_DEBUG, "test_driver: invalid SSID in scanres");
- os_free(res);
- return;
- }
- ie_pos += len;
-
- pos = pos2 + 1;
- pos2 = os_strchr(pos, ' ');
- if (pos2 == NULL)
- len = os_strlen(pos) / 2;
- else
- len = (pos2 - pos) / 2;
- if ((int) len > ie_end - ie_pos)
- len = ie_end - ie_pos;
- if (hexstr2bin(pos, ie_pos, len) < 0) {
- wpa_printf(MSG_DEBUG, "test_driver: invalid IEs in scanres");
- os_free(res);
- return;
- }
- ie_pos += len;
- res->ie_len = ie_pos - ie_start;
-
- if (pos2) {
- pos = pos2 + 1;
- while (*pos == ' ')
- pos++;
- if (os_strstr(pos, "PRIVACY"))
- res->caps |= IEEE80211_CAP_PRIVACY;
- if (os_strstr(pos, "IBSS"))
- res->caps |= IEEE80211_CAP_IBSS;
- }
-
- ds_params = wpa_scan_get_ie(res, WLAN_EID_DS_PARAMS);
- if (ds_params && ds_params[1] > 0) {
- if (ds_params[2] >= 1 && ds_params[2] <= 13)
- res->freq = 2407 + ds_params[2] * 5;
- }
-
- os_free(drv->scanres[drv->num_scanres]);
- drv->scanres[drv->num_scanres++] = res;
-}
-
-
-static void wpa_driver_test_assocresp(struct wpa_driver_test_data *drv,
- struct sockaddr *from,
- socklen_t fromlen,
- const char *data)
-{
- struct test_driver_bss *bss;
-
- bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
-
- /* ASSOCRESP BSSID <res> */
- if (hwaddr_aton(data, bss->bssid)) {
- wpa_printf(MSG_DEBUG, "test_driver: invalid BSSID in "
- "assocresp");
- }
- if (drv->use_associnfo) {
- union wpa_event_data event;
- os_memset(&event, 0, sizeof(event));
- event.assoc_info.req_ies = drv->assoc_wpa_ie;
- event.assoc_info.req_ies_len = drv->assoc_wpa_ie_len;
- wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &event);
- }
- drv->associated = 1;
- wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
-}
-
-
-static void wpa_driver_test_disassoc(struct wpa_driver_test_data *drv,
- struct sockaddr *from,
- socklen_t fromlen)
-{
- drv->associated = 0;
- wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
-}
-
-
-static void wpa_driver_test_eapol(struct wpa_driver_test_data *drv,
- struct sockaddr *from,
- socklen_t fromlen,
- const u8 *data, size_t data_len)
-{
- const u8 *src;
- struct test_driver_bss *bss;
-
- bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
-
- if (data_len > 14) {
- /* Skip Ethernet header */
- src = data + ETH_ALEN;
- data += 14;
- data_len -= 14;
- } else
- src = bss->bssid;
-
- drv_event_eapol_rx(drv->ctx, src, data, data_len);
-}
-
-
-static void wpa_driver_test_mlme(struct wpa_driver_test_data *drv,
- struct sockaddr *from,
- socklen_t fromlen,
- const u8 *data, size_t data_len)
-{
- int freq = 0, own_freq;
- union wpa_event_data event;
- const struct ieee80211_mgmt *mgmt;
- u16 fc;
- struct test_driver_bss *bss;
-
- bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
- if (data_len > 6 && os_memcmp(data, "freq=", 5) == 0) {
- size_t pos;
- for (pos = 5; pos < data_len; pos++) {
- if (data[pos] == ' ')
- break;
- }
- if (pos < data_len) {
- freq = atoi((const char *) &data[5]);
- wpa_printf(MSG_DEBUG, "test_driver(%s): MLME RX on "
- "freq %d MHz", bss->ifname, freq);
- pos++;
- data += pos;
- data_len -= pos;
- }
- }
-
- if (drv->remain_on_channel_freq)
- own_freq = drv->remain_on_channel_freq;
- else
- own_freq = drv->current_freq;
-
- if (freq && own_freq && freq != own_freq) {
- wpa_printf(MSG_DEBUG, "test_driver(%s): Ignore MLME RX on "
- "another frequency %d MHz (own %d MHz)",
- bss->ifname, freq, own_freq);
- return;
- }
-
- os_memset(&event, 0, sizeof(event));
- event.mlme_rx.buf = data;
- event.mlme_rx.len = data_len;
- event.mlme_rx.freq = freq;
- wpa_supplicant_event(drv->ctx, EVENT_MLME_RX, &event);
-
- mgmt = (const struct ieee80211_mgmt *) data;
- fc = le_to_host16(mgmt->frame_control);
-
- if (drv->probe_req_report && data_len >= 24) {
- if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
- WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_REQ) {
- os_memset(&event, 0, sizeof(event));
- event.rx_probe_req.sa = mgmt->sa;
- event.rx_probe_req.da = mgmt->da;
- event.rx_probe_req.bssid = mgmt->bssid;
- event.rx_probe_req.ie = mgmt->u.probe_req.variable;
- event.rx_probe_req.ie_len =
- data_len - (mgmt->u.probe_req.variable - data);
- wpa_supplicant_event(drv->ctx, EVENT_RX_PROBE_REQ,
- &event);
- }
- }
-}
-
-
-static void wpa_driver_test_scan_cmd(struct wpa_driver_test_data *drv,
- struct sockaddr *from,
- socklen_t fromlen,
- const u8 *data, size_t data_len)
-{
- char buf[512], *pos, *end;
- int ret;
- struct test_driver_bss *bss;
-
- bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
-
- /* data: optional [ STA-addr | ' ' | IEs(hex) ] */
-
- if (bss == NULL || !drv->ibss)
- return;
-
- pos = buf;
- end = buf + sizeof(buf);
-
- /* reply: SCANRESP BSSID SSID IEs */
- ret = snprintf(pos, end - pos, "SCANRESP " MACSTR " ",
- MAC2STR(bss->bssid));
- if (ret < 0 || ret >= end - pos)
- return;
- pos += ret;
- pos += wpa_snprintf_hex(pos, end - pos,
- bss->ssid, bss->ssid_len);
- ret = snprintf(pos, end - pos, " ");
- if (ret < 0 || ret >= end - pos)
- return;
- pos += ret;
- pos += wpa_snprintf_hex(pos, end - pos, drv->assoc_wpa_ie,
- drv->assoc_wpa_ie_len);
-
- if (bss->privacy) {
- ret = snprintf(pos, end - pos, " PRIVACY");
- if (ret < 0 || ret >= end - pos)
- return;
- pos += ret;
- }
-
- ret = snprintf(pos, end - pos, " IBSS");
- if (ret < 0 || ret >= end - pos)
- return;
- pos += ret;
-
- sendto(drv->test_socket, buf, pos - buf, 0,
- (struct sockaddr *) from, fromlen);
-}
-
-
-static void wpa_driver_test_receive_unix(int sock, void *eloop_ctx,
- void *sock_ctx)
-{
- struct wpa_driver_test_data *drv = eloop_ctx;
- char *buf;
- int res;
- struct sockaddr_storage from;
- socklen_t fromlen = sizeof(from);
- const size_t buflen = 2000;
-
- if (drv->ap) {
- test_driver_receive_unix(sock, eloop_ctx, sock_ctx);
- return;
- }
-
- buf = os_malloc(buflen);
- if (buf == NULL)
- return;
- res = recvfrom(sock, buf, buflen - 1, 0,
- (struct sockaddr *) &from, &fromlen);
- if (res < 0) {
- perror("recvfrom(test_socket)");
- os_free(buf);
- return;
- }
- buf[res] = '\0';
-
- wpa_printf(MSG_DEBUG, "test_driver: received %u bytes", res);
-
- if (os_strncmp(buf, "SCANRESP ", 9) == 0) {
- wpa_driver_test_scanresp(drv, (struct sockaddr *) &from,
- fromlen, buf + 9);
- } else if (os_strncmp(buf, "ASSOCRESP ", 10) == 0) {
- wpa_driver_test_assocresp(drv, (struct sockaddr *) &from,
- fromlen, buf + 10);
- } else if (os_strcmp(buf, "DISASSOC") == 0) {
- wpa_driver_test_disassoc(drv, (struct sockaddr *) &from,
- fromlen);
- } else if (os_strcmp(buf, "DEAUTH") == 0) {
- wpa_driver_test_disassoc(drv, (struct sockaddr *) &from,
- fromlen);
- } else if (os_strncmp(buf, "EAPOL ", 6) == 0) {
- wpa_driver_test_eapol(drv, (struct sockaddr *) &from, fromlen,
- (const u8 *) buf + 6, res - 6);
- } else if (os_strncmp(buf, "MLME ", 5) == 0) {
- wpa_driver_test_mlme(drv, (struct sockaddr *) &from, fromlen,
- (const u8 *) buf + 5, res - 5);
- } else if (os_strncmp(buf, "SCAN ", 5) == 0) {
- wpa_driver_test_scan_cmd(drv, (struct sockaddr *) &from,
- fromlen,
- (const u8 *) buf + 5, res - 5);
- } else {
- wpa_hexdump_ascii(MSG_DEBUG, "Unknown test_socket command",
- (u8 *) buf, res);
- }
- os_free(buf);
-}
-
-
-static void * wpa_driver_test_init2(void *ctx, const char *ifname,
- void *global_priv)
-{
- struct wpa_driver_test_data *drv;
- struct wpa_driver_test_global *global = global_priv;
- struct test_driver_bss *bss;
-
- drv = test_alloc_data(ctx, ifname);
- if (drv == NULL)
- return NULL;
- bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
- drv->global = global_priv;
- drv->test_socket = -1;
-
- /* Set dummy BSSID and SSID for testing. */
- bss->bssid[0] = 0x02;
- bss->bssid[1] = 0x00;
- bss->bssid[2] = 0x00;
- bss->bssid[3] = 0x00;
- bss->bssid[4] = 0x00;
- bss->bssid[5] = 0x01;
- os_memcpy(bss->ssid, "test", 5);
- bss->ssid_len = 4;
-
- if (global->bss_add_used) {
- os_memcpy(drv->own_addr, global->req_addr, ETH_ALEN);
- global->bss_add_used = 0;
- }
-
- eloop_register_timeout(1, 0, wpa_driver_test_poll, drv, NULL);
-
- return bss;
-}
-
-
-static void wpa_driver_test_close_test_socket(struct wpa_driver_test_data *drv)
-{
- if (drv->test_socket >= 0) {
- eloop_unregister_read_sock(drv->test_socket);
- close(drv->test_socket);
- drv->test_socket = -1;
- }
-
- if (drv->own_socket_path) {
- unlink(drv->own_socket_path);
- os_free(drv->own_socket_path);
- drv->own_socket_path = NULL;
- }
-}
-
-
-static void wpa_driver_test_deinit(void *priv)
-{
- struct test_driver_bss *dbss = priv;
- struct wpa_driver_test_data *drv = dbss->drv;
- struct test_client_socket *cli, *prev;
- int i;
-
- cli = drv->cli;
- while (cli) {
- prev = cli;
- cli = cli->next;
- os_free(prev);
- }
-
-#ifdef HOSTAPD
- /* There should be only one BSS remaining at this point. */
- if (dl_list_len(&drv->bss) != 1)
- wpa_printf(MSG_ERROR, "%s: %u remaining BSS entries",
- __func__, dl_list_len(&drv->bss));
-#endif /* HOSTAPD */
-
- test_driver_free_bsses(drv);
-
- wpa_driver_test_close_test_socket(drv);
- eloop_cancel_timeout(wpa_driver_test_scan_timeout, drv, drv->ctx);
- eloop_cancel_timeout(wpa_driver_test_poll, drv, NULL);
- eloop_cancel_timeout(test_remain_on_channel_timeout, drv, NULL);
- os_free(drv->test_dir);
- for (i = 0; i < MAX_SCAN_RESULTS; i++)
- os_free(drv->scanres[i]);
- os_free(drv->probe_req_ie);
- wpa_trace_remove_ref(drv, ctx, drv->ctx);
- os_free(drv);
-}
-
-
-static int wpa_driver_test_attach(struct wpa_driver_test_data *drv,
- const char *dir, int ap)
-{
-#ifdef DRIVER_TEST_UNIX
- static unsigned int counter = 0;
- struct sockaddr_un addr;
- size_t len;
-
- os_free(drv->own_socket_path);
- if (dir) {
- len = os_strlen(dir) + 30;
- drv->own_socket_path = os_malloc(len);
- if (drv->own_socket_path == NULL)
- return -1;
- os_snprintf(drv->own_socket_path, len, "%s/%s-" MACSTR,
- dir, ap ? "AP" : "STA", MAC2STR(drv->own_addr));
- } else {
- drv->own_socket_path = os_malloc(100);
- if (drv->own_socket_path == NULL)
- return -1;
- os_snprintf(drv->own_socket_path, 100,
- "/tmp/wpa_supplicant_test-%d-%d",
- getpid(), counter++);
- }
-
- drv->test_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
- if (drv->test_socket < 0) {
- perror("socket(PF_UNIX)");
- os_free(drv->own_socket_path);
- drv->own_socket_path = NULL;
- return -1;
- }
-
- os_memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- os_strlcpy(addr.sun_path, drv->own_socket_path, sizeof(addr.sun_path));
- if (bind(drv->test_socket, (struct sockaddr *) &addr,
- sizeof(addr)) < 0) {
- perror("test-driver-attach: bind(PF_UNIX)");
- close(drv->test_socket);
- unlink(drv->own_socket_path);
- os_free(drv->own_socket_path);
- drv->own_socket_path = NULL;
- return -1;
- }
-
- eloop_register_read_sock(drv->test_socket,
- wpa_driver_test_receive_unix, drv, NULL);
-
- return 0;
-#else /* DRIVER_TEST_UNIX */
- return -1;
-#endif /* DRIVER_TEST_UNIX */
-}
-
-
-static int wpa_driver_test_attach_udp(struct wpa_driver_test_data *drv,
- char *dst)
-{
- char *pos;
-
- pos = os_strchr(dst, ':');
- if (pos == NULL)
- return -1;
- *pos++ = '\0';
- wpa_printf(MSG_DEBUG, "%s: addr=%s port=%s", __func__, dst, pos);
-
- drv->test_socket = socket(PF_INET, SOCK_DGRAM, 0);
- if (drv->test_socket < 0) {
- perror("socket(PF_INET)");
- return -1;
- }
-
- os_memset(&drv->hostapd_addr_udp, 0, sizeof(drv->hostapd_addr_udp));
- drv->hostapd_addr_udp.sin_family = AF_INET;
-#if defined(CONFIG_NATIVE_WINDOWS) || defined(CONFIG_ANSI_C_EXTRA)
- {
- int a[4];
- u8 *pos;
- sscanf(dst, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]);
- pos = (u8 *) &drv->hostapd_addr_udp.sin_addr;
- *pos++ = a[0];
- *pos++ = a[1];
- *pos++ = a[2];
- *pos++ = a[3];
- }
-#else /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
- inet_aton(dst, &drv->hostapd_addr_udp.sin_addr);
-#endif /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
- drv->hostapd_addr_udp.sin_port = htons(atoi(pos));
-
- drv->hostapd_addr_udp_set = 1;
-
- eloop_register_read_sock(drv->test_socket,
- wpa_driver_test_receive_unix, drv, NULL);
-
- return 0;
-}
-
-
-static int wpa_driver_test_set_param(void *priv, const char *param)
-{
- struct test_driver_bss *dbss = priv;
- struct wpa_driver_test_data *drv = dbss->drv;
- const char *pos;
-
- wpa_printf(MSG_DEBUG, "%s: param='%s'", __func__, param);
- if (param == NULL)
- return 0;
-
- wpa_driver_test_close_test_socket(drv);
-
-#ifdef DRIVER_TEST_UNIX
- pos = os_strstr(param, "test_socket=");
- if (pos) {
- const char *pos2;
- size_t len;
-
- pos += 12;
- pos2 = os_strchr(pos, ' ');
- if (pos2)
- len = pos2 - pos;
- else
- len = os_strlen(pos);
- if (len > sizeof(drv->hostapd_addr.sun_path))
- return -1;
- os_memset(&drv->hostapd_addr, 0, sizeof(drv->hostapd_addr));
- drv->hostapd_addr.sun_family = AF_UNIX;
- os_memcpy(drv->hostapd_addr.sun_path, pos, len);
- drv->hostapd_addr_set = 1;
- }
-#endif /* DRIVER_TEST_UNIX */
-
- pos = os_strstr(param, "test_dir=");
- if (pos) {
- char *end;
- os_free(drv->test_dir);
- drv->test_dir = os_strdup(pos + 9);
- if (drv->test_dir == NULL)
- return -1;
- end = os_strchr(drv->test_dir, ' ');
- if (end)
- *end = '\0';
- if (wpa_driver_test_attach(drv, drv->test_dir, 0))
- return -1;
- } else {
- pos = os_strstr(param, "test_udp=");
- if (pos) {
- char *dst, *epos;
- dst = os_strdup(pos + 9);
- if (dst == NULL)
- return -1;
- epos = os_strchr(dst, ' ');
- if (epos)
- *epos = '\0';
- if (wpa_driver_test_attach_udp(drv, dst))
- return -1;
- os_free(dst);
- } else if (wpa_driver_test_attach(drv, NULL, 0))
- return -1;
- }
-
- if (os_strstr(param, "use_associnfo=1")) {
- wpa_printf(MSG_DEBUG, "test_driver: Use AssocInfo events");
- drv->use_associnfo = 1;
- }
-
- return 0;
-}
-
-
-static const u8 * wpa_driver_test_get_mac_addr(void *priv)
-{
- struct test_driver_bss *dbss = priv;
- struct wpa_driver_test_data *drv = dbss->drv;
- wpa_printf(MSG_DEBUG, "%s", __func__);
- return drv->own_addr;
-}
-
-
-static int wpa_driver_test_send_eapol(void *priv, const u8 *dest, u16 proto,
- const u8 *data, size_t data_len)
-{
- struct test_driver_bss *dbss = priv;
- struct wpa_driver_test_data *drv = dbss->drv;
- char *msg;
- size_t msg_len;
- struct l2_ethhdr eth;
- struct sockaddr *addr;
- socklen_t alen;
-#ifdef DRIVER_TEST_UNIX
- struct sockaddr_un addr_un;
-#endif /* DRIVER_TEST_UNIX */
-
- wpa_hexdump(MSG_MSGDUMP, "test_send_eapol TX frame", data, data_len);
-
- os_memset(ð, 0, sizeof(eth));
- os_memcpy(eth.h_dest, dest, ETH_ALEN);
- os_memcpy(eth.h_source, drv->own_addr, ETH_ALEN);
- eth.h_proto = host_to_be16(proto);
-
- msg_len = 6 + sizeof(eth) + data_len;
- msg = os_malloc(msg_len);
- if (msg == NULL)
- return -1;
- os_memcpy(msg, "EAPOL ", 6);
- os_memcpy(msg + 6, ð, sizeof(eth));
- os_memcpy(msg + 6 + sizeof(eth), data, data_len);
-
- if (os_memcmp(dest, dbss->bssid, ETH_ALEN) == 0 ||
- drv->test_dir == NULL) {
- if (drv->hostapd_addr_udp_set) {
- addr = (struct sockaddr *) &drv->hostapd_addr_udp;
- alen = sizeof(drv->hostapd_addr_udp);
- } else {
-#ifdef DRIVER_TEST_UNIX
- addr = (struct sockaddr *) &drv->hostapd_addr;
- alen = sizeof(drv->hostapd_addr);
-#else /* DRIVER_TEST_UNIX */
- os_free(msg);
- return -1;
-#endif /* DRIVER_TEST_UNIX */
- }
- } else {
-#ifdef DRIVER_TEST_UNIX
- struct stat st;
- os_memset(&addr_un, 0, sizeof(addr_un));
- addr_un.sun_family = AF_UNIX;
- os_snprintf(addr_un.sun_path, sizeof(addr_un.sun_path),
- "%s/STA-" MACSTR, drv->test_dir, MAC2STR(dest));
- if (stat(addr_un.sun_path, &st) < 0) {
- os_snprintf(addr_un.sun_path, sizeof(addr_un.sun_path),
- "%s/AP-" MACSTR,
- drv->test_dir, MAC2STR(dest));
- }
- addr = (struct sockaddr *) &addr_un;
- alen = sizeof(addr_un);
-#else /* DRIVER_TEST_UNIX */
- os_free(msg);
- return -1;
-#endif /* DRIVER_TEST_UNIX */
- }
-
- if (sendto(drv->test_socket, msg, msg_len, 0, addr, alen) < 0) {
- perror("sendmsg(test_socket)");
- os_free(msg);
- return -1;
- }
-
- os_free(msg);
- return 0;
-}
-
-
-static int wpa_driver_test_get_capa(void *priv, struct wpa_driver_capa *capa)
-{
- os_memset(capa, 0, sizeof(*capa));
- capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE |
- WPA_DRIVER_CAPA_KEY_MGMT_FT |
- WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
- capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 |
- WPA_DRIVER_CAPA_ENC_WEP104 |
- WPA_DRIVER_CAPA_ENC_TKIP |
- WPA_DRIVER_CAPA_ENC_CCMP;
- capa->auth = WPA_DRIVER_AUTH_OPEN |
- WPA_DRIVER_AUTH_SHARED |
- WPA_DRIVER_AUTH_LEAP;
- capa->flags |= WPA_DRIVER_FLAGS_AP;
- capa->flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
- capa->flags |= WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE;
- capa->flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE;
- capa->max_scan_ssids = 2;
- capa->max_remain_on_chan = 60000;
-
- return 0;
-}
-
-
-static int wpa_driver_test_mlme_setprotection(void *priv, const u8 *addr,
- int protect_type,
- int key_type)
-{
- wpa_printf(MSG_DEBUG, "%s: protect_type=%d key_type=%d",
- __func__, protect_type, key_type);
-
- if (addr) {
- wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR,
- __func__, MAC2STR(addr));
- }
-
- return 0;
-}
-
-
-static void * wpa_driver_test_global_init(void)
-{
- struct wpa_driver_test_global *global;
-
- global = os_zalloc(sizeof(*global));
- return global;
-}
-
-
-static void wpa_driver_test_global_deinit(void *priv)
-{
- struct wpa_driver_test_global *global = priv;
- os_free(global);
-}
-
-
-static struct wpa_interface_info *
-wpa_driver_test_get_interfaces(void *global_priv)
-{
- /* struct wpa_driver_test_global *global = priv; */
- struct wpa_interface_info *iface;
-
- iface = os_zalloc(sizeof(*iface));
- if (iface == NULL)
- return iface;
- iface->ifname = os_strdup("sta0");
- iface->desc = os_strdup("test interface 0");
- iface->drv_name = "test";
- iface->next = os_zalloc(sizeof(*iface));
- if (iface->next) {
- iface->next->ifname = os_strdup("sta1");
- iface->next->desc = os_strdup("test interface 1");
- iface->next->drv_name = "test";
- }
-
- return iface;
-}
-
-
-static struct hostapd_hw_modes *
-wpa_driver_test_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
-{
- struct hostapd_hw_modes *modes;
- size_t i;
-
- *num_modes = 3;
- *flags = 0;
- modes = os_calloc(*num_modes, sizeof(struct hostapd_hw_modes));
- if (modes == NULL)
- return NULL;
- modes[0].mode = HOSTAPD_MODE_IEEE80211G;
- modes[0].num_channels = 11;
- modes[0].num_rates = 12;
- modes[0].channels = os_calloc(11, sizeof(struct hostapd_channel_data));
- modes[0].rates = os_calloc(modes[0].num_rates, sizeof(int));
- if (modes[0].channels == NULL || modes[0].rates == NULL)
- goto fail;
- for (i = 0; i < 11; i++) {
- modes[0].channels[i].chan = i + 1;
- modes[0].channels[i].freq = 2412 + 5 * i;
- modes[0].channels[i].flag = 0;
- }
- modes[0].rates[0] = 10;
- modes[0].rates[1] = 20;
- modes[0].rates[2] = 55;
- modes[0].rates[3] = 110;
- modes[0].rates[4] = 60;
- modes[0].rates[5] = 90;
- modes[0].rates[6] = 120;
- modes[0].rates[7] = 180;
- modes[0].rates[8] = 240;
- modes[0].rates[9] = 360;
- modes[0].rates[10] = 480;
- modes[0].rates[11] = 540;
-
- modes[1].mode = HOSTAPD_MODE_IEEE80211B;
- modes[1].num_channels = 11;
- modes[1].num_rates = 4;
- modes[1].channels = os_calloc(11, sizeof(struct hostapd_channel_data));
- modes[1].rates = os_calloc(modes[1].num_rates, sizeof(int));
- if (modes[1].channels == NULL || modes[1].rates == NULL)
- goto fail;
- for (i = 0; i < 11; i++) {
- modes[1].channels[i].chan = i + 1;
- modes[1].channels[i].freq = 2412 + 5 * i;
- modes[1].channels[i].flag = 0;
- }
- modes[1].rates[0] = 10;
- modes[1].rates[1] = 20;
- modes[1].rates[2] = 55;
- modes[1].rates[3] = 110;
-
- modes[2].mode = HOSTAPD_MODE_IEEE80211A;
- modes[2].num_channels = 1;
- modes[2].num_rates = 8;
- modes[2].channels = os_calloc(1, sizeof(struct hostapd_channel_data));
- modes[2].rates = os_calloc(modes[2].num_rates, sizeof(int));
- if (modes[2].channels == NULL || modes[2].rates == NULL)
- goto fail;
- modes[2].channels[0].chan = 60;
- modes[2].channels[0].freq = 5300;
- modes[2].channels[0].flag = 0;
- modes[2].rates[0] = 60;
- modes[2].rates[1] = 90;
- modes[2].rates[2] = 120;
- modes[2].rates[3] = 180;
- modes[2].rates[4] = 240;
- modes[2].rates[5] = 360;
- modes[2].rates[6] = 480;
- modes[2].rates[7] = 540;
-
- return modes;
-
-fail:
- if (modes) {
- for (i = 0; i < *num_modes; i++) {
- os_free(modes[i].channels);
- os_free(modes[i].rates);
- }
- os_free(modes);
- }
- return NULL;
-}
-
-
-static int wpa_driver_test_set_freq(void *priv,
- struct hostapd_freq_params *freq)
-{
- struct test_driver_bss *dbss = priv;
- struct wpa_driver_test_data *drv = dbss->drv;
- wpa_printf(MSG_DEBUG, "test: set_freq %u MHz", freq->freq);
- drv->current_freq = freq->freq;
- return 0;
-}
-
-
-static int wpa_driver_test_send_action(void *priv, unsigned int freq,
- unsigned int wait,
- const u8 *dst, const u8 *src,
- const u8 *bssid,
- const u8 *data, size_t data_len,
- int no_cck)
-{
- struct test_driver_bss *dbss = priv;
- struct wpa_driver_test_data *drv = dbss->drv;
- int ret = -1;
- u8 *buf;
- struct ieee80211_hdr *hdr;
-
- wpa_printf(MSG_DEBUG, "test: Send Action frame");
-
- if ((drv->remain_on_channel_freq &&
- freq != drv->remain_on_channel_freq) ||
- (drv->remain_on_channel_freq == 0 &&
- freq != (unsigned int) drv->current_freq)) {
- wpa_printf(MSG_DEBUG, "test: Reject Action frame TX on "
- "unexpected channel: freq=%u MHz (current_freq=%u "
- "MHz, remain-on-channel freq=%u MHz)",
- freq, drv->current_freq,
- drv->remain_on_channel_freq);
- return -1;
- }
-
- buf = os_zalloc(24 + data_len);
- if (buf == NULL)
- return ret;
- os_memcpy(buf + 24, data, data_len);
- hdr = (struct ieee80211_hdr *) buf;
- hdr->frame_control =
- IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION);
- os_memcpy(hdr->addr1, dst, ETH_ALEN);
- os_memcpy(hdr->addr2, src, ETH_ALEN);
- os_memcpy(hdr->addr3, bssid, ETH_ALEN);
-
- ret = wpa_driver_test_send_mlme(priv, buf, 24 + data_len, 0);
- os_free(buf);
- return ret;
-}
-
-
-static void test_remain_on_channel_timeout(void *eloop_ctx, void *timeout_ctx)
-{
- struct wpa_driver_test_data *drv = eloop_ctx;
- union wpa_event_data data;
-
- wpa_printf(MSG_DEBUG, "test: Remain-on-channel timeout");
-
- os_memset(&data, 0, sizeof(data));
- data.remain_on_channel.freq = drv->remain_on_channel_freq;
- data.remain_on_channel.duration = drv->remain_on_channel_duration;
-
- drv->remain_on_channel_freq = 0;
-
- wpa_supplicant_event(drv->ctx, EVENT_CANCEL_REMAIN_ON_CHANNEL, &data);
-}
-
-
-static int wpa_driver_test_remain_on_channel(void *priv, unsigned int freq,
- unsigned int duration)
-{
- struct test_driver_bss *dbss = priv;
- struct wpa_driver_test_data *drv = dbss->drv;
- union wpa_event_data data;
-
- wpa_printf(MSG_DEBUG, "%s(freq=%u, duration=%u)",
- __func__, freq, duration);
- if (drv->remain_on_channel_freq &&
- drv->remain_on_channel_freq != freq) {
- wpa_printf(MSG_DEBUG, "test: Refuse concurrent "
- "remain_on_channel request");
- return -1;
- }
-
- drv->remain_on_channel_freq = freq;
- drv->remain_on_channel_duration = duration;
- eloop_cancel_timeout(test_remain_on_channel_timeout, drv, NULL);
- eloop_register_timeout(duration / 1000, (duration % 1000) * 1000,
- test_remain_on_channel_timeout, drv, NULL);
-
- os_memset(&data, 0, sizeof(data));
- data.remain_on_channel.freq = freq;
- data.remain_on_channel.duration = duration;
- wpa_supplicant_event(drv->ctx, EVENT_REMAIN_ON_CHANNEL, &data);
-
- return 0;
-}
-
-
-static int wpa_driver_test_cancel_remain_on_channel(void *priv)
-{
- struct test_driver_bss *dbss = priv;
- struct wpa_driver_test_data *drv = dbss->drv;
- wpa_printf(MSG_DEBUG, "%s", __func__);
- if (!drv->remain_on_channel_freq)
- return -1;
- drv->remain_on_channel_freq = 0;
- eloop_cancel_timeout(test_remain_on_channel_timeout, drv, NULL);
- return 0;
-}
-
-
-static int wpa_driver_test_probe_req_report(void *priv, int report)
-{
- struct test_driver_bss *dbss = priv;
- struct wpa_driver_test_data *drv = dbss->drv;
- wpa_printf(MSG_DEBUG, "%s(report=%d)", __func__, report);
- drv->probe_req_report = report;
- return 0;
-}
-
-
-const struct wpa_driver_ops wpa_driver_test_ops = {
- "test",
- "wpa_supplicant test driver",
- .hapd_init = test_driver_init,
- .hapd_deinit = wpa_driver_test_deinit,
- .hapd_send_eapol = test_driver_send_eapol,
- .send_mlme = wpa_driver_test_send_mlme,
- .set_generic_elem = test_driver_set_generic_elem,
- .sta_deauth = test_driver_sta_deauth,
- .sta_disassoc = test_driver_sta_disassoc,
- .get_hw_feature_data = wpa_driver_test_get_hw_feature_data,
- .if_add = test_driver_if_add,
- .if_remove = test_driver_if_remove,
- .hapd_set_ssid = test_driver_set_ssid,
- .set_privacy = test_driver_set_privacy,
- .set_sta_vlan = test_driver_set_sta_vlan,
- .sta_add = test_driver_sta_add,
- .send_ether = test_driver_send_ether,
- .set_ap_wps_ie = test_driver_set_ap_wps_ie,
- .get_bssid = wpa_driver_test_get_bssid,
- .get_ssid = wpa_driver_test_get_ssid,
- .set_key = wpa_driver_test_set_key,
- .deinit = wpa_driver_test_deinit,
- .set_param = wpa_driver_test_set_param,
- .deauthenticate = wpa_driver_test_deauthenticate,
- .associate = wpa_driver_test_associate,
- .get_capa = wpa_driver_test_get_capa,
- .get_mac_addr = wpa_driver_test_get_mac_addr,
- .send_eapol = wpa_driver_test_send_eapol,
- .mlme_setprotection = wpa_driver_test_mlme_setprotection,
- .get_scan_results2 = wpa_driver_test_get_scan_results2,
- .global_init = wpa_driver_test_global_init,
- .global_deinit = wpa_driver_test_global_deinit,
- .init2 = wpa_driver_test_init2,
- .get_interfaces = wpa_driver_test_get_interfaces,
- .scan2 = wpa_driver_test_scan,
- .set_freq = wpa_driver_test_set_freq,
- .send_action = wpa_driver_test_send_action,
- .remain_on_channel = wpa_driver_test_remain_on_channel,
- .cancel_remain_on_channel = wpa_driver_test_cancel_remain_on_channel,
- .probe_req_report = wpa_driver_test_probe_req_report,
-};
diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
index 1b3a757..a1581b8 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -78,7 +78,7 @@
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) {
- perror("ioctl[SIOCGIWAP]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWAP]: %s", strerror(errno));
ret = -1;
}
os_memcpy(bssid, iwr.u.ap_addr.sa_data, ETH_ALEN);
@@ -108,7 +108,7 @@
os_memset(iwr.u.ap_addr.sa_data, 0, ETH_ALEN);
if (ioctl(drv->ioctl_sock, SIOCSIWAP, &iwr) < 0) {
- perror("ioctl[SIOCSIWAP]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWAP]: %s", strerror(errno));
ret = -1;
}
@@ -134,7 +134,8 @@
iwr.u.essid.length = 32;
if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
- perror("ioctl[SIOCGIWESSID]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWESSID]: %s",
+ strerror(errno));
ret = -1;
} else {
ret = iwr.u.essid.length;
@@ -192,7 +193,8 @@
iwr.u.essid.length = ssid_len;
if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
- perror("ioctl[SIOCSIWESSID]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWESSID]: %s",
+ strerror(errno));
ret = -1;
}
@@ -218,7 +220,8 @@
iwr.u.freq.e = 1;
if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) {
- perror("ioctl[SIOCSIWFREQ]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWFREQ]: %s",
+ strerror(errno));
ret = -1;
}
@@ -815,7 +818,8 @@
drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
if (drv->ioctl_sock < 0) {
- perror("socket(PF_INET,SOCK_DGRAM)");
+ wpa_printf(MSG_ERROR, "socket(PF_INET,SOCK_DGRAM): %s",
+ strerror(errno));
goto err1;
}
@@ -1027,7 +1031,8 @@
}
if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) {
- perror("ioctl[SIOCSIWSCAN]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWSCAN]: %s",
+ strerror(errno));
ret = -1;
}
@@ -1082,7 +1087,8 @@
"trying larger buffer (%lu bytes)",
(unsigned long) res_buf_len);
} else {
- perror("ioctl[SIOCGIWSCAN]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWSCAN]: %s",
+ strerror(errno));
os_free(res_buf);
return NULL;
}
@@ -1533,7 +1539,8 @@
sizeof(range->enc_capa);
if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
- perror("ioctl[SIOCGIWRANGE]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWRANGE]: %s",
+ strerror(errno));
os_free(range);
return -1;
} else if (iwr.u.data.length >= minlen &&
@@ -1568,8 +1575,9 @@
drv->capa.max_scan_ssids = 1;
wpa_printf(MSG_DEBUG, " capabilities: key_mgmt 0x%x enc 0x%x "
- "flags 0x%x",
- drv->capa.key_mgmt, drv->capa.enc, drv->capa.flags);
+ "flags 0x%llx",
+ drv->capa.key_mgmt, drv->capa.enc,
+ (unsigned long long) drv->capa.flags);
} else {
wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: too old (short) data - "
"assuming WPA is not supported");
@@ -1612,7 +1620,8 @@
ret = ioctl(drv->ioctl_sock, SIOCSIWENCODEEXT, &iwr);
if (ret < 0)
- perror("ioctl[SIOCSIWENCODEEXT] PMK");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWENCODEEXT] PMK: %s",
+ strerror(errno));
os_free(ext);
return ret;
@@ -1704,7 +1713,8 @@
ret = -2;
}
- perror("ioctl[SIOCSIWENCODEEXT]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWENCODEEXT]: %s",
+ strerror(errno));
}
os_free(ext);
@@ -1778,7 +1788,8 @@
iwr.u.encoding.length = key_len;
if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
- perror("ioctl[SIOCSIWENCODE]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWENCODE]: %s",
+ strerror(errno));
ret = -1;
}
@@ -1790,7 +1801,9 @@
iwr.u.encoding.pointer = (caddr_t) NULL;
iwr.u.encoding.length = 0;
if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
- perror("ioctl[SIOCSIWENCODE] (set_tx)");
+ wpa_printf(MSG_ERROR,
+ "ioctl[SIOCSIWENCODE] (set_tx): %s",
+ strerror(errno));
ret = -1;
}
}
@@ -1839,7 +1852,8 @@
iwr.u.data.length = sizeof(mlme);
if (ioctl(drv->ioctl_sock, SIOCSIWMLME, &iwr) < 0) {
- perror("ioctl[SIOCSIWMLME]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWMLME]: %s",
+ strerror(errno));
ret = -1;
}
@@ -1862,7 +1876,8 @@
os_memset(&iwr, 0, sizeof(iwr));
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) {
- perror("ioctl[SIOCGIWMODE]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWMODE]: %s",
+ strerror(errno));
iwr.u.mode = IW_MODE_INFRA;
}
@@ -1927,7 +1942,8 @@
iwr.u.data.length = ie_len;
if (ioctl(drv->ioctl_sock, SIOCSIWGENIE, &iwr) < 0) {
- perror("ioctl[SIOCSIWGENIE]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWGENIE]: %s",
+ strerror(errno));
ret = -1;
}
@@ -2004,7 +2020,8 @@
}
if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
- perror("ioctl[SIOCSIWENCODE]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWENCODE]: %s",
+ strerror(errno));
ret = -1;
}
@@ -2060,12 +2077,12 @@
if (wpa_driver_wext_set_gen_ie(drv, params->wpa_ie, params->wpa_ie_len)
< 0)
ret = -1;
- if (params->wpa_ie == NULL || params->wpa_ie_len == 0)
- value = IW_AUTH_WPA_VERSION_DISABLED;
- else if (params->wpa_ie[0] == WLAN_EID_RSN)
+ if (params->wpa_proto & WPA_PROTO_RSN)
value = IW_AUTH_WPA_VERSION_WPA2;
- else
+ else if (params->wpa_proto & WPA_PROTO_WPA)
value = IW_AUTH_WPA_VERSION_WPA;
+ else
+ value = IW_AUTH_WPA_VERSION_DISABLED;
if (wpa_driver_wext_set_auth_param(drv,
IW_AUTH_WPA_VERSION, value) < 0)
ret = -1;
@@ -2084,7 +2101,7 @@
value = params->key_mgmt_suite != WPA_KEY_MGMT_NONE ||
params->pairwise_suite != WPA_CIPHER_NONE ||
params->group_suite != WPA_CIPHER_NONE ||
- params->wpa_ie_len;
+ (params->wpa_proto & (WPA_PROTO_RSN | WPA_PROTO_WPA));
if (wpa_driver_wext_set_auth_param(drv,
IW_AUTH_PRIVACY_INVOKED, value) < 0)
ret = -1;
@@ -2181,7 +2198,8 @@
}
if (errno != EBUSY) {
- perror("ioctl[SIOCSIWMODE]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWMODE]: %s",
+ strerror(errno));
goto done;
}
@@ -2190,7 +2208,8 @@
* down, try to set the mode again, and bring it back up.
*/
if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) {
- perror("ioctl[SIOCGIWMODE]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIWMODE]: %s",
+ strerror(errno));
goto done;
}
@@ -2203,7 +2222,8 @@
/* Try to set the mode again while the interface is down */
iwr.u.mode = new_mode;
if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0)
- perror("ioctl[SIOCSIWMODE]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWMODE]: %s",
+ strerror(errno));
else
ret = 0;
@@ -2236,7 +2256,8 @@
if (ioctl(drv->ioctl_sock, SIOCSIWPMKSA, &iwr) < 0) {
if (errno != EOPNOTSUPP)
- perror("ioctl[SIOCSIWPMKSA]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPMKSA]: %s",
+ strerror(errno));
ret = -1;
}
@@ -2352,6 +2373,33 @@
}
+static int wpa_driver_wext_status(void *priv, char *buf, size_t buflen)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ int res;
+ char *pos, *end;
+ unsigned char addr[ETH_ALEN];
+
+ pos = buf;
+ end = buf + buflen;
+
+ if (linux_get_ifhwaddr(drv->ioctl_sock, drv->ifname, addr))
+ return -1;
+
+ res = os_snprintf(pos, end - pos,
+ "ifindex=%d\n"
+ "ifname=%s\n"
+ "addr=" MACSTR "\n",
+ drv->ifindex,
+ drv->ifname,
+ MAC2STR(addr));
+ if (os_snprintf_error(end - pos, res))
+ return pos - buf;
+ pos += res;
+
+ return pos - buf;
+}
+
const struct wpa_driver_ops wpa_driver_wext_ops = {
.name = "wext",
.desc = "Linux wireless extensions (generic)",
@@ -2372,4 +2420,5 @@
.set_operstate = wpa_driver_wext_set_operstate,
.get_radio_name = wext_get_radio_name,
.signal_poll = wpa_driver_wext_signal_poll,
+ .status = wpa_driver_wext_status,
};
diff --git a/src/drivers/driver_wired.c b/src/drivers/driver_wired.c
index 21f5e42..f95f3cc 100644
--- a/src/drivers/driver_wired.c
+++ b/src/drivers/driver_wired.c
@@ -100,7 +100,7 @@
if (setsockopt(sock, SOL_PACKET,
add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP,
&mreq, sizeof(mreq)) < 0) {
- perror("setsockopt");
+ wpa_printf(MSG_ERROR, "setsockopt: %s", strerror(errno));
return -1;
}
return 0;
@@ -158,7 +158,7 @@
len = recv(sock, buf, sizeof(buf), 0);
if (len < 0) {
- perror("recv");
+ wpa_printf(MSG_ERROR, "recv: %s", strerror(errno));
return;
}
@@ -176,7 +176,7 @@
len = recv(sock, buf, sizeof(buf), 0);
if (len < 0) {
- perror("recv");
+ wpa_printf(MSG_ERROR, "recv: %s", strerror(errno));
return;
}
@@ -209,19 +209,21 @@
drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE));
if (drv->sock < 0) {
- perror("socket[PF_PACKET,SOCK_RAW]");
+ wpa_printf(MSG_ERROR, "socket[PF_PACKET,SOCK_RAW]: %s",
+ strerror(errno));
return -1;
}
if (eloop_register_read_sock(drv->sock, handle_read, drv->ctx, NULL)) {
- printf("Could not register read socket\n");
+ wpa_printf(MSG_INFO, "Could not register read socket");
return -1;
}
os_memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) {
- perror("ioctl(SIOCGIFINDEX)");
+ wpa_printf(MSG_ERROR, "ioctl(SIOCGIFINDEX): %s",
+ strerror(errno));
return -1;
}
@@ -232,7 +234,7 @@
addr.sll_ifindex);
if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("bind");
+ wpa_printf(MSG_ERROR, "bind: %s", strerror(errno));
return -1;
}
@@ -247,26 +249,28 @@
os_memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
if (ioctl(drv->sock, SIOCGIFHWADDR, &ifr) != 0) {
- perror("ioctl(SIOCGIFHWADDR)");
+ wpa_printf(MSG_ERROR, "ioctl(SIOCGIFHWADDR): %s",
+ strerror(errno));
return -1;
}
if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
- printf("Invalid HW-addr family 0x%04x\n",
- ifr.ifr_hwaddr.sa_family);
+ wpa_printf(MSG_INFO, "Invalid HW-addr family 0x%04x",
+ ifr.ifr_hwaddr.sa_family);
return -1;
}
os_memcpy(own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
/* setup dhcp listen socket for sta detection */
if ((drv->dhcp_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
- perror("socket call failed for dhcp");
+ wpa_printf(MSG_ERROR, "socket call failed for dhcp: %s",
+ strerror(errno));
return -1;
}
if (eloop_register_read_sock(drv->dhcp_sock, handle_dhcp, drv->ctx,
NULL)) {
- printf("Could not register read socket\n");
+ wpa_printf(MSG_INFO, "Could not register read socket");
return -1;
}
@@ -277,12 +281,14 @@
if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_REUSEADDR, (char *) &n,
sizeof(n)) == -1) {
- perror("setsockopt[SOL_SOCKET,SO_REUSEADDR]");
+ wpa_printf(MSG_ERROR, "setsockopt[SOL_SOCKET,SO_REUSEADDR]: %s",
+ strerror(errno));
return -1;
}
if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BROADCAST, (char *) &n,
sizeof(n)) == -1) {
- perror("setsockopt[SOL_SOCKET,SO_BROADCAST]");
+ wpa_printf(MSG_ERROR, "setsockopt[SOL_SOCKET,SO_BROADCAST]: %s",
+ strerror(errno));
return -1;
}
@@ -290,13 +296,15 @@
os_strlcpy(ifr.ifr_ifrn.ifrn_name, drv->ifname, IFNAMSIZ);
if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BINDTODEVICE,
(char *) &ifr, sizeof(ifr)) < 0) {
- perror("setsockopt[SOL_SOCKET,SO_BINDTODEVICE]");
+ wpa_printf(MSG_ERROR,
+ "setsockopt[SOL_SOCKET,SO_BINDTODEVICE]: %s",
+ strerror(errno));
return -1;
}
if (bind(drv->dhcp_sock, (struct sockaddr *) &addr2,
sizeof(struct sockaddr)) == -1) {
- perror("bind");
+ wpa_printf(MSG_ERROR, "bind: %s", strerror(errno));
return -1;
}
@@ -320,8 +328,9 @@
len = sizeof(*hdr) + data_len;
hdr = os_zalloc(len);
if (hdr == NULL) {
- printf("malloc() failed for wired_send_eapol(len=%lu)\n",
- (unsigned long) len);
+ wpa_printf(MSG_INFO,
+ "malloc() failed for wired_send_eapol(len=%lu)",
+ (unsigned long) len);
return -1;
}
@@ -337,9 +346,9 @@
os_free(hdr);
if (res < 0) {
- perror("wired_send_eapol: send");
- printf("wired_send_eapol - packet len: %lu - failed\n",
- (unsigned long) len);
+ wpa_printf(MSG_ERROR,
+ "wired_send_eapol - packet len: %lu - failed: send: %s",
+ (unsigned long) len, strerror(errno));
}
return res;
@@ -353,7 +362,8 @@
drv = os_zalloc(sizeof(struct wpa_driver_wired_data));
if (drv == NULL) {
- printf("Could not allocate memory for wired driver data\n");
+ wpa_printf(MSG_INFO,
+ "Could not allocate memory for wired driver data");
return NULL;
}
@@ -374,11 +384,15 @@
{
struct wpa_driver_wired_data *drv = priv;
- if (drv->sock >= 0)
+ if (drv->sock >= 0) {
+ eloop_unregister_read_sock(drv->sock);
close(drv->sock);
+ }
- if (drv->dhcp_sock >= 0)
+ if (drv->dhcp_sock >= 0) {
+ eloop_unregister_read_sock(drv->dhcp_sock);
close(drv->dhcp_sock);
+ }
os_free(drv);
}
@@ -414,14 +428,15 @@
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s < 0) {
- perror("socket");
+ wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
return -1;
}
os_memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
- perror("ioctl[SIOCGIFFLAGS]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIFFLAGS]: %s",
+ strerror(errno));
close(s);
return -1;
}
@@ -438,7 +453,7 @@
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s < 0) {
- perror("socket");
+ wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
return -1;
}
@@ -446,7 +461,8 @@
os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
ifr.ifr_flags = flags & 0xffff;
if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
- perror("ioctl[SIOCSIFFLAGS]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s",
+ strerror(errno));
close(s);
return -1;
}
@@ -463,14 +479,15 @@
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s < 0) {
- perror("socket");
+ wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
return -1;
}
os_memset(&ifmr, 0, sizeof(ifmr));
os_strlcpy(ifmr.ifm_name, ifname, IFNAMSIZ);
if (ioctl(s, SIOCGIFMEDIA, (caddr_t) &ifmr) < 0) {
- perror("ioctl[SIOCGIFMEDIA]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOCGIFMEDIA]: %s",
+ strerror(errno));
close(s);
return -1;
}
@@ -494,7 +511,7 @@
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s < 0) {
- perror("socket");
+ wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
return -1;
}
@@ -528,7 +545,8 @@
#endif /* defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) */
if (ioctl(s, add ? SIOCADDMULTI : SIOCDELMULTI, (caddr_t) &ifr) < 0) {
- perror("ioctl[SIOC{ADD/DEL}MULTI]");
+ wpa_printf(MSG_ERROR, "ioctl[SIOC{ADD/DEL}MULTI]: %s",
+ strerror(errno));
close(s);
return -1;
}
@@ -551,7 +569,7 @@
#ifdef __linux__
drv->pf_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
if (drv->pf_sock < 0)
- perror("socket(PF_PACKET)");
+ wpa_printf(MSG_ERROR, "socket(PF_PACKET): %s", strerror(errno));
#else /* __linux__ */
drv->pf_sock = -1;
#endif /* __linux__ */
diff --git a/src/drivers/drivers.c b/src/drivers/drivers.c
index d0e42ec..f0c3bb3 100644
--- a/src/drivers/drivers.c
+++ b/src/drivers/drivers.c
@@ -19,9 +19,6 @@
#ifdef CONFIG_DRIVER_HOSTAP
extern struct wpa_driver_ops wpa_driver_hostap_ops; /* driver_hostap.c */
#endif /* CONFIG_DRIVER_HOSTAP */
-#ifdef CONFIG_DRIVER_MADWIFI
-extern struct wpa_driver_ops wpa_driver_madwifi_ops; /* driver_madwifi.c */
-#endif /* CONFIG_DRIVER_MADWIFI */
#ifdef CONFIG_DRIVER_BSD
extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */
#endif /* CONFIG_DRIVER_BSD */
@@ -38,9 +35,6 @@
/* driver_macsec_qca.c */
extern struct wpa_driver_ops wpa_driver_macsec_qca_ops;
#endif /* CONFIG_DRIVER_MACSEC_QCA */
-#ifdef CONFIG_DRIVER_TEST
-extern struct wpa_driver_ops wpa_driver_test_ops; /* driver_test.c */
-#endif /* CONFIG_DRIVER_TEST */
#ifdef CONFIG_DRIVER_ROBOSWITCH
/* driver_roboswitch.c */
extern struct wpa_driver_ops wpa_driver_roboswitch_ops;
@@ -64,9 +58,6 @@
#ifdef CONFIG_DRIVER_HOSTAP
&wpa_driver_hostap_ops,
#endif /* CONFIG_DRIVER_HOSTAP */
-#ifdef CONFIG_DRIVER_MADWIFI
- &wpa_driver_madwifi_ops,
-#endif /* CONFIG_DRIVER_MADWIFI */
#ifdef CONFIG_DRIVER_BSD
&wpa_driver_bsd_ops,
#endif /* CONFIG_DRIVER_BSD */
@@ -82,9 +73,6 @@
#ifdef CONFIG_DRIVER_MACSEC_QCA
&wpa_driver_macsec_qca_ops,
#endif /* CONFIG_DRIVER_MACSEC_QCA */
-#ifdef CONFIG_DRIVER_TEST
- &wpa_driver_test_ops,
-#endif /* CONFIG_DRIVER_TEST */
#ifdef CONFIG_DRIVER_ROBOSWITCH
&wpa_driver_roboswitch_ops,
#endif /* CONFIG_DRIVER_ROBOSWITCH */
diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak
index cdb913e..ab392bc 100644
--- a/src/drivers/drivers.mak
+++ b/src/drivers/drivers.mak
@@ -25,6 +25,10 @@
ifdef CONFIG_DRIVER_NL80211
DRV_CFLAGS += -DCONFIG_DRIVER_NL80211
DRV_OBJS += ../src/drivers/driver_nl80211.o
+DRV_OBJS += ../src/drivers/driver_nl80211_capa.o
+DRV_OBJS += ../src/drivers/driver_nl80211_event.o
+DRV_OBJS += ../src/drivers/driver_nl80211_monitor.o
+DRV_OBJS += ../src/drivers/driver_nl80211_scan.o
DRV_OBJS += ../src/utils/radiotap.o
NEED_SME=y
NEED_AP_MLME=y
@@ -72,12 +76,6 @@
DRV_OBJS += ../src/drivers/driver_openbsd.o
endif
-ifdef CONFIG_DRIVER_TEST
-DRV_CFLAGS += -DCONFIG_DRIVER_TEST
-DRV_OBJS += ../src/drivers/driver_test.o
-NEED_AP_MLME=y
-endif
-
ifdef CONFIG_DRIVER_NONE
DRV_CFLAGS += -DCONFIG_DRIVER_NONE
DRV_OBJS += ../src/drivers/driver_none.o
@@ -94,15 +92,6 @@
NEED_LINUX_IOCTL=y
endif
-ifdef CONFIG_DRIVER_MADWIFI
-DRV_AP_CFLAGS += -DCONFIG_DRIVER_MADWIFI
-DRV_AP_OBJS += ../src/drivers/driver_madwifi.o
-CONFIG_WIRELESS_EXTENSION=y
-CONFIG_L2_PACKET=linux
-NEED_NETLINK=y
-NEED_LINUX_IOCTL=y
-endif
-
ifdef CONFIG_DRIVER_ATHEROS
DRV_AP_CFLAGS += -DCONFIG_DRIVER_ATHEROS
DRV_AP_OBJS += ../src/drivers/driver_atheros.o
diff --git a/src/drivers/drivers.mk b/src/drivers/drivers.mk
index 9fa70d9..8da4c53 100644
--- a/src/drivers/drivers.mk
+++ b/src/drivers/drivers.mk
@@ -20,6 +20,11 @@
ifdef CONFIG_DRIVER_NL80211
DRV_CFLAGS += -DCONFIG_DRIVER_NL80211
DRV_OBJS += src/drivers/driver_nl80211.c
+DRV_OBJS += src/drivers/driver_nl80211_android.c
+DRV_OBJS += src/drivers/driver_nl80211_capa.c
+DRV_OBJS += src/drivers/driver_nl80211_event.c
+DRV_OBJS += src/drivers/driver_nl80211_monitor.c
+DRV_OBJS += src/drivers/driver_nl80211_scan.c
DRV_OBJS += src/utils/radiotap.c
NEED_SME=y
NEED_AP_MLME=y
@@ -67,12 +72,6 @@
DRV_OBJS += src/drivers/driver_openbsd.c
endif
-ifdef CONFIG_DRIVER_TEST
-DRV_CFLAGS += -DCONFIG_DRIVER_TEST
-DRV_OBJS += src/drivers/driver_test.c
-NEED_AP_MLME=y
-endif
-
ifdef CONFIG_DRIVER_NONE
DRV_CFLAGS += -DCONFIG_DRIVER_NONE
DRV_OBJS += src/drivers/driver_none.c
@@ -89,15 +88,6 @@
NEED_LINUX_IOCTL=y
endif
-ifdef CONFIG_DRIVER_MADWIFI
-DRV_AP_CFLAGS += -DCONFIG_DRIVER_MADWIFI
-DRV_AP_OBJS += src/drivers/driver_madwifi.c
-CONFIG_WIRELESS_EXTENSION=y
-CONFIG_L2_PACKET=linux
-NEED_NETLINK=y
-NEED_LINUX_IOCTL=y
-endif
-
ifdef CONFIG_DRIVER_ATHEROS
DRV_AP_CFLAGS += -DCONFIG_DRIVER_ATHEROS
DRV_AP_OBJS += src/drivers/driver_atheros.c
diff --git a/src/drivers/linux_defines.h b/src/drivers/linux_defines.h
new file mode 100644
index 0000000..a107479
--- /dev/null
+++ b/src/drivers/linux_defines.h
@@ -0,0 +1,46 @@
+/*
+ * Linux defines for values that are not yet included in common C libraries
+ * Copyright (c) 2014, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef LINUX_DEFINES_H
+#define LINUX_DEFINES_H
+
+#ifndef SO_WIFI_STATUS
+# if defined(__sparc__)
+# define SO_WIFI_STATUS 0x0025
+# elif defined(__parisc__)
+# define SO_WIFI_STATUS 0x4022
+# else
+# define SO_WIFI_STATUS 41
+# endif
+
+# define SCM_WIFI_STATUS SO_WIFI_STATUS
+#endif
+
+#ifndef SO_EE_ORIGIN_TXSTATUS
+#define SO_EE_ORIGIN_TXSTATUS 4
+#endif
+
+#ifndef PACKET_TX_TIMESTAMP
+#define PACKET_TX_TIMESTAMP 16
+#endif
+
+#ifndef IFF_LOWER_UP
+#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */
+#endif
+#ifndef IFF_DORMANT
+#define IFF_DORMANT 0x20000 /* driver signals dormant */
+#endif
+
+#ifndef IF_OPER_DORMANT
+#define IF_OPER_DORMANT 5
+#endif
+#ifndef IF_OPER_UP
+#define IF_OPER_UP 6
+#endif
+
+#endif /* LINUX_DEFINES_H */
diff --git a/src/drivers/linux_wext.h b/src/drivers/linux_wext.h
index 55cf955..e7c7001 100644
--- a/src/drivers/linux_wext.h
+++ b/src/drivers/linux_wext.h
@@ -19,13 +19,13 @@
#define _LINUX_SOCKET_H
#define _LINUX_IF_H
-#include <sys/types.h>
+#include <stdint.h>
#include <net/if.h>
-typedef __uint32_t __u32;
-typedef __int32_t __s32;
-typedef __uint16_t __u16;
-typedef __int16_t __s16;
-typedef __uint8_t __u8;
+typedef uint32_t __u32;
+typedef int32_t __s32;
+typedef uint16_t __u16;
+typedef int16_t __s16;
+typedef uint8_t __u8;
#ifndef __user
#define __user
#endif /* __user */
diff --git a/src/drivers/netlink.c b/src/drivers/netlink.c
index 2fa20b1..0e960f4 100644
--- a/src/drivers/netlink.c
+++ b/src/drivers/netlink.c
@@ -199,8 +199,7 @@
rta->rta_type = IFLA_LINKMODE;
rta->rta_len = RTA_LENGTH(sizeof(char));
*((char *) RTA_DATA(rta)) = linkmode;
- req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
- RTA_LENGTH(sizeof(char));
+ req.hdr.nlmsg_len += RTA_SPACE(sizeof(char));
}
if (operstate != -1) {
rta = aliasing_hide_typecast(
@@ -209,8 +208,7 @@
rta->rta_type = IFLA_OPERSTATE;
rta->rta_len = RTA_LENGTH(sizeof(char));
*((char *) RTA_DATA(rta)) = operstate;
- req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
- RTA_LENGTH(sizeof(char));
+ req.hdr.nlmsg_len += RTA_SPACE(sizeof(char));
}
wpa_printf(MSG_DEBUG, "netlink: Operstate: ifindex=%d linkmode=%d (%s), operstate=%d (%s)",
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 4b28dc0..b37bd5a 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -227,7 +227,11 @@
* the interface identified by %NL80211_ATTR_IFINDEX.
* @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC
* or, if no MAC address given, all stations, on the interface identified
- * by %NL80211_ATTR_IFINDEX.
+ * by %NL80211_ATTR_IFINDEX. %NL80211_ATTR_MGMT_SUBTYPE and
+ * %NL80211_ATTR_REASON_CODE can optionally be used to specify which type
+ * of disconnection indication should be sent to the station
+ * (Deauthentication or Disassociation frame and reason code for that
+ * frame).
*
* @NL80211_CMD_GET_MPATH: Get mesh path attributes for mesh path to
* destination %NL80211_ATTR_MAC on the interface identified by
@@ -639,7 +643,18 @@
* @NL80211_CMD_CH_SWITCH_NOTIFY: An AP or GO may decide to switch channels
* independently of the userspace SME, send this event indicating
* %NL80211_ATTR_IFINDEX is now on %NL80211_ATTR_WIPHY_FREQ and the
- * attributes determining channel width.
+ * attributes determining channel width. This indication may also be
+ * sent when a remotely-initiated switch (e.g., when a STA receives a CSA
+ * from the remote AP) is completed;
+ *
+ * @NL80211_CMD_CH_SWITCH_STARTED_NOTIFY: Notify that a channel switch
+ * has been started on an interface, regardless of the initiator
+ * (ie. whether it was requested from a remote device or
+ * initiated on our own). It indicates that
+ * %NL80211_ATTR_IFINDEX will be on %NL80211_ATTR_WIPHY_FREQ
+ * after %NL80211_ATTR_CH_SWITCH_COUNT TBTT's. The userspace may
+ * decide to react to this indication by requesting other
+ * interfaces to change channel as well.
*
* @NL80211_CMD_START_P2P_DEVICE: Start the given P2P Device, identified by
* its %NL80211_ATTR_WDEV identifier. It must have been created with
@@ -738,6 +753,27 @@
* before removing a station entry entirely, or before disassociating
* or similar, cleanup will happen in the driver/device in this case.
*
+ * @NL80211_CMD_GET_MPP: Get mesh path attributes for mesh proxy path to
+ * destination %NL80211_ATTR_MAC on the interface identified by
+ * %NL80211_ATTR_IFINDEX.
+ *
+ * @NL80211_CMD_JOIN_OCB: Join the OCB network. The center frequency and
+ * bandwidth of a channel must be given.
+ * @NL80211_CMD_LEAVE_OCB: Leave the OCB network -- no special arguments, the
+ * network is determined by the network interface.
+ *
+ * @NL80211_CMD_TDLS_CHANNEL_SWITCH: Start channel-switching with a TDLS peer,
+ * identified by the %NL80211_ATTR_MAC parameter. A target channel is
+ * provided via %NL80211_ATTR_WIPHY_FREQ and other attributes determining
+ * channel width/type. The target operating class is given via
+ * %NL80211_ATTR_OPER_CLASS.
+ * The driver is responsible for continually initiating channel-switching
+ * operations and returning to the base channel for communication with the
+ * AP.
+ * @NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH: Stop channel-switching with a TDLS
+ * peer given by %NL80211_ATTR_MAC. Both peers must be on the base channel
+ * when this command completes.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -912,6 +948,16 @@
NL80211_CMD_ADD_TX_TS,
NL80211_CMD_DEL_TX_TS,
+ NL80211_CMD_GET_MPP,
+
+ NL80211_CMD_JOIN_OCB,
+ NL80211_CMD_LEAVE_OCB,
+
+ NL80211_CMD_CH_SWITCH_STARTED_NOTIFY,
+
+ NL80211_CMD_TDLS_CHANNEL_SWITCH,
+ NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -1606,9 +1652,9 @@
* @NL80211_ATTR_TDLS_PEER_CAPABILITY: flags for TDLS peer capabilities, u32.
* As specified in the &enum nl80211_tdls_peer_capability.
*
- * @NL80211_ATTR_IFACE_SOCKET_OWNER: flag attribute, if set during interface
+ * @NL80211_ATTR_SOCKET_OWNER: Flag attribute, if set during interface
* creation then the new interface will be owned by the netlink socket
- * that created it and will be destroyed when the socket is closed
+ * that created it and will be destroyed when the socket is closed.
*
* @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
* the TDLS link initiator.
@@ -1638,6 +1684,11 @@
* @NL80211_ATTR_SMPS_MODE: SMPS mode to use (ap mode). see
* &enum nl80211_smps_mode.
*
+ * @NL80211_ATTR_OPER_CLASS: operating class
+ *
+ * @NL80211_ATTR_MAC_MASK: MAC address mask
+ *
+ * @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -1973,7 +2024,7 @@
NL80211_ATTR_TDLS_PEER_CAPABILITY,
- NL80211_ATTR_IFACE_SOCKET_OWNER,
+ NL80211_ATTR_SOCKET_OWNER,
NL80211_ATTR_CSA_C_OFFSETS_TX,
NL80211_ATTR_MAX_CSA_COUNTERS,
@@ -1990,15 +2041,21 @@
NL80211_ATTR_SMPS_MODE,
+ NL80211_ATTR_OPER_CLASS,
+
+ NL80211_ATTR_MAC_MASK,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
+ NUM_NL80211_ATTR = __NL80211_ATTR_AFTER_LAST,
NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
};
/* source-level API compatibility */
#define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION
#define NL80211_ATTR_MESH_PARAMS NL80211_ATTR_MESH_CONFIG
+#define NL80211_ATTR_IFACE_SOCKET_OWNER NL80211_ATTR_SOCKET_OWNER
/*
* Allow user space programs to use #ifdef on new attributes by defining them
@@ -2064,6 +2121,8 @@
* and therefore can't be created in the normal ways, use the
* %NL80211_CMD_START_P2P_DEVICE and %NL80211_CMD_STOP_P2P_DEVICE
* commands to create and destroy one
+ * @NL80211_IF_TYPE_OCB: Outside Context of a BSS
+ * This mode corresponds to the MIB variable dot11OCBActivated=true
* @NL80211_IFTYPE_MAX: highest interface type number currently defined
* @NUM_NL80211_IFTYPES: number of defined interface types
*
@@ -2083,6 +2142,7 @@
NL80211_IFTYPE_P2P_CLIENT,
NL80211_IFTYPE_P2P_GO,
NL80211_IFTYPE_P2P_DEVICE,
+ NL80211_IFTYPE_OCB,
/* keep last */
NUM_NL80211_IFTYPES,
@@ -2631,6 +2691,11 @@
* @NL80211_RRF_AUTO_BW: maximum available bandwidth should be calculated
* base on contiguous rules and wider channels will be allowed to cross
* multiple contiguous/overlapping frequency ranges.
+ * @NL80211_RRF_GO_CONCURRENT: See &NL80211_FREQUENCY_ATTR_GO_CONCURRENT
+ * @NL80211_RRF_NO_HT40MINUS: channels can't be used in HT40- operation
+ * @NL80211_RRF_NO_HT40PLUS: channels can't be used in HT40+ operation
+ * @NL80211_RRF_NO_80MHZ: 80MHz operation not allowed
+ * @NL80211_RRF_NO_160MHZ: 160MHz operation not allowed
*/
enum nl80211_reg_rule_flags {
NL80211_RRF_NO_OFDM = 1<<0,
@@ -2643,11 +2708,18 @@
NL80211_RRF_NO_IR = 1<<7,
__NL80211_RRF_NO_IBSS = 1<<8,
NL80211_RRF_AUTO_BW = 1<<11,
+ NL80211_RRF_GO_CONCURRENT = 1<<12,
+ NL80211_RRF_NO_HT40MINUS = 1<<13,
+ NL80211_RRF_NO_HT40PLUS = 1<<14,
+ NL80211_RRF_NO_80MHZ = 1<<15,
+ NL80211_RRF_NO_160MHZ = 1<<16,
};
#define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR
#define NL80211_RRF_NO_IBSS NL80211_RRF_NO_IR
#define NL80211_RRF_NO_IR NL80211_RRF_NO_IR
+#define NL80211_RRF_NO_HT40 (NL80211_RRF_NO_HT40MINUS |\
+ NL80211_RRF_NO_HT40PLUS)
/* For backport compatibility with older userspace */
#define NL80211_RRF_NO_IR_ALL (NL80211_RRF_NO_IR | __NL80211_RRF_NO_IBSS)
@@ -3379,6 +3451,8 @@
* interval in which %NL80211_ATTR_CQM_TXE_PKTS and
* %NL80211_ATTR_CQM_TXE_RATE must be satisfied before generating an
* %NL80211_CMD_NOTIFY_CQM. Set to 0 to turn off TX error reporting.
+ * @NL80211_ATTR_CQM_BEACON_LOSS_EVENT: flag attribute that's set in a beacon
+ * loss event
* @__NL80211_ATTR_CQM_AFTER_LAST: internal
* @NL80211_ATTR_CQM_MAX: highest key attribute
*/
@@ -3391,6 +3465,7 @@
NL80211_ATTR_CQM_TXE_RATE,
NL80211_ATTR_CQM_TXE_PKTS,
NL80211_ATTR_CQM_TXE_INTVL,
+ NL80211_ATTR_CQM_BEACON_LOSS_EVENT,
/* keep last */
__NL80211_ATTR_CQM_AFTER_LAST,
@@ -3403,9 +3478,7 @@
* configured threshold
* @NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH: The RSSI is higher than the
* configured threshold
- * @NL80211_CQM_RSSI_BEACON_LOSS_EVENT: The device experienced beacon loss.
- * (Note that deauth/disassoc will still follow if the AP is not
- * available. This event might get used as roaming event, etc.)
+ * @NL80211_CQM_RSSI_BEACON_LOSS_EVENT: (reserved, never sent)
*/
enum nl80211_cqm_rssi_threshold_event {
NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
@@ -3545,6 +3618,25 @@
* @NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS: For wakeup reporting only,
* the TCP connection ran out of tokens to use for data to send to the
* service
+ * @NL80211_WOWLAN_TRIG_NET_DETECT: wake up when a configured network
+ * is detected. This is a nested attribute that contains the
+ * same attributes used with @NL80211_CMD_START_SCHED_SCAN. It
+ * specifies how the scan is performed (e.g. the interval and the
+ * channels to scan) as well as the scan results that will
+ * trigger a wake (i.e. the matchsets).
+ * @NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS: nested attribute
+ * containing an array with information about what triggered the
+ * wake up. If no elements are present in the array, it means
+ * that the information is not available. If more than one
+ * element is present, it means that more than one match
+ * occurred.
+ * Each element in the array is a nested attribute that contains
+ * one optional %NL80211_ATTR_SSID attribute and one optional
+ * %NL80211_ATTR_SCAN_FREQUENCIES attribute. At least one of
+ * these attributes must be present. If
+ * %NL80211_ATTR_SCAN_FREQUENCIES contains more than one
+ * frequency, it means that the match occurred in more than one
+ * channel.
* @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers
* @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number
*
@@ -3570,6 +3662,8 @@
NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH,
NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST,
NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS,
+ NL80211_WOWLAN_TRIG_NET_DETECT,
+ NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS,
/* keep last */
NUM_NL80211_WOWLAN_TRIG,
@@ -4042,6 +4136,27 @@
* multiplexing powersave, ie. can turn off all but one chain
* and then wake the rest up as required after, for example,
* rts/cts handshake.
+ * @NL80211_FEATURE_SUPPORTS_WMM_ADMISSION: the device supports setting up WMM
+ * TSPEC sessions (TID aka TSID 0-7) with the %NL80211_CMD_ADD_TX_TS
+ * command. Standard IEEE 802.11 TSPEC setup is not yet supported, it
+ * needs to be able to handle Block-Ack agreements and other things.
+ * @NL80211_FEATURE_MAC_ON_CREATE: Device supports configuring
+ * the vif's MAC address upon creation.
+ * See 'macaddr' field in the vif_params (cfg80211.h).
+ * @NL80211_FEATURE_TDLS_CHANNEL_SWITCH: Driver supports channel switching when
+ * operating as a TDLS peer.
+ * @NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR: This device/driver supports using a
+ * random MAC address during scan (if the device is unassociated); the
+ * %NL80211_SCAN_FLAG_RANDOM_ADDR flag may be set for scans and the MAC
+ * address mask/value will be used.
+ * @NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR: This device/driver supports
+ * using a random MAC address for every scan iteration during scheduled
+ * scan (while not associated), the %NL80211_SCAN_FLAG_RANDOM_ADDR may
+ * be set for scheduled scan and the MAC address mask/value will be used.
+ * @NL80211_FEATURE_ND_RANDOM_MAC_ADDR: This device/driver supports using a
+ * random MAC address for every scan iteration during "net detect", i.e.
+ * scan in unassociated WoWLAN, the %NL80211_SCAN_FLAG_RANDOM_ADDR may
+ * be set for scheduled scan and the MAC address mask/value will be used.
*/
enum nl80211_feature_flags {
NL80211_FEATURE_SK_TX_STATUS = 1 << 0,
@@ -4070,6 +4185,12 @@
NL80211_FEATURE_ACKTO_ESTIMATION = 1 << 23,
NL80211_FEATURE_STATIC_SMPS = 1 << 24,
NL80211_FEATURE_DYNAMIC_SMPS = 1 << 25,
+ NL80211_FEATURE_SUPPORTS_WMM_ADMISSION = 1 << 26,
+ NL80211_FEATURE_MAC_ON_CREATE = 1 << 27,
+ NL80211_FEATURE_TDLS_CHANNEL_SWITCH = 1 << 28,
+ NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR = 1 << 29,
+ NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR = 1 << 30,
+ NL80211_FEATURE_ND_RANDOM_MAC_ADDR = 1 << 31,
};
/**
@@ -4118,11 +4239,21 @@
* dangerous because will destroy stations performance as a lot of frames
* will be lost while scanning off-channel, therefore it must be used only
* when really needed
+ * @NL80211_SCAN_FLAG_RANDOM_ADDR: use a random MAC address for this scan (or
+ * for scheduled scan: a different one for every scan iteration). When the
+ * flag is set, depending on device capabilities the @NL80211_ATTR_MAC and
+ * @NL80211_ATTR_MAC_MASK attributes may also be given in which case only
+ * the masked bits will be preserved from the MAC address and the remainder
+ * randomised. If the attributes are not given full randomisation (46 bits,
+ * locally administered 1, multicast 0) is assumed.
+ * This flag must not be requested when the feature isn't supported, check
+ * the nl80211 feature flags for the device.
*/
enum nl80211_scan_flags {
NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0,
NL80211_SCAN_FLAG_FLUSH = 1<<1,
NL80211_SCAN_FLAG_AP = 1<<2,
+ NL80211_SCAN_FLAG_RANDOM_ADDR = 1<<3,
};
/**
diff --git a/src/drivers/priv_netlink.h b/src/drivers/priv_netlink.h
index 6232088..d3f091c 100644
--- a/src/drivers/priv_netlink.h
+++ b/src/drivers/priv_netlink.h
@@ -68,6 +68,7 @@
((attrlen) -= RTA_ALIGN((rta)->rta_len), \
(struct rtattr *) (((char *)(rta)) + RTA_ALIGN((rta)->rta_len)))
#define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len))
+#define RTA_SPACE(len) RTA_ALIGN(RTA_LENGTH(len))
#define RTA_DATA(rta) ((void *) (((char *) (rta)) + RTA_LENGTH(0)))
#define RTA_PAYLOAD(rta) ((int) ((rta)->rta_len) - RTA_LENGTH(0))
diff --git a/src/eap_common/eap_common.c b/src/eap_common/eap_common.c
index 7b077cb..1de1328 100644
--- a/src/eap_common/eap_common.c
+++ b/src/eap_common/eap_common.c
@@ -1,6 +1,6 @@
/*
* EAP common peer/server definitions
- * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -203,3 +203,86 @@
return ((const u8 *) wpabuf_head(msg))[sizeof(struct eap_hdr)];
}
+
+
+#ifdef CONFIG_ERP
+int erp_parse_tlvs(const u8 *pos, const u8 *end, struct erp_tlvs *tlvs,
+ int stop_at_keyname)
+{
+ os_memset(tlvs, 0, sizeof(*tlvs));
+
+ while (pos < end) {
+ u8 tlv_type, tlv_len;
+
+ tlv_type = *pos++;
+ switch (tlv_type) {
+ case EAP_ERP_TV_RRK_LIFETIME:
+ case EAP_ERP_TV_RMSK_LIFETIME:
+ /* 4-octet TV */
+ if (pos + 4 > end) {
+ wpa_printf(MSG_DEBUG, "EAP: Too short TV");
+ return -1;
+ }
+ pos += 4;
+ break;
+ case EAP_ERP_TLV_DOMAIN_NAME:
+ case EAP_ERP_TLV_KEYNAME_NAI:
+ case EAP_ERP_TLV_CRYPTOSUITES:
+ case EAP_ERP_TLV_AUTHORIZATION_INDICATION:
+ case EAP_ERP_TLV_CALLED_STATION_ID:
+ case EAP_ERP_TLV_CALLING_STATION_ID:
+ case EAP_ERP_TLV_NAS_IDENTIFIER:
+ case EAP_ERP_TLV_NAS_IP_ADDRESS:
+ case EAP_ERP_TLV_NAS_IPV6_ADDRESS:
+ if (pos >= end) {
+ wpa_printf(MSG_DEBUG, "EAP: Too short TLV");
+ return -1;
+ }
+ tlv_len = *pos++;
+ if (tlv_len > (unsigned) (end - pos)) {
+ wpa_printf(MSG_DEBUG, "EAP: Truncated TLV");
+ return -1;
+ }
+ if (tlv_type == EAP_ERP_TLV_KEYNAME_NAI) {
+ if (tlvs->keyname) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: More than one keyName-NAI");
+ return -1;
+ }
+ tlvs->keyname = pos;
+ tlvs->keyname_len = tlv_len;
+ if (stop_at_keyname)
+ return 0;
+ } else if (tlv_type == EAP_ERP_TLV_DOMAIN_NAME) {
+ tlvs->domain = pos;
+ tlvs->domain_len = tlv_len;
+ }
+ pos += tlv_len;
+ break;
+ default:
+ if (tlv_type >= 128 && tlv_type <= 191) {
+ /* Undefined TLV */
+ if (pos >= end) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Too short TLV");
+ return -1;
+ }
+ tlv_len = *pos++;
+ if (tlv_len > (unsigned) (end - pos)) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Truncated TLV");
+ return -1;
+ }
+ pos += tlv_len;
+ break;
+ }
+ wpa_printf(MSG_DEBUG, "EAP: Unknown TV/TLV type %u",
+ tlv_type);
+ pos = end;
+ break;
+ }
+ }
+
+ return 0;
+}
+#endif /* CONFIG_ERP */
diff --git a/src/eap_common/eap_common.h b/src/eap_common/eap_common.h
index 8850c1f..e62f167 100644
--- a/src/eap_common/eap_common.h
+++ b/src/eap_common/eap_common.h
@@ -1,6 +1,6 @@
/*
* EAP common peer/server definitions
- * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -11,6 +11,14 @@
#include "wpabuf.h"
+struct erp_tlvs {
+ const u8 *keyname;
+ const u8 *domain;
+
+ u8 keyname_len;
+ u8 domain_len;
+};
+
int eap_hdr_len_valid(const struct wpabuf *msg, size_t min_payload);
const u8 * eap_hdr_validate(int vendor, EapType eap_type,
const struct wpabuf *msg, size_t *plen);
@@ -19,5 +27,7 @@
void eap_update_len(struct wpabuf *msg);
u8 eap_get_id(const struct wpabuf *msg);
EapType eap_get_type(const struct wpabuf *msg);
+int erp_parse_tlvs(const u8 *pos, const u8 *end, struct erp_tlvs *tlvs,
+ int stop_at_keyname);
#endif /* EAP_COMMON_H */
diff --git a/src/eap_common/eap_defs.h b/src/eap_common/eap_defs.h
index 4f14a01..54f26ca 100644
--- a/src/eap_common/eap_defs.h
+++ b/src/eap_common/eap_defs.h
@@ -1,6 +1,6 @@
/*
* EAP server/peer: Shared EAP definitions
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -27,11 +27,39 @@
#endif /* _MSC_VER */
enum { EAP_CODE_REQUEST = 1, EAP_CODE_RESPONSE = 2, EAP_CODE_SUCCESS = 3,
- EAP_CODE_FAILURE = 4 };
+ EAP_CODE_FAILURE = 4, EAP_CODE_INITIATE = 5, EAP_CODE_FINISH = 6 };
/* EAP Request and Response data begins with one octet Type. Success and
* Failure do not have additional data. */
+/* Type field in EAP-Initiate and EAP-Finish messages */
+enum eap_erp_type {
+ EAP_ERP_TYPE_REAUTH_START = 1,
+ EAP_ERP_TYPE_REAUTH = 2,
+};
+
+/* ERP TV/TLV types */
+enum eap_erp_tlv_type {
+ EAP_ERP_TLV_KEYNAME_NAI = 1,
+ EAP_ERP_TV_RRK_LIFETIME = 2,
+ EAP_ERP_TV_RMSK_LIFETIME = 3,
+ EAP_ERP_TLV_DOMAIN_NAME = 4,
+ EAP_ERP_TLV_CRYPTOSUITES = 5,
+ EAP_ERP_TLV_AUTHORIZATION_INDICATION = 6,
+ EAP_ERP_TLV_CALLED_STATION_ID = 128,
+ EAP_ERP_TLV_CALLING_STATION_ID = 129,
+ EAP_ERP_TLV_NAS_IDENTIFIER = 130,
+ EAP_ERP_TLV_NAS_IP_ADDRESS = 131,
+ EAP_ERP_TLV_NAS_IPV6_ADDRESS = 132,
+};
+
+/* ERP Cryptosuite */
+enum eap_erp_cryptosuite {
+ EAP_ERP_CS_HMAC_SHA256_64 = 1,
+ EAP_ERP_CS_HMAC_SHA256_128 = 2,
+ EAP_ERP_CS_HMAC_SHA256_256 = 3,
+};
+
/*
* EAP Method Types as allocated by IANA:
* http://www.iana.org/assignments/eap-numbers
@@ -84,5 +112,7 @@
#define EAP_MSK_LEN 64
#define EAP_EMSK_LEN 64
+#define EAP_EMSK_NAME_LEN 8
+#define ERP_MAX_KEY_LEN 64
#endif /* EAP_DEFS_H */
diff --git a/src/eap_common/eap_pax_common.c b/src/eap_common/eap_pax_common.c
index b3bbacc..0e80ef5 100644
--- a/src/eap_common/eap_pax_common.c
+++ b/src/eap_common/eap_pax_common.c
@@ -121,10 +121,11 @@
* @mk: Buffer for the derived Master Key
* @ck: Buffer for the derived Confirmation Key
* @ick: Buffer for the derived Integrity Check Key
+ * @mid: Buffer for the derived Method ID
* Returns: 0 on success, -1 on failure
*/
int eap_pax_initial_key_derivation(u8 mac_id, const u8 *ak, const u8 *e,
- u8 *mk, u8 *ck, u8 *ick)
+ u8 *mk, u8 *ck, u8 *ick, u8 *mid)
{
wpa_printf(MSG_DEBUG, "EAP-PAX: initial key derivation");
if (eap_pax_kdf(mac_id, ak, EAP_PAX_AK_LEN, "Master Key",
@@ -132,13 +133,16 @@
eap_pax_kdf(mac_id, mk, EAP_PAX_MK_LEN, "Confirmation Key",
e, 2 * EAP_PAX_RAND_LEN, EAP_PAX_CK_LEN, ck) ||
eap_pax_kdf(mac_id, mk, EAP_PAX_MK_LEN, "Integrity Check Key",
- e, 2 * EAP_PAX_RAND_LEN, EAP_PAX_ICK_LEN, ick))
+ e, 2 * EAP_PAX_RAND_LEN, EAP_PAX_ICK_LEN, ick) ||
+ eap_pax_kdf(mac_id, mk, EAP_PAX_MK_LEN, "Method ID",
+ e, 2 * EAP_PAX_RAND_LEN, EAP_PAX_MID_LEN, mid))
return -1;
wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: AK", ak, EAP_PAX_AK_LEN);
wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: MK", mk, EAP_PAX_MK_LEN);
wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: CK", ck, EAP_PAX_CK_LEN);
wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: ICK", ick, EAP_PAX_ICK_LEN);
+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: MID", mid, EAP_PAX_MID_LEN);
return 0;
}
diff --git a/src/eap_common/eap_pax_common.h b/src/eap_common/eap_pax_common.h
index fb03df2..e6cdf4d 100644
--- a/src/eap_common/eap_pax_common.h
+++ b/src/eap_common/eap_pax_common.h
@@ -74,6 +74,7 @@
#define EAP_PAX_MK_LEN 16
#define EAP_PAX_CK_LEN 16
#define EAP_PAX_ICK_LEN 16
+#define EAP_PAX_MID_LEN 16
int eap_pax_kdf(u8 mac_id, const u8 *key, size_t key_len,
@@ -86,6 +87,6 @@
const u8 *data3, size_t data3_len,
u8 *mac);
int eap_pax_initial_key_derivation(u8 mac_id, const u8 *ak, const u8 *e,
- u8 *mk, u8 *ck, u8 *ick);
+ u8 *mk, u8 *ck, u8 *ick, u8 *mid);
#endif /* EAP_PAX_COMMON_H */
diff --git a/src/eap_common/ikev2_common.c b/src/eap_common/ikev2_common.c
index 3d4fb6f..4f9e64e 100644
--- a/src/eap_common/ikev2_common.c
+++ b/src/eap_common/ikev2_common.c
@@ -251,25 +251,29 @@
os_memset(payloads, 0, sizeof(*payloads));
while (next_payload != IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) {
- int plen, pdatalen;
+ unsigned int plen, pdatalen, left;
const u8 *pdata;
wpa_printf(MSG_DEBUG, "IKEV2: Processing payload %u",
next_payload);
- if (end - pos < (int) sizeof(*phdr)) {
+ if (end < pos)
+ return -1;
+ left = end - pos;
+ if (left < sizeof(*phdr)) {
wpa_printf(MSG_INFO, "IKEV2: Too short message for "
"payload header (left=%ld)",
(long) (end - pos));
+ return -1;
}
phdr = (const struct ikev2_payload_hdr *) pos;
plen = WPA_GET_BE16(phdr->payload_length);
- if (plen < (int) sizeof(*phdr) || pos + plen > end) {
+ if (plen < sizeof(*phdr) || plen > left) {
wpa_printf(MSG_INFO, "IKEV2: Invalid payload header "
"length %d", plen);
return -1;
}
wpa_printf(MSG_DEBUG, "IKEV2: Next Payload: %u Flags: 0x%x"
- " Payload Length: %d",
+ " Payload Length: %u",
phdr->next_payload, phdr->flags, plen);
pdata = (const u8 *) (phdr + 1);
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index 9880d3b..62cd4a1 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -23,6 +23,7 @@
#include "ext_password.h"
#include "crypto/crypto.h"
#include "crypto/tls.h"
+#include "crypto/sha256.h"
#include "common/wpa_ctrl.h"
#include "eap_common/eap_wsc_common.h"
#include "eap_i.h"
@@ -190,6 +191,8 @@
sm->num_rounds = 0;
sm->prev_failure = 0;
sm->expected_failure = 0;
+ sm->reauthInit = FALSE;
+ sm->erp_seq = (u32) -1;
}
@@ -353,6 +356,267 @@
}
+#ifdef CONFIG_ERP
+
+static char * eap_home_realm(struct eap_sm *sm)
+{
+ struct eap_peer_config *config = eap_get_config(sm);
+ char *realm;
+ size_t i, realm_len;
+
+ if (!config)
+ return NULL;
+
+ if (config->identity) {
+ for (i = 0; i < config->identity_len; i++) {
+ if (config->identity[i] == '@')
+ break;
+ }
+ if (i < config->identity_len) {
+ realm_len = config->identity_len - i - 1;
+ realm = os_malloc(realm_len + 1);
+ if (realm == NULL)
+ return NULL;
+ os_memcpy(realm, &config->identity[i + 1], realm_len);
+ realm[realm_len] = '\0';
+ return realm;
+ }
+ }
+
+ if (config->anonymous_identity) {
+ for (i = 0; i < config->anonymous_identity_len; i++) {
+ if (config->anonymous_identity[i] == '@')
+ break;
+ }
+ if (i < config->anonymous_identity_len) {
+ realm_len = config->anonymous_identity_len - i - 1;
+ realm = os_malloc(realm_len + 1);
+ if (realm == NULL)
+ return NULL;
+ os_memcpy(realm, &config->anonymous_identity[i + 1],
+ realm_len);
+ realm[realm_len] = '\0';
+ return realm;
+ }
+ }
+
+ return os_strdup("");
+}
+
+
+static struct eap_erp_key *
+eap_erp_get_key(struct eap_sm *sm, const char *realm)
+{
+ struct eap_erp_key *erp;
+
+ dl_list_for_each(erp, &sm->erp_keys, struct eap_erp_key, list) {
+ char *pos;
+
+ pos = os_strchr(erp->keyname_nai, '@');
+ if (!pos)
+ continue;
+ pos++;
+ if (os_strcmp(pos, realm) == 0)
+ return erp;
+ }
+
+ return NULL;
+}
+
+
+static struct eap_erp_key *
+eap_erp_get_key_nai(struct eap_sm *sm, const char *nai)
+{
+ struct eap_erp_key *erp;
+
+ dl_list_for_each(erp, &sm->erp_keys, struct eap_erp_key, list) {
+ if (os_strcmp(erp->keyname_nai, nai) == 0)
+ return erp;
+ }
+
+ return NULL;
+}
+
+
+static void eap_peer_erp_free_key(struct eap_erp_key *erp)
+{
+ dl_list_del(&erp->list);
+ bin_clear_free(erp, sizeof(*erp));
+}
+
+
+static void eap_erp_remove_keys_realm(struct eap_sm *sm, const char *realm)
+{
+ struct eap_erp_key *erp;
+
+ while ((erp = eap_erp_get_key(sm, realm)) != NULL) {
+ wpa_printf(MSG_DEBUG, "EAP: Delete old ERP key %s",
+ erp->keyname_nai);
+ eap_peer_erp_free_key(erp);
+ }
+}
+
+#endif /* CONFIG_ERP */
+
+
+void eap_peer_erp_free_keys(struct eap_sm *sm)
+{
+#ifdef CONFIG_ERP
+ struct eap_erp_key *erp, *tmp;
+
+ dl_list_for_each_safe(erp, tmp, &sm->erp_keys, struct eap_erp_key, list)
+ eap_peer_erp_free_key(erp);
+#endif /* CONFIG_ERP */
+}
+
+
+static void eap_peer_erp_init(struct eap_sm *sm)
+{
+#ifdef CONFIG_ERP
+ u8 *emsk = NULL;
+ size_t emsk_len = 0;
+ u8 EMSKname[EAP_EMSK_NAME_LEN];
+ u8 len[2];
+ char *realm;
+ size_t realm_len, nai_buf_len;
+ struct eap_erp_key *erp = NULL;
+ int pos;
+
+ realm = eap_home_realm(sm);
+ if (!realm)
+ return;
+ realm_len = os_strlen(realm);
+ wpa_printf(MSG_DEBUG, "EAP: Realm for ERP keyName-NAI: %s", realm);
+ eap_erp_remove_keys_realm(sm, realm);
+
+ nai_buf_len = 2 * EAP_EMSK_NAME_LEN + 1 + realm_len;
+ if (nai_buf_len > 253) {
+ /*
+ * keyName-NAI has a maximum length of 253 octet to fit in
+ * RADIUS attributes.
+ */
+ wpa_printf(MSG_DEBUG,
+ "EAP: Too long realm for ERP keyName-NAI maximum length");
+ goto fail;
+ }
+ nai_buf_len++; /* null termination */
+ erp = os_zalloc(sizeof(*erp) + nai_buf_len);
+ if (erp == NULL)
+ goto fail;
+
+ emsk = sm->m->get_emsk(sm, sm->eap_method_priv, &emsk_len);
+ if (!emsk || emsk_len == 0 || emsk_len > ERP_MAX_KEY_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: No suitable EMSK available for ERP");
+ goto fail;
+ }
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP: EMSK", emsk, emsk_len);
+
+ WPA_PUT_BE16(len, 8);
+ if (hmac_sha256_kdf(sm->eapSessionId, sm->eapSessionIdLen, "EMSK",
+ len, sizeof(len),
+ EMSKname, EAP_EMSK_NAME_LEN) < 0) {
+ wpa_printf(MSG_DEBUG, "EAP: Could not derive EMSKname");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "EAP: EMSKname", EMSKname, EAP_EMSK_NAME_LEN);
+
+ pos = wpa_snprintf_hex(erp->keyname_nai, nai_buf_len,
+ EMSKname, EAP_EMSK_NAME_LEN);
+ erp->keyname_nai[pos] = '@';
+ os_memcpy(&erp->keyname_nai[pos + 1], realm, realm_len);
+
+ WPA_PUT_BE16(len, emsk_len);
+ if (hmac_sha256_kdf(emsk, emsk_len,
+ "EAP Re-authentication Root Key@ietf.org",
+ len, sizeof(len), erp->rRK, emsk_len) < 0) {
+ wpa_printf(MSG_DEBUG, "EAP: Could not derive rRK for ERP");
+ goto fail;
+ }
+ erp->rRK_len = emsk_len;
+ wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rRK", erp->rRK, erp->rRK_len);
+
+ if (hmac_sha256_kdf(erp->rRK, erp->rRK_len,
+ "EAP Re-authentication Integrity Key@ietf.org",
+ len, sizeof(len), erp->rIK, erp->rRK_len) < 0) {
+ wpa_printf(MSG_DEBUG, "EAP: Could not derive rIK for ERP");
+ goto fail;
+ }
+ erp->rIK_len = erp->rRK_len;
+ wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rIK", erp->rIK, erp->rIK_len);
+
+ wpa_printf(MSG_DEBUG, "EAP: Stored ERP keys %s", erp->keyname_nai);
+ dl_list_add(&sm->erp_keys, &erp->list);
+ erp = NULL;
+fail:
+ bin_clear_free(emsk, emsk_len);
+ bin_clear_free(erp, sizeof(*erp));
+ os_free(realm);
+#endif /* CONFIG_ERP */
+}
+
+
+#ifdef CONFIG_ERP
+static int eap_peer_erp_reauth_start(struct eap_sm *sm,
+ const struct eap_hdr *hdr, size_t len)
+{
+ char *realm;
+ struct eap_erp_key *erp;
+ struct wpabuf *msg;
+ u8 hash[SHA256_MAC_LEN];
+
+ realm = eap_home_realm(sm);
+ if (!realm)
+ return -1;
+
+ erp = eap_erp_get_key(sm, realm);
+ os_free(realm);
+ realm = NULL;
+ if (!erp)
+ return -1;
+
+ if (erp->next_seq >= 65536)
+ return -1; /* SEQ has range of 0..65535 */
+
+ /* TODO: check rRK lifetime expiration */
+
+ wpa_printf(MSG_DEBUG, "EAP: Valid ERP key found %s (SEQ=%u)",
+ erp->keyname_nai, erp->next_seq);
+
+ msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_ERP_TYPE_REAUTH,
+ 1 + 2 + 2 + os_strlen(erp->keyname_nai) + 1 + 16,
+ EAP_CODE_INITIATE, hdr->identifier);
+ if (msg == NULL)
+ return -1;
+
+ wpabuf_put_u8(msg, 0x20); /* Flags: R=0 B=0 L=1 */
+ wpabuf_put_be16(msg, erp->next_seq);
+
+ wpabuf_put_u8(msg, EAP_ERP_TLV_KEYNAME_NAI);
+ wpabuf_put_u8(msg, os_strlen(erp->keyname_nai));
+ wpabuf_put_str(msg, erp->keyname_nai);
+
+ wpabuf_put_u8(msg, EAP_ERP_CS_HMAC_SHA256_128); /* Cryptosuite */
+
+ if (hmac_sha256(erp->rIK, erp->rIK_len,
+ wpabuf_head(msg), wpabuf_len(msg), hash) < 0) {
+ wpabuf_free(msg);
+ return -1;
+ }
+ wpabuf_put_data(msg, hash, 16);
+
+ wpa_printf(MSG_DEBUG, "EAP: Sending EAP-Initiate/Re-auth");
+ sm->erp_seq = erp->next_seq;
+ erp->next_seq++;
+ wpabuf_free(sm->eapRespData);
+ sm->eapRespData = msg;
+ sm->reauthInit = TRUE;
+ return 0;
+}
+#endif /* CONFIG_ERP */
+
+
/*
* The method processing happens here. The request from the authenticator is
* processed, and an appropriate response packet is built.
@@ -414,6 +678,8 @@
if (sm->m->isKeyAvailable && sm->m->getKey &&
sm->m->isKeyAvailable(sm, sm->eap_method_priv)) {
+ struct eap_peer_config *config = eap_get_config(sm);
+
eap_sm_free_key(sm);
sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv,
&sm->eapKeyDataLen);
@@ -426,6 +692,8 @@
wpa_hexdump(MSG_DEBUG, "EAP: Session-Id",
sm->eapSessionId, sm->eapSessionIdLen);
}
+ if (config->erp && sm->m->get_emsk && sm->eapSessionId)
+ eap_peer_erp_init(sm);
}
}
@@ -450,6 +718,7 @@
}
eapol_set_bool(sm, EAPOL_eapReq, FALSE);
eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
+ sm->reauthInit = FALSE;
}
@@ -709,6 +978,8 @@
else if (sm->selectedMethod == EAP_TYPE_LEAP &&
(sm->rxSuccess || sm->rxResp))
SM_ENTER(EAP, METHOD);
+ else if (sm->reauthInit)
+ SM_ENTER(EAP, SEND_RESPONSE);
else
SM_ENTER(EAP, DISCARD);
}
@@ -1231,6 +1502,219 @@
}
+static void eap_peer_initiate(struct eap_sm *sm, const struct eap_hdr *hdr,
+ size_t len)
+{
+#ifdef CONFIG_ERP
+ const u8 *pos = (const u8 *) (hdr + 1);
+ const u8 *end = ((const u8 *) hdr) + len;
+ struct erp_tlvs parse;
+
+ if (len < sizeof(*hdr) + 1) {
+ wpa_printf(MSG_DEBUG, "EAP: Ignored too short EAP-Initiate");
+ return;
+ }
+
+ if (*pos != EAP_ERP_TYPE_REAUTH_START) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Ignored unexpected EAP-Initiate Type=%u",
+ *pos);
+ return;
+ }
+
+ pos++;
+ if (pos >= end) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Too short EAP-Initiate/Re-auth-Start");
+ return;
+ }
+ pos++; /* Reserved */
+ wpa_hexdump(MSG_DEBUG, "EAP: EAP-Initiate/Re-auth-Start TVs/TLVs",
+ pos, end - pos);
+
+ if (erp_parse_tlvs(pos, end, &parse, 0) < 0)
+ goto invalid;
+
+ if (parse.domain) {
+ wpa_hexdump_ascii(MSG_DEBUG,
+ "EAP: EAP-Initiate/Re-auth-Start - Domain name",
+ parse.domain, parse.domain_len);
+ /* TODO: Derivation of domain specific keys for local ER */
+ }
+
+ if (eap_peer_erp_reauth_start(sm, hdr, len) == 0)
+ return;
+
+invalid:
+#endif /* CONFIG_ERP */
+ wpa_printf(MSG_DEBUG,
+ "EAP: EAP-Initiate/Re-auth-Start - No suitable ERP keys available - try to start full EAP authentication");
+ eapol_set_bool(sm, EAPOL_eapTriggerStart, TRUE);
+}
+
+
+static void eap_peer_finish(struct eap_sm *sm, const struct eap_hdr *hdr,
+ size_t len)
+{
+#ifdef CONFIG_ERP
+ const u8 *pos = (const u8 *) (hdr + 1);
+ const u8 *end = ((const u8 *) hdr) + len;
+ const u8 *start;
+ struct erp_tlvs parse;
+ u8 flags;
+ u16 seq;
+ u8 hash[SHA256_MAC_LEN];
+ size_t hash_len;
+ struct eap_erp_key *erp;
+ int max_len;
+ char nai[254];
+ u8 seed[4];
+ int auth_tag_ok = 0;
+
+ if (len < sizeof(*hdr) + 1) {
+ wpa_printf(MSG_DEBUG, "EAP: Ignored too short EAP-Finish");
+ return;
+ }
+
+ if (*pos != EAP_ERP_TYPE_REAUTH) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Ignored unexpected EAP-Finish Type=%u", *pos);
+ return;
+ }
+
+ if (len < sizeof(*hdr) + 4) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Ignored too short EAP-Finish/Re-auth");
+ return;
+ }
+
+ pos++;
+ flags = *pos++;
+ seq = WPA_GET_BE16(pos);
+ pos += 2;
+ wpa_printf(MSG_DEBUG, "EAP: Flags=0x%x SEQ=%u", flags, seq);
+
+ if (seq != sm->erp_seq) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Unexpected EAP-Finish/Re-auth SEQ=%u", seq);
+ return;
+ }
+
+ /*
+ * Parse TVs/TLVs. Since we do not yet know the length of the
+ * Authentication Tag, stop parsing if an unknown TV/TLV is seen and
+ * just try to find the keyName-NAI first so that we can check the
+ * Authentication Tag.
+ */
+ if (erp_parse_tlvs(pos, end, &parse, 1) < 0)
+ return;
+
+ if (!parse.keyname) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: No keyName-NAI in EAP-Finish/Re-auth Packet");
+ return;
+ }
+
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Finish/Re-auth - keyName-NAI",
+ parse.keyname, parse.keyname_len);
+ if (parse.keyname_len > 253) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Too long keyName-NAI in EAP-Finish/Re-auth");
+ return;
+ }
+ os_memcpy(nai, parse.keyname, parse.keyname_len);
+ nai[parse.keyname_len] = '\0';
+
+ erp = eap_erp_get_key_nai(sm, nai);
+ if (!erp) {
+ wpa_printf(MSG_DEBUG, "EAP: No matching ERP key found for %s",
+ nai);
+ return;
+ }
+
+ /* Is there enough room for Cryptosuite and Authentication Tag? */
+ start = parse.keyname + parse.keyname_len;
+ max_len = end - start;
+ hash_len = 16;
+ if (max_len < 1 + (int) hash_len) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Not enough room for Authentication Tag");
+ if (flags & 0x80)
+ goto no_auth_tag;
+ return;
+ }
+ if (end[-17] != EAP_ERP_CS_HMAC_SHA256_128) {
+ wpa_printf(MSG_DEBUG, "EAP: Different Cryptosuite used");
+ if (flags & 0x80)
+ goto no_auth_tag;
+ return;
+ }
+
+ if (hmac_sha256(erp->rIK, erp->rIK_len, (const u8 *) hdr,
+ end - ((const u8 *) hdr) - hash_len, hash) < 0)
+ return;
+ if (os_memcmp(end - hash_len, hash, hash_len) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Authentication Tag mismatch");
+ return;
+ }
+ auth_tag_ok = 1;
+ end -= 1 + hash_len;
+
+no_auth_tag:
+ /*
+ * Parse TVs/TLVs again now that we know the exact part of the buffer
+ * that contains them.
+ */
+ wpa_hexdump(MSG_DEBUG, "EAP: EAP-Finish/Re-Auth TVs/TLVs",
+ pos, end - pos);
+ if (erp_parse_tlvs(pos, end, &parse, 0) < 0)
+ return;
+
+ if (flags & 0x80 || !auth_tag_ok) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: EAP-Finish/Re-auth indicated failure");
+ eapol_set_bool(sm, EAPOL_eapFail, TRUE);
+ eapol_set_bool(sm, EAPOL_eapReq, FALSE);
+ eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
+ "EAP authentication failed");
+ sm->prev_failure = 1;
+ wpa_printf(MSG_DEBUG,
+ "EAP: Drop ERP key to try full authentication on next attempt");
+ eap_peer_erp_free_key(erp);
+ return;
+ }
+
+ eap_sm_free_key(sm);
+ sm->eapKeyDataLen = 0;
+ sm->eapKeyData = os_malloc(erp->rRK_len);
+ if (!sm->eapKeyData)
+ return;
+ sm->eapKeyDataLen = erp->rRK_len;
+
+ WPA_PUT_BE16(seed, seq);
+ WPA_PUT_BE16(&seed[2], erp->rRK_len);
+ if (hmac_sha256_kdf(erp->rRK, erp->rRK_len,
+ "Re-authentication Master Session Key@ietf.org",
+ seed, sizeof(seed),
+ sm->eapKeyData, erp->rRK_len) < 0) {
+ wpa_printf(MSG_DEBUG, "EAP: Could not derive rMSK for ERP");
+ eap_sm_free_key(sm);
+ return;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rMSK",
+ sm->eapKeyData, sm->eapKeyDataLen);
+ sm->eapKeyAvailable = TRUE;
+ eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
+ eapol_set_bool(sm, EAPOL_eapReq, FALSE);
+ eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
+ "EAP re-authentication completed successfully");
+#endif /* CONFIG_ERP */
+}
+
+
static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req)
{
const struct eap_hdr *hdr;
@@ -1322,6 +1806,12 @@
eap_notify_status(sm, "completion", "failure");
sm->rxFailure = TRUE;
break;
+ case EAP_CODE_INITIATE:
+ eap_peer_initiate(sm, hdr, plen);
+ break;
+ case EAP_CODE_FINISH:
+ eap_peer_finish(sm, hdr, plen);
+ break;
default:
wpa_printf(MSG_DEBUG, "EAP: Ignored EAP-Packet with unknown "
"code %d", hdr->code);
@@ -1368,6 +1858,8 @@
sm->eapol_cb->notify_cert(sm->eapol_ctx,
data->peer_cert.depth,
data->peer_cert.subject,
+ data->peer_cert.altsubject,
+ data->peer_cert.num_altsubject,
hash_hex, data->peer_cert.cert);
break;
case TLS_ALERT:
@@ -1413,11 +1905,13 @@
sm->msg_ctx = msg_ctx;
sm->ClientTimeout = EAP_CLIENT_TIMEOUT_DEFAULT;
sm->wps = conf->wps;
+ dl_list_init(&sm->erp_keys);
os_memset(&tlsconf, 0, sizeof(tlsconf));
tlsconf.opensc_engine_path = conf->opensc_engine_path;
tlsconf.pkcs11_engine_path = conf->pkcs11_engine_path;
tlsconf.pkcs11_module_path = conf->pkcs11_module_path;
+ tlsconf.openssl_ciphers = conf->openssl_ciphers;
#ifdef CONFIG_FIPS
tlsconf.fips_mode = 1;
#endif /* CONFIG_FIPS */
@@ -1459,6 +1953,7 @@
if (sm->ssl_ctx2)
tls_deinit(sm->ssl_ctx2);
tls_deinit(sm->ssl_ctx);
+ eap_peer_erp_free_keys(sm);
os_free(sm);
}
@@ -1607,7 +2102,7 @@
len = os_snprintf(buf, buflen,
"EAP state=%s\n",
eap_sm_state_txt(sm->EAP_state));
- if (len < 0 || (size_t) len >= buflen)
+ if (os_snprintf_error(buflen, len))
return 0;
if (sm->selectedMethod != EAP_TYPE_NONE) {
@@ -1626,7 +2121,7 @@
ret = os_snprintf(buf + len, buflen - len,
"selectedMethod=%d (EAP-%s)\n",
sm->selectedMethod, name);
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -1647,7 +2142,7 @@
eap_sm_method_state_txt(sm->methodState),
eap_sm_decision_txt(sm->decision),
sm->ClientTimeout);
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
}
diff --git a/src/eap_peer/eap.h b/src/eap_peer/eap.h
index 712e929..8c4a42f 100644
--- a/src/eap_peer/eap.h
+++ b/src/eap_peer/eap.h
@@ -94,7 +94,14 @@
*
* EAP state machines reads this value.
*/
- EAPOL_altReject
+ EAPOL_altReject,
+
+ /**
+ * EAPOL_eapTriggerStart - EAP-based trigger to send EAPOL-Start
+ *
+ * EAP state machine writes this value.
+ */
+ EAPOL_eapTriggerStart
};
/**
@@ -221,10 +228,13 @@
* @ctx: eapol_ctx from eap_peer_sm_init() call
* @depth: Depth in certificate chain (0 = server)
* @subject: Subject of the peer certificate
+ * @altsubject: Select fields from AltSubject of the peer certificate
+ * @num_altsubject: Number of altsubject values
* @cert_hash: SHA-256 hash of the certificate
* @cert: Peer certificate
*/
void (*notify_cert)(void *ctx, int depth, const char *subject,
+ const char *altsubject[], int num_altsubject,
const char *cert_hash, const struct wpabuf *cert);
/**
@@ -268,6 +278,14 @@
*/
const char *pkcs11_module_path;
/**
+ * openssl_ciphers - OpenSSL cipher string
+ *
+ * This is an OpenSSL specific configuration option for configuring the
+ * default ciphers. If not set, "DEFAULT:!EXP:!LOW" is used as the
+ * default.
+ */
+ const char *openssl_ciphers;
+ /**
* wps - WPS context data
*
* This is only used by EAP-WSC and can be left %NULL if not available.
@@ -321,6 +339,7 @@
void eap_sm_set_ext_pw_ctx(struct eap_sm *sm, struct ext_password_data *ext);
void eap_set_anon_id(struct eap_sm *sm, const u8 *id, size_t len);
int eap_peer_was_failure_expected(struct eap_sm *sm);
+void eap_peer_erp_free_keys(struct eap_sm *sm);
#endif /* IEEE8021X_EAPOL */
diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h
index 2591e11..903412d 100644
--- a/src/eap_peer/eap_config.h
+++ b/src/eap_peer/eap_config.h
@@ -186,6 +186,10 @@
* string is in following format:
*
* /C=US/ST=CA/L=San Francisco/CN=Test AS/emailAddress=as@n.example.com
+ *
+ * Note: Since this is a substring match, this cannot be used securily
+ * to do a suffix match against a possible domain name in the CN entry.
+ * For such a use case, domain_suffix_match should be used instead.
*/
u8 *subject_match;
@@ -213,7 +217,7 @@
* If set, this FQDN is used as a suffix match requirement for the
* server certificate in SubjectAltName dNSName element(s). If a
* matching dNSName is found, this constraint is met. If no dNSName
- * values are present, this constraint is matched against SubjetName CN
+ * values are present, this constraint is matched against SubjectName CN
* using same suffix match comparison. Suffix match here means that the
* host/domain name is compared one label at a time starting from the
* top-level domain and all the labels in domain_suffix_match shall be
@@ -226,6 +230,21 @@
char *domain_suffix_match;
/**
+ * domain_match - Constraint for server domain name
+ *
+ * If set, this FQDN is used as a full match requirement for the
+ * server certificate in SubjectAltName dNSName element(s). If a
+ * matching dNSName is found, this constraint is met. If no dNSName
+ * values are present, this constraint is matched against SubjectName CN
+ * using same full match comparison. This behavior is similar to
+ * domain_suffix_match, but has the requirement of a full match, i.e.,
+ * no subdomains or wildcard matches are allowed. Case-insensitive
+ * comparison is used, so "Example.com" matches "example.com", but would
+ * not match "test.Example.com".
+ */
+ char *domain_match;
+
+ /**
* ca_cert2 - File path to CA certificate file (PEM/DER) (Phase 2)
*
* This file can have one or more trusted CA certificates. If ca_cert2
@@ -329,6 +348,14 @@
char *domain_suffix_match2;
/**
+ * domain_match2 - Constraint for server domain name
+ *
+ * This field is like domain_match, but used for phase 2 (inside
+ * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ */
+ char *domain_match2;
+
+ /**
* eap_methods - Allowed EAP methods
*
* (vendor=EAP_VENDOR_IETF,method=EAP_TYPE_NONE) terminated list of
@@ -686,6 +713,20 @@
* has more than one.
*/
int sim_num;
+
+ /**
+ * openssl_ciphers - OpenSSL cipher string
+ *
+ * This is an OpenSSL specific configuration option for configuring the
+ * ciphers for this connection. If not set, the default cipher suite
+ * list is used.
+ */
+ char *openssl_ciphers;
+
+ /**
+ * erp - Whether EAP Re-authentication Protocol (ERP) is enabled
+ */
+ int erp;
};
diff --git a/src/eap_peer/eap_fast.c b/src/eap_peer/eap_fast.c
index 0739187..68d7fba 100644
--- a/src/eap_peer/eap_fast.c
+++ b/src/eap_peer/eap_fast.c
@@ -1666,7 +1666,7 @@
ret = os_snprintf(buf + len, buflen - len,
"EAP-FAST Phase2 method=%s\n",
data->phase2_method->name);
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
}
diff --git a/src/eap_peer/eap_fast_pac.c b/src/eap_peer/eap_fast_pac.c
index 21d6098..89e604e 100644
--- a/src/eap_peer/eap_fast_pac.c
+++ b/src/eap_peer/eap_fast_pac.c
@@ -504,28 +504,28 @@
end = *buf + *buf_len;
ret = os_snprintf(*pos, end - *pos, "%s=", field);
- if (ret < 0 || ret >= end - *pos)
+ if (os_snprintf_error(end - *pos, ret))
return;
*pos += ret;
*pos += wpa_snprintf_hex(*pos, end - *pos, data, len);
ret = os_snprintf(*pos, end - *pos, "\n");
- if (ret < 0 || ret >= end - *pos)
+ if (os_snprintf_error(end - *pos, ret))
return;
*pos += ret;
if (txt) {
ret = os_snprintf(*pos, end - *pos, "%s-txt=", field);
- if (ret < 0 || ret >= end - *pos)
+ if (os_snprintf_error(end - *pos, ret))
return;
*pos += ret;
for (i = 0; i < len; i++) {
ret = os_snprintf(*pos, end - *pos, "%c", data[i]);
- if (ret < 0 || ret >= end - *pos)
+ if (os_snprintf_error(end - *pos, ret))
return;
*pos += ret;
}
ret = os_snprintf(*pos, end - *pos, "\n");
- if (ret < 0 || ret >= end - *pos)
+ if (os_snprintf_error(end - *pos, ret))
return;
*pos += ret;
}
@@ -578,7 +578,7 @@
ret = os_snprintf(*pos, *buf + *buf_len - *pos,
"START\nPAC-Type=%d\n", pac->pac_type);
- if (ret < 0 || ret >= *buf + *buf_len - *pos)
+ if (os_snprintf_error(*buf + *buf_len - *pos, ret))
return -1;
*pos += ret;
@@ -600,7 +600,7 @@
return -1;
}
ret = os_snprintf(*pos, *buf + *buf_len - *pos, "END\n");
- if (ret < 0 || ret >= *buf + *buf_len - *pos)
+ if (os_snprintf_error(*buf + *buf_len - *pos, ret))
return -1;
*pos += ret;
@@ -632,7 +632,7 @@
return -1;
ret = os_snprintf(pos, buf + buf_len - pos, "%s\n", pac_file_hdr);
- if (ret < 0 || ret >= buf + buf_len - pos) {
+ if (os_snprintf_error(buf + buf_len - pos, ret)) {
os_free(buf);
return -1;
}
@@ -714,7 +714,7 @@
pos += 2;
len = WPA_GET_BE16(pos);
pos += 2;
- if (pos + len > end)
+ if (len > (unsigned int) (end - pos))
break;
if (type == PAC_TYPE_A_ID) {
@@ -799,7 +799,9 @@
pos = buf + 6;
end = buf + len;
while (pos < end) {
- if (end - pos < 2 + 32 + 2 + 2)
+ u16 val;
+
+ if (end - pos < 2 + EAP_FAST_PAC_KEY_LEN + 2 + 2)
goto parse_fail;
pac = os_zalloc(sizeof(*pac));
@@ -810,19 +812,23 @@
pos += 2;
os_memcpy(pac->pac_key, pos, EAP_FAST_PAC_KEY_LEN);
pos += EAP_FAST_PAC_KEY_LEN;
- pac->pac_opaque_len = WPA_GET_BE16(pos);
+ val = WPA_GET_BE16(pos);
pos += 2;
- if (pos + pac->pac_opaque_len + 2 > end)
+ if (val > end - pos)
goto parse_fail;
+ pac->pac_opaque_len = val;
pac->pac_opaque = os_malloc(pac->pac_opaque_len);
if (pac->pac_opaque == NULL)
goto parse_fail;
os_memcpy(pac->pac_opaque, pos, pac->pac_opaque_len);
pos += pac->pac_opaque_len;
- pac->pac_info_len = WPA_GET_BE16(pos);
- pos += 2;
- if (pos + pac->pac_info_len > end)
+ if (2 > end - pos)
goto parse_fail;
+ val = WPA_GET_BE16(pos);
+ pos += 2;
+ if (val > end - pos)
+ goto parse_fail;
+ pac->pac_info_len = val;
pac->pac_info = os_malloc(pac->pac_info_len);
if (pac->pac_info == NULL)
goto parse_fail;
diff --git a/src/eap_peer/eap_i.h b/src/eap_peer/eap_i.h
index fde809c..2d7fdea 100644
--- a/src/eap_peer/eap_i.h
+++ b/src/eap_peer/eap_i.h
@@ -1,6 +1,6 @@
/*
* EAP peer state machines internal structures (RFC 4137)
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,6 +10,7 @@
#define EAP_I_H
#include "wpabuf.h"
+#include "utils/list.h"
#include "eap_peer/eap.h"
#include "eap_common/eap_common.h"
@@ -277,6 +278,16 @@
};
+struct eap_erp_key {
+ struct dl_list list;
+ size_t rRK_len;
+ size_t rIK_len;
+ u8 rRK[ERP_MAX_KEY_LEN];
+ u8 rIK[ERP_MAX_KEY_LEN];
+ u32 next_seq;
+ char keyname_nai[];
+};
+
/**
* struct eap_sm - EAP state machine data
*/
@@ -321,6 +332,8 @@
void *eap_method_priv;
int init_phase2;
int fast_reauth;
+ Boolean reauthInit; /* send EAP-Identity/Re-auth */
+ u32 erp_seq;
Boolean rxResp /* LEAP only */;
Boolean leap_done;
@@ -353,6 +366,8 @@
int external_sim;
unsigned int expected_failure:1;
+
+ struct dl_list erp_keys; /* struct eap_erp_key */
};
const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len);
diff --git a/src/eap_peer/eap_ikev2.c b/src/eap_peer/eap_ikev2.c
index c12b519..b5ef71b 100644
--- a/src/eap_peer/eap_ikev2.c
+++ b/src/eap_peer/eap_ikev2.c
@@ -301,6 +301,13 @@
if (data->in_buf == NULL) {
/* First fragment of the message */
+ if (message_length > 50000) {
+ /* Limit maximum memory allocation */
+ wpa_printf(MSG_DEBUG,
+ "EAP-IKEV2: Ignore too long message");
+ ret->ignore = TRUE;
+ return NULL;
+ }
data->in_buf = wpabuf_alloc(message_length);
if (data->in_buf == NULL) {
wpa_printf(MSG_DEBUG, "EAP-IKEV2: No memory for "
@@ -315,6 +322,7 @@
(unsigned long) wpabuf_tailroom(data->in_buf));
}
+ ret->ignore = FALSE;
return eap_ikev2_build_frag_ack(id, EAP_CODE_RESPONSE);
}
diff --git a/src/eap_peer/eap_methods.c b/src/eap_peer/eap_methods.c
index 83a1457..1bdd81e 100644
--- a/src/eap_peer/eap_methods.c
+++ b/src/eap_peer/eap_methods.c
@@ -103,7 +103,7 @@
for (m = eap_methods; m; m = m->next) {
ret = os_snprintf(pos, end - pos, "%s%s",
m == eap_methods ? "" : " ", m->name);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
break;
pos += ret;
}
@@ -133,7 +133,7 @@
for (m = eap_methods; m; m = m->next)
array_len++;
- array = os_zalloc(sizeof(char *) * (array_len + 1));
+ array = os_calloc(array_len + 1, sizeof(char *));
if (array == NULL)
return NULL;
diff --git a/src/eap_peer/eap_pax.c b/src/eap_peer/eap_pax.c
index 1c111c2..6d1ff20 100644
--- a/src/eap_peer/eap_pax.c
+++ b/src/eap_peer/eap_pax.c
@@ -38,6 +38,7 @@
u8 mk[EAP_PAX_MK_LEN];
u8 ck[EAP_PAX_CK_LEN];
u8 ick[EAP_PAX_ICK_LEN];
+ u8 mid[EAP_PAX_MID_LEN];
};
@@ -178,8 +179,8 @@
data->rand.r.y, EAP_PAX_RAND_LEN);
if (eap_pax_initial_key_derivation(req->mac_id, data->ak, data->rand.e,
- data->mk, data->ck, data->ick) < 0)
- {
+ data->mk, data->ck, data->ick,
+ data->mid) < 0) {
ret->ignore = TRUE;
return NULL;
}
@@ -501,6 +502,26 @@
}
+static u8 * eap_pax_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_pax_data *data = priv;
+ u8 *sid;
+
+ if (data->state != PAX_DONE)
+ return NULL;
+
+ sid = os_malloc(1 + EAP_PAX_MID_LEN);
+ if (sid == NULL)
+ return NULL;
+
+ *len = 1 + EAP_PAX_MID_LEN;
+ sid[0] = EAP_TYPE_PAX;
+ os_memcpy(sid + 1, data->mid, EAP_PAX_MID_LEN);
+
+ return sid;
+}
+
+
int eap_peer_pax_register(void)
{
struct eap_method *eap;
@@ -517,6 +538,7 @@
eap->isKeyAvailable = eap_pax_isKeyAvailable;
eap->getKey = eap_pax_getKey;
eap->get_emsk = eap_pax_get_emsk;
+ eap->getSessionId = eap_pax_get_session_id;
ret = eap_peer_method_register(eap);
if (ret)
diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c
index 472e861..86a18bb 100644
--- a/src/eap_peer/eap_peap.c
+++ b/src/eap_peer/eap_peap.c
@@ -1156,7 +1156,7 @@
"EAP-PEAPv%d Phase2 method=%s\n",
data->peap_version,
data->phase2_method->name);
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
}
diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c
index 1c915ed..059bbee 100644
--- a/src/eap_peer/eap_pwd.c
+++ b/src/eap_peer/eap_pwd.c
@@ -952,7 +952,6 @@
struct eap_method *eap;
int ret;
- EVP_add_digest(EVP_sha256());
eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
EAP_VENDOR_IETF, EAP_TYPE_PWD, "PWD");
if (eap == NULL)
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index fe9bfe0..8710781 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -91,6 +91,7 @@
params->subject_match = (char *) config->subject_match;
params->altsubject_match = (char *) config->altsubject_match;
params->suffix_match = config->domain_suffix_match;
+ params->domain_match = config->domain_match;
params->engine = config->engine;
params->engine_id = config->engine_id;
params->pin = config->pin;
@@ -113,6 +114,7 @@
params->subject_match = (char *) config->subject_match2;
params->altsubject_match = (char *) config->altsubject_match2;
params->suffix_match = config->domain_suffix_match2;
+ params->domain_match = config->domain_match2;
params->engine = config->engine2;
params->engine_id = config->engine2_id;
params->pin = config->pin2;
@@ -147,6 +149,8 @@
} else {
wpa_printf(MSG_DEBUG, "TLS: using phase1 config options");
eap_tls_params_from_conf1(params, config);
+ if (data->eap_type == EAP_TYPE_FAST)
+ params->flags |= TLS_CONN_EAP_FAST;
}
/*
@@ -167,6 +171,8 @@
return -1;
}
+ params->openssl_ciphers = config->openssl_ciphers;
+
return 0;
}
@@ -377,15 +383,10 @@
struct tls_keys keys;
u8 *out;
- /*
- * TLS library did not support session ID generation,
- * so get the needed TLS session parameters
- */
if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
return NULL;
- if (keys.client_random == NULL || keys.server_random == NULL ||
- keys.master_key == NULL)
+ if (keys.client_random == NULL || keys.server_random == NULL)
return NULL;
*len = 1 + keys.client_random_len + keys.server_random_len;
@@ -397,7 +398,7 @@
out[0] = eap_type;
os_memcpy(out + 1, keys.client_random, keys.client_random_len);
os_memcpy(out + 1 + keys.client_random_len, keys.server_random,
- keys.server_random_len);
+ keys.server_random_len);
return out;
}
@@ -795,8 +796,11 @@
if (tls_get_cipher(data->ssl_ctx, data->conn, name, sizeof(name)) == 0)
{
ret = os_snprintf(buf + len, buflen - len,
- "EAP TLS cipher=%s\n", name);
- if (ret < 0 || (size_t) ret >= buflen - len)
+ "EAP TLS cipher=%s\n"
+ "tls_session_reused=%d\n",
+ name, tls_connection_resumed(data->ssl_ctx,
+ data->conn));
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
}
diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c
index 771da58..b5c028b 100644
--- a/src/eap_peer/eap_ttls.c
+++ b/src/eap_peer/eap_ttls.c
@@ -136,7 +136,7 @@
static void eap_ttls_free_key(struct eap_ttls_data *data)
{
if (data->key_data) {
- bin_clear_free(data->key_data, EAP_TLS_KEY_LEN);
+ bin_clear_free(data->key_data, EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
data->key_data = NULL;
}
}
@@ -225,7 +225,8 @@
eap_ttls_free_key(data);
data->key_data = eap_peer_tls_derive_key(sm, &data->ssl,
"ttls keying material",
- EAP_TLS_KEY_LEN);
+ EAP_TLS_KEY_LEN +
+ EAP_EMSK_LEN);
if (!data->key_data) {
wpa_printf(MSG_INFO, "EAP-TTLS: Failed to derive key");
return -1;
@@ -233,6 +234,9 @@
wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key",
data->key_data, EAP_TLS_KEY_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived EMSK",
+ data->key_data + EAP_TLS_KEY_LEN,
+ EAP_EMSK_LEN);
os_free(data->session_id);
data->session_id = eap_peer_tls_derive_session_id(sm, &data->ssl,
@@ -991,6 +995,7 @@
resp, out_data)) {
wpa_printf(MSG_INFO, "EAP-TTLS: Failed to encrypt a Phase 2 "
"frame");
+ wpabuf_free(resp);
return -1;
}
wpabuf_free(resp);
@@ -1567,7 +1572,7 @@
ret = os_snprintf(buf + len, buflen - len,
"EAP-TTLSv%d Phase2 method=",
data->ttls_version);
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
switch (data->phase2_type) {
@@ -1592,7 +1597,7 @@
ret = 0;
break;
}
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -1645,6 +1650,25 @@
}
+static u8 * eap_ttls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_ttls_data *data = priv;
+ u8 *key;
+
+ if (data->key_data == NULL)
+ return NULL;
+
+ key = os_malloc(EAP_EMSK_LEN);
+ if (key == NULL)
+ return NULL;
+
+ *len = EAP_EMSK_LEN;
+ os_memcpy(key, data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN);
+
+ return key;
+}
+
+
int eap_peer_ttls_register(void)
{
struct eap_method *eap;
@@ -1665,6 +1689,7 @@
eap->has_reauth_data = eap_ttls_has_reauth_data;
eap->deinit_for_reauth = eap_ttls_deinit_for_reauth;
eap->init_for_reauth = eap_ttls_init_for_reauth;
+ eap->get_emsk = eap_ttls_get_emsk;
ret = eap_peer_method_register(eap);
if (ret)
diff --git a/src/eap_peer/eap_wsc.c b/src/eap_peer/eap_wsc.c
index 23e9823..7ce0a53 100644
--- a/src/eap_peer/eap_wsc.c
+++ b/src/eap_peer/eap_wsc.c
@@ -462,7 +462,7 @@
message_length = WPA_GET_BE16(pos);
pos += 2;
- if (message_length < end - pos) {
+ if (message_length < end - pos || message_length > 50000) {
wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message "
"Length");
ret->ignore = TRUE;
diff --git a/src/eap_peer/ikev2.c b/src/eap_peer/ikev2.c
index 8186afb..55ab72a 100644
--- a/src/eap_peer/ikev2.c
+++ b/src/eap_peer/ikev2.c
@@ -213,7 +213,7 @@
p = (const struct ikev2_proposal *) pos;
proposal_len = WPA_GET_BE16(p->proposal_length);
- if (proposal_len < (int) sizeof(*p) || pos + proposal_len > end) {
+ if (proposal_len < (int) sizeof(*p) || proposal_len > end - pos) {
wpa_printf(MSG_INFO, "IKEV2: Invalid proposal length %d",
proposal_len);
return -1;
@@ -369,7 +369,7 @@
}
if (kei_len < 4 + 96) {
- wpa_printf(MSG_INFO, "IKEV2: Too show Key Exchange Payload");
+ wpa_printf(MSG_INFO, "IKEV2: Too short Key Exchange Payload");
return -1;
}
diff --git a/src/eap_server/eap.h b/src/eap_server/eap.h
index 1253bd6..9de6cb6 100644
--- a/src/eap_server/eap.h
+++ b/src/eap_server/eap.h
@@ -1,6 +1,6 @@
/*
* hostapd / EAP Full Authenticator state machine (RFC 4137)
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,6 +10,7 @@
#define EAP_H
#include "common/defs.h"
+#include "utils/list.h"
#include "eap_common/eap_defs.h"
#include "eap_server/eap_methods.h"
#include "wpabuf.h"
@@ -58,6 +59,8 @@
struct wpabuf *eapReqData;
u8 *eapKeyData;
size_t eapKeyDataLen;
+ u8 *eapSessionId;
+ size_t eapSessionIdLen;
Boolean eapKeyAvailable; /* called keyAvailable in IEEE 802.1X-2004 */
/* AAA interface to full authenticator variables */
@@ -78,11 +81,27 @@
Boolean aaaTimeout;
};
+struct eap_server_erp_key {
+ struct dl_list list;
+ size_t rRK_len;
+ size_t rIK_len;
+ u8 rRK[ERP_MAX_KEY_LEN];
+ u8 rIK[ERP_MAX_KEY_LEN];
+ u32 recv_seq;
+ u8 cryptosuite;
+ char keyname_nai[];
+};
+
struct eapol_callbacks {
int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
int phase2, struct eap_user *user);
const char * (*get_eap_req_id_text)(void *ctx, size_t *len);
void (*log_msg)(void *ctx, const char *msg);
+ int (*get_erp_send_reauth_start)(void *ctx);
+ const char * (*get_erp_domain)(void *ctx);
+ struct eap_server_erp_key * (*erp_get_key)(void *ctx,
+ const char *keyname);
+ int (*erp_add_key)(void *ctx, struct eap_server_erp_key *erp);
};
struct eap_config {
@@ -111,6 +130,7 @@
const u8 *server_id;
size_t server_id_len;
+ int erp;
#ifdef CONFIG_TESTING_OPTIONS
u32 tls_test_flags;
diff --git a/src/eap_server/eap_i.h b/src/eap_server/eap_i.h
index 3a6802b..7d72309 100644
--- a/src/eap_server/eap_i.h
+++ b/src/eap_server/eap_i.h
@@ -88,6 +88,19 @@
* private data or this function may derive the key.
*/
u8 * (*get_emsk)(struct eap_sm *sm, void *priv, size_t *len);
+
+ /**
+ * getSessionId - Get EAP method specific Session-Id
+ * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
+ * @priv: Pointer to private EAP method data from eap_method::init()
+ * @len: Pointer to a variable to store Session-Id length
+ * Returns: Session-Id or %NULL if not available
+ *
+ * This function can be used to get the Session-Id from the EAP method.
+ * The Session-Id may already be stored in the method-specific private
+ * data or this function may derive the Session-Id.
+ */
+ u8 * (*getSessionId)(struct eap_sm *sm, void *priv, size_t *len);
};
/**
@@ -103,7 +116,8 @@
EAP_INITIALIZE_PASSTHROUGH, EAP_IDLE2, EAP_RETRANSMIT2,
EAP_RECEIVED2, EAP_DISCARD2, EAP_SEND_REQUEST2,
EAP_AAA_REQUEST, EAP_AAA_RESPONSE, EAP_AAA_IDLE,
- EAP_TIMEOUT_FAILURE2, EAP_FAILURE2, EAP_SUCCESS2
+ EAP_TIMEOUT_FAILURE2, EAP_FAILURE2, EAP_SUCCESS2,
+ EAP_INITIATE_REAUTH_START, EAP_INITIATE_RECEIVED
} EAP_state;
/* Constants */
@@ -125,6 +139,7 @@
/* Short-term (not maintained between packets) */
Boolean rxResp;
+ Boolean rxInitiate;
int respId;
EapType respMethod;
int respVendor;
@@ -132,7 +147,7 @@
Boolean ignore;
enum {
DECISION_SUCCESS, DECISION_FAILURE, DECISION_CONTINUE,
- DECISION_PASSTHROUGH
+ DECISION_PASSTHROUGH, DECISION_INITIATE_REAUTH_START
} decision;
/* Miscellaneous variables */
@@ -192,6 +207,10 @@
const u8 *server_id;
size_t server_id_len;
+ Boolean initiate_reauth_start_sent;
+ Boolean try_initiate_reauth;
+ int erp;
+
#ifdef CONFIG_TESTING_OPTIONS
u32 tls_test_flags;
#endif /* CONFIG_TESTING_OPTIONS */
diff --git a/src/eap_server/eap_server.c b/src/eap_server/eap_server.c
index c1bb6b8..bd919e5 100644
--- a/src/eap_server/eap_server.c
+++ b/src/eap_server/eap_server.c
@@ -1,6 +1,6 @@
/*
* hostapd / EAP Full Authenticator state machine (RFC 4137)
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -15,6 +15,7 @@
#include "includes.h"
#include "common.h"
+#include "crypto/sha256.h"
#include "eap_i.h"
#include "state_machine.h"
#include "common/wpa_ctrl.h"
@@ -44,6 +45,73 @@
static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method);
+static int eap_get_erp_send_reauth_start(struct eap_sm *sm)
+{
+ if (sm->eapol_cb->get_erp_send_reauth_start)
+ return sm->eapol_cb->get_erp_send_reauth_start(sm->eapol_ctx);
+ return 0;
+}
+
+
+static const char * eap_get_erp_domain(struct eap_sm *sm)
+{
+ if (sm->eapol_cb->get_erp_domain)
+ return sm->eapol_cb->get_erp_domain(sm->eapol_ctx);
+ return NULL;
+}
+
+
+#ifdef CONFIG_ERP
+
+static struct eap_server_erp_key * eap_erp_get_key(struct eap_sm *sm,
+ const char *keyname)
+{
+ if (sm->eapol_cb->erp_get_key)
+ return sm->eapol_cb->erp_get_key(sm->eapol_ctx, keyname);
+ return NULL;
+}
+
+
+static int eap_erp_add_key(struct eap_sm *sm, struct eap_server_erp_key *erp)
+{
+ if (sm->eapol_cb->erp_add_key)
+ return sm->eapol_cb->erp_add_key(sm->eapol_ctx, erp);
+ return -1;
+}
+
+#endif /* CONFIG_ERP */
+
+
+static struct wpabuf * eap_sm_buildInitiateReauthStart(struct eap_sm *sm,
+ u8 id)
+{
+ const char *domain;
+ size_t plen = 1;
+ struct wpabuf *msg;
+ size_t domain_len = 0;
+
+ domain = eap_get_erp_domain(sm);
+ if (domain) {
+ domain_len = os_strlen(domain);
+ plen += 2 + domain_len;
+ }
+
+ msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_ERP_TYPE_REAUTH_START, plen,
+ EAP_CODE_INITIATE, id);
+ if (msg == NULL)
+ return NULL;
+ wpabuf_put_u8(msg, 0); /* Reserved */
+ if (domain) {
+ /* Domain name TLV */
+ wpabuf_put_u8(msg, EAP_ERP_TLV_DOMAIN_NAME);
+ wpabuf_put_u8(msg, domain_len);
+ wpabuf_put_data(msg, domain, domain_len);
+ }
+
+ return msg;
+}
+
+
static int eap_copy_buf(struct wpabuf **dst, const struct wpabuf *src)
{
if (src == NULL)
@@ -164,6 +232,7 @@
eap_server_clear_identity(sm);
}
+ sm->try_initiate_reauth = FALSE;
sm->currentId = -1;
sm->eap_if.eapSuccess = FALSE;
sm->eap_if.eapFail = FALSE;
@@ -171,6 +240,9 @@
bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
sm->eap_if.eapKeyData = NULL;
sm->eap_if.eapKeyDataLen = 0;
+ os_free(sm->eap_if.eapSessionId);
+ sm->eap_if.eapSessionId = NULL;
+ sm->eap_if.eapSessionIdLen = 0;
sm->eap_if.eapKeyAvailable = FALSE;
sm->eap_if.eapRestart = FALSE;
@@ -336,6 +408,95 @@
}
+static void eap_server_erp_init(struct eap_sm *sm)
+{
+#ifdef CONFIG_ERP
+ u8 *emsk = NULL;
+ size_t emsk_len = 0;
+ u8 EMSKname[EAP_EMSK_NAME_LEN];
+ u8 len[2];
+ const char *domain;
+ size_t domain_len, nai_buf_len;
+ struct eap_server_erp_key *erp = NULL;
+ int pos;
+
+ domain = eap_get_erp_domain(sm);
+ if (!domain)
+ return;
+
+ domain_len = os_strlen(domain);
+
+ nai_buf_len = 2 * EAP_EMSK_NAME_LEN + 1 + domain_len;
+ if (nai_buf_len > 253) {
+ /*
+ * keyName-NAI has a maximum length of 253 octet to fit in
+ * RADIUS attributes.
+ */
+ wpa_printf(MSG_DEBUG,
+ "EAP: Too long realm for ERP keyName-NAI maximum length");
+ return;
+ }
+ nai_buf_len++; /* null termination */
+ erp = os_zalloc(sizeof(*erp) + nai_buf_len);
+ if (erp == NULL)
+ goto fail;
+ erp->recv_seq = (u32) -1;
+
+ emsk = sm->m->get_emsk(sm, sm->eap_method_priv, &emsk_len);
+ if (!emsk || emsk_len == 0 || emsk_len > ERP_MAX_KEY_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: No suitable EMSK available for ERP");
+ goto fail;
+ }
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP: EMSK", emsk, emsk_len);
+
+ WPA_PUT_BE16(len, 8);
+ if (hmac_sha256_kdf(sm->eap_if.eapSessionId, sm->eap_if.eapSessionIdLen,
+ "EMSK", len, sizeof(len),
+ EMSKname, EAP_EMSK_NAME_LEN) < 0) {
+ wpa_printf(MSG_DEBUG, "EAP: Could not derive EMSKname");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG, "EAP: EMSKname", EMSKname, EAP_EMSK_NAME_LEN);
+
+ pos = wpa_snprintf_hex(erp->keyname_nai, nai_buf_len,
+ EMSKname, EAP_EMSK_NAME_LEN);
+ erp->keyname_nai[pos] = '@';
+ os_memcpy(&erp->keyname_nai[pos + 1], domain, domain_len);
+
+ WPA_PUT_BE16(len, emsk_len);
+ if (hmac_sha256_kdf(emsk, emsk_len,
+ "EAP Re-authentication Root Key@ietf.org",
+ len, sizeof(len), erp->rRK, emsk_len) < 0) {
+ wpa_printf(MSG_DEBUG, "EAP: Could not derive rRK for ERP");
+ goto fail;
+ }
+ erp->rRK_len = emsk_len;
+ wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rRK", erp->rRK, erp->rRK_len);
+
+ if (hmac_sha256_kdf(erp->rRK, erp->rRK_len,
+ "EAP Re-authentication Integrity Key@ietf.org",
+ len, sizeof(len), erp->rIK, erp->rRK_len) < 0) {
+ wpa_printf(MSG_DEBUG, "EAP: Could not derive rIK for ERP");
+ goto fail;
+ }
+ erp->rIK_len = erp->rRK_len;
+ wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rIK", erp->rIK, erp->rIK_len);
+
+ if (eap_erp_add_key(sm, erp) == 0) {
+ wpa_printf(MSG_DEBUG, "EAP: Stored ERP keys %s",
+ erp->keyname_nai);
+ erp = NULL;
+ }
+
+fail:
+ bin_clear_free(emsk, emsk_len);
+ bin_clear_free(erp, sizeof(*erp));
+#endif /* CONFIG_ERP */
+}
+
+
SM_STATE(EAP, METHOD_RESPONSE)
{
SM_ENTRY(EAP, METHOD_RESPONSE);
@@ -355,6 +516,18 @@
sm->eap_if.eapKeyData = NULL;
sm->eap_if.eapKeyDataLen = 0;
}
+ os_free(sm->eap_if.eapSessionId);
+ sm->eap_if.eapSessionId = NULL;
+ if (sm->m->getSessionId) {
+ sm->eap_if.eapSessionId = sm->m->getSessionId(
+ sm, sm->eap_method_priv,
+ &sm->eap_if.eapSessionIdLen);
+ wpa_hexdump(MSG_DEBUG, "EAP: Session-Id",
+ sm->eap_if.eapSessionId,
+ sm->eap_if.eapSessionIdLen);
+ }
+ if (sm->erp && sm->m->get_emsk && sm->eap_if.eapSessionId)
+ eap_server_erp_init(sm);
sm->methodState = METHOD_END;
} else {
sm->methodState = METHOD_CONTINUE;
@@ -369,6 +542,7 @@
SM_ENTRY(EAP, PROPOSE_METHOD);
+ sm->try_initiate_reauth = FALSE;
try_another_method:
type = eap_sm_Policy_getNextMethod(sm, &vendor);
if (vendor == EAP_VENDOR_IETF)
@@ -492,12 +666,326 @@
}
+SM_STATE(EAP, INITIATE_REAUTH_START)
+{
+ SM_ENTRY(EAP, INITIATE_REAUTH_START);
+
+ sm->initiate_reauth_start_sent = TRUE;
+ sm->try_initiate_reauth = TRUE;
+ sm->currentId = eap_sm_nextId(sm, sm->currentId);
+ wpa_printf(MSG_DEBUG,
+ "EAP: building EAP-Initiate-Re-auth-Start: Identifier %d",
+ sm->currentId);
+ sm->lastId = sm->currentId;
+ wpabuf_free(sm->eap_if.eapReqData);
+ sm->eap_if.eapReqData = eap_sm_buildInitiateReauthStart(sm,
+ sm->currentId);
+ wpabuf_free(sm->lastReqData);
+ sm->lastReqData = NULL;
+}
+
+
+#ifdef CONFIG_ERP
+
+static void erp_send_finish_reauth(struct eap_sm *sm,
+ struct eap_server_erp_key *erp, u8 id,
+ u8 flags, u16 seq, const char *nai)
+{
+ size_t plen;
+ struct wpabuf *msg;
+ u8 hash[SHA256_MAC_LEN];
+ size_t hash_len;
+ u8 seed[4];
+
+ if (erp) {
+ switch (erp->cryptosuite) {
+ case EAP_ERP_CS_HMAC_SHA256_256:
+ hash_len = 32;
+ break;
+ case EAP_ERP_CS_HMAC_SHA256_128:
+ hash_len = 16;
+ break;
+ default:
+ return;
+ }
+ } else
+ hash_len = 0;
+
+ plen = 1 + 2 + 2 + os_strlen(nai);
+ if (hash_len)
+ plen += 1 + hash_len;
+ msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_ERP_TYPE_REAUTH, plen,
+ EAP_CODE_FINISH, id);
+ if (msg == NULL)
+ return;
+ wpabuf_put_u8(msg, flags);
+ wpabuf_put_be16(msg, seq);
+
+ wpabuf_put_u8(msg, EAP_ERP_TLV_KEYNAME_NAI);
+ wpabuf_put_u8(msg, os_strlen(nai));
+ wpabuf_put_str(msg, nai);
+
+ if (erp) {
+ wpabuf_put_u8(msg, erp->cryptosuite);
+ if (hmac_sha256(erp->rIK, erp->rIK_len,
+ wpabuf_head(msg), wpabuf_len(msg), hash) < 0) {
+ wpabuf_free(msg);
+ return;
+ }
+ wpabuf_put_data(msg, hash, hash_len);
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP: Send EAP-Finish/Re-auth (%s)",
+ flags & 0x80 ? "failure" : "success");
+
+ sm->lastId = sm->currentId;
+ sm->currentId = id;
+ wpabuf_free(sm->eap_if.eapReqData);
+ sm->eap_if.eapReqData = msg;
+ wpabuf_free(sm->lastReqData);
+ sm->lastReqData = NULL;
+
+ if (flags & 0x80) {
+ sm->eap_if.eapFail = TRUE;
+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
+ MACSTR, MAC2STR(sm->peer_addr));
+ return;
+ }
+
+ bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
+ sm->eap_if.eapKeyDataLen = 0;
+ sm->eap_if.eapKeyData = os_malloc(erp->rRK_len);
+ if (!sm->eap_if.eapKeyData)
+ return;
+
+ WPA_PUT_BE16(seed, seq);
+ WPA_PUT_BE16(&seed[2], erp->rRK_len);
+ if (hmac_sha256_kdf(erp->rRK, erp->rRK_len,
+ "Re-authentication Master Session Key@ietf.org",
+ seed, sizeof(seed),
+ sm->eap_if.eapKeyData, erp->rRK_len) < 0) {
+ wpa_printf(MSG_DEBUG, "EAP: Could not derive rMSK for ERP");
+ bin_clear_free(sm->eap_if.eapKeyData, erp->rRK_len);
+ sm->eap_if.eapKeyData = NULL;
+ return;
+ }
+ sm->eap_if.eapKeyDataLen = erp->rRK_len;
+ sm->eap_if.eapKeyAvailable = TRUE;
+ wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rMSK",
+ sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
+ sm->eap_if.eapSuccess = TRUE;
+
+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
+ MACSTR, MAC2STR(sm->peer_addr));
+}
+
+
+SM_STATE(EAP, INITIATE_RECEIVED)
+{
+ const u8 *pos, *end, *start, *tlvs, *hdr;
+ const struct eap_hdr *ehdr;
+ size_t len;
+ u8 flags;
+ u16 seq;
+ char nai[254];
+ struct eap_server_erp_key *erp;
+ int max_len;
+ u8 hash[SHA256_MAC_LEN];
+ size_t hash_len;
+ struct erp_tlvs parse;
+ u8 resp_flags = 0x80; /* default to failure; cleared on success */
+
+ SM_ENTRY(EAP, INITIATE_RECEIVED);
+
+ sm->rxInitiate = FALSE;
+
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_ERP_TYPE_REAUTH,
+ sm->eap_if.eapRespData, &len);
+ if (pos == NULL) {
+ wpa_printf(MSG_INFO, "EAP-Initiate: Invalid frame");
+ goto fail;
+ }
+ hdr = wpabuf_head(sm->eap_if.eapRespData);
+ ehdr = wpabuf_head(sm->eap_if.eapRespData);
+
+ wpa_hexdump(MSG_DEBUG, "EAP: EAP-Initiate/Re-Auth", pos, len);
+ if (len < 4) {
+ wpa_printf(MSG_INFO, "EAP: Too short EAP-Initiate/Re-auth");
+ goto fail;
+ }
+ end = pos + len;
+
+ flags = *pos++;
+ seq = WPA_GET_BE16(pos);
+ pos += 2;
+ wpa_printf(MSG_DEBUG, "EAP: Flags=0x%x SEQ=%u", flags, seq);
+ tlvs = pos;
+
+ /*
+ * Parse TVs/TLVs. Since we do not yet know the length of the
+ * Authentication Tag, stop parsing if an unknown TV/TLV is seen and
+ * just try to find the keyName-NAI first so that we can check the
+ * Authentication Tag.
+ */
+ if (erp_parse_tlvs(tlvs, end, &parse, 1) < 0)
+ goto fail;
+
+ if (!parse.keyname) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: No keyName-NAI in EAP-Initiate/Re-auth Packet");
+ goto fail;
+ }
+
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Initiate/Re-auth - keyName-NAI",
+ parse.keyname, parse.keyname_len);
+ if (parse.keyname_len > 253) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Too long keyName-NAI in EAP-Initiate/Re-auth");
+ goto fail;
+ }
+ os_memcpy(nai, parse.keyname, parse.keyname_len);
+ nai[parse.keyname_len] = '\0';
+
+ if (!sm->eap_server) {
+ /*
+ * In passthrough case, EAP-Initiate/Re-auth replaces
+ * EAP Identity exchange. Use keyName-NAI as the user identity
+ * and forward EAP-Initiate/Re-auth to the backend
+ * authentication server.
+ */
+ wpa_printf(MSG_DEBUG,
+ "EAP: Use keyName-NAI as user identity for backend authentication");
+ eap_server_clear_identity(sm);
+ sm->identity = (u8 *) dup_binstr(parse.keyname,
+ parse.keyname_len);
+ if (!sm->identity)
+ goto fail;
+ sm->identity_len = parse.keyname_len;
+ return;
+ }
+
+ erp = eap_erp_get_key(sm, nai);
+ if (!erp) {
+ wpa_printf(MSG_DEBUG, "EAP: No matching ERP key found for %s",
+ nai);
+ goto report_error;
+ }
+
+ if (erp->recv_seq != (u32) -1 && erp->recv_seq >= seq) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: SEQ=%u replayed (already received SEQ=%u)",
+ seq, erp->recv_seq);
+ goto fail;
+ }
+
+ /* Is there enough room for Cryptosuite and Authentication Tag? */
+ start = parse.keyname + parse.keyname_len;
+ max_len = end - start;
+ if (max_len <
+ 1 + (erp->cryptosuite == EAP_ERP_CS_HMAC_SHA256_256 ? 32 : 16)) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Not enough room for Authentication Tag");
+ goto fail;
+ }
+
+ switch (erp->cryptosuite) {
+ case EAP_ERP_CS_HMAC_SHA256_256:
+ if (end[-33] != erp->cryptosuite) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Different Cryptosuite used");
+ goto fail;
+ }
+ hash_len = 32;
+ break;
+ case EAP_ERP_CS_HMAC_SHA256_128:
+ if (end[-17] != erp->cryptosuite) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Different Cryptosuite used");
+ goto fail;
+ }
+ hash_len = 16;
+ break;
+ default:
+ hash_len = 0;
+ break;
+ }
+
+ if (hash_len) {
+ if (hmac_sha256(erp->rIK, erp->rIK_len, hdr,
+ end - hdr - hash_len, hash) < 0)
+ goto fail;
+ if (os_memcmp(end - hash_len, hash, hash_len) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Authentication Tag mismatch");
+ goto fail;
+ }
+ }
+
+ /* Check if any supported CS results in matching tag */
+ if (!hash_len && max_len >= 1 + 32 &&
+ end[-33] == EAP_ERP_CS_HMAC_SHA256_256) {
+ if (hmac_sha256(erp->rIK, erp->rIK_len, hdr,
+ end - hdr - 32, hash) < 0)
+ goto fail;
+ if (os_memcmp(end - 32, hash, 32) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Authentication Tag match using HMAC-SHA256-256");
+ hash_len = 32;
+ erp->cryptosuite = EAP_ERP_CS_HMAC_SHA256_256;
+ }
+ }
+
+ if (!hash_len && end[-17] == EAP_ERP_CS_HMAC_SHA256_128) {
+ if (hmac_sha256(erp->rIK, erp->rIK_len, hdr,
+ end - hdr - 16, hash) < 0)
+ goto fail;
+ if (os_memcmp(end - 16, hash, 16) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: Authentication Tag match using HMAC-SHA256-128");
+ hash_len = 16;
+ erp->cryptosuite = EAP_ERP_CS_HMAC_SHA256_128;
+ }
+ }
+
+ if (!hash_len) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: No supported cryptosuite matched Authentication Tag");
+ goto fail;
+ }
+ end -= 1 + hash_len;
+
+ /*
+ * Parse TVs/TLVs again now that we know the exact part of the buffer
+ * that contains them.
+ */
+ wpa_hexdump(MSG_DEBUG, "EAP: EAP-Initiate/Re-Auth TVs/TLVs",
+ tlvs, end - tlvs);
+ if (erp_parse_tlvs(tlvs, end, &parse, 0) < 0)
+ goto fail;
+
+ wpa_printf(MSG_DEBUG, "EAP: ERP key %s SEQ updated to %u",
+ erp->keyname_nai, seq);
+ erp->recv_seq = seq;
+ resp_flags &= ~0x80; /* R=0 - success */
+
+report_error:
+ erp_send_finish_reauth(sm, erp, ehdr->identifier, resp_flags, seq, nai);
+ return;
+
+fail:
+ sm->ignore = TRUE;
+}
+
+#endif /* CONFIG_ERP */
+
+
SM_STATE(EAP, INITIALIZE_PASSTHROUGH)
{
SM_ENTRY(EAP, INITIALIZE_PASSTHROUGH);
wpabuf_free(sm->eap_if.aaaEapRespData);
sm->eap_if.aaaEapRespData = NULL;
+ sm->try_initiate_reauth = FALSE;
}
@@ -691,9 +1179,14 @@
SM_ENTER(EAP, INITIALIZE);
break;
case EAP_IDLE:
- if (sm->eap_if.retransWhile == 0)
- SM_ENTER(EAP, RETRANSMIT);
- else if (sm->eap_if.eapResp)
+ if (sm->eap_if.retransWhile == 0) {
+ if (sm->try_initiate_reauth) {
+ sm->try_initiate_reauth = FALSE;
+ SM_ENTER(EAP, SELECT_ACTION);
+ } else {
+ SM_ENTER(EAP, RETRANSMIT);
+ }
+ } else if (sm->eap_if.eapResp)
SM_ENTER(EAP, RECEIVED);
break;
case EAP_RETRANSMIT:
@@ -716,6 +1209,10 @@
sm->respVendor == EAP_VENDOR_IETF &&
sm->respVendorMethod == sm->currentMethod)))
SM_ENTER(EAP, INTEGRITY_CHECK);
+#ifdef CONFIG_ERP
+ else if (sm->rxInitiate)
+ SM_ENTER(EAP, INITIATE_RECEIVED);
+#endif /* CONFIG_ERP */
else {
wpa_printf(MSG_DEBUG, "EAP: RECEIVED->DISCARD: "
"rxResp=%d respId=%d currentId=%d "
@@ -804,9 +1301,22 @@
SM_ENTER(EAP, SUCCESS);
else if (sm->decision == DECISION_PASSTHROUGH)
SM_ENTER(EAP, INITIALIZE_PASSTHROUGH);
+ else if (sm->decision == DECISION_INITIATE_REAUTH_START)
+ SM_ENTER(EAP, INITIATE_REAUTH_START);
+#ifdef CONFIG_ERP
+ else if (sm->eap_server && sm->erp && sm->rxInitiate)
+ SM_ENTER(EAP, INITIATE_RECEIVED);
+#endif /* CONFIG_ERP */
else
SM_ENTER(EAP, PROPOSE_METHOD);
break;
+ case EAP_INITIATE_REAUTH_START:
+ SM_ENTER(EAP, SEND_REQUEST);
+ break;
+ case EAP_INITIATE_RECEIVED:
+ if (!sm->eap_server)
+ SM_ENTER(EAP, SELECT_ACTION);
+ break;
case EAP_TIMEOUT_FAILURE:
break;
case EAP_FAILURE:
@@ -876,6 +1386,12 @@
{
int rto, i;
+ if (sm->try_initiate_reauth) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: retransmit timeout 1 second for EAP-Initiate-Re-auth-Start");
+ return 1;
+ }
+
if (methodTimeout) {
/*
* EAP method (either internal or through AAA server, provided
@@ -929,6 +1445,7 @@
/* parse rxResp, respId, respMethod */
sm->rxResp = FALSE;
+ sm->rxInitiate = FALSE;
sm->respId = -1;
sm->respMethod = EAP_TYPE_NONE;
sm->respVendor = EAP_VENDOR_IETF;
@@ -955,6 +1472,8 @@
if (hdr->code == EAP_CODE_RESPONSE)
sm->rxResp = TRUE;
+ else if (hdr->code == EAP_CODE_INITIATE)
+ sm->rxInitiate = TRUE;
if (plen > sizeof(*hdr)) {
u8 *pos = (u8 *) (hdr + 1);
@@ -972,10 +1491,10 @@
}
}
- wpa_printf(MSG_DEBUG, "EAP: parseEapResp: rxResp=%d respId=%d "
- "respMethod=%u respVendor=%u respVendorMethod=%u",
- sm->rxResp, sm->respId, sm->respMethod, sm->respVendor,
- sm->respVendorMethod);
+ wpa_printf(MSG_DEBUG,
+ "EAP: parseEapResp: rxResp=%d rxInitiate=%d respId=%d respMethod=%u respVendor=%u respVendorMethod=%u",
+ sm->rxResp, sm->rxInitiate, sm->respId, sm->respMethod,
+ sm->respVendor, sm->respVendorMethod);
}
@@ -1216,6 +1735,13 @@
return DECISION_CONTINUE;
}
+ if (!sm->identity && eap_get_erp_send_reauth_start(sm) &&
+ !sm->initiate_reauth_start_sent) {
+ wpa_printf(MSG_DEBUG,
+ "EAP: getDecision: send EAP-Initiate/Re-auth-Start");
+ return DECISION_INITIATE_REAUTH_START;
+ }
+
if (sm->identity == NULL || sm->currentId == -1) {
wpa_printf(MSG_DEBUG, "EAP: getDecision: no identity known "
"yet -> CONTINUE");
@@ -1326,6 +1852,7 @@
sm->pbc_in_m1 = conf->pbc_in_m1;
sm->server_id = conf->server_id;
sm->server_id_len = conf->server_id_len;
+ sm->erp = conf->erp;
#ifdef CONFIG_TESTING_OPTIONS
sm->tls_test_flags = conf->tls_test_flags;
@@ -1353,6 +1880,7 @@
sm->m->reset(sm, sm->eap_method_priv);
wpabuf_free(sm->eap_if.eapReqData);
bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
+ os_free(sm->eap_if.eapSessionId);
wpabuf_free(sm->lastReqData);
wpabuf_free(sm->eap_if.eapRespData);
os_free(sm->identity);
diff --git a/src/eap_server/eap_server_aka.c b/src/eap_server/eap_server_aka.c
index 09b976e..db9b6aa 100644
--- a/src/eap_server/eap_server_aka.c
+++ b/src/eap_server/eap_server_aka.c
@@ -1294,6 +1294,28 @@
}
+static u8 * eap_aka_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_aka_data *data = priv;
+ u8 *id;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ *len = 1 + EAP_AKA_RAND_LEN + EAP_AKA_AUTN_LEN;
+ id = os_malloc(*len);
+ if (id == NULL)
+ return NULL;
+
+ id[0] = data->eap_method;
+ os_memcpy(id + 1, data->rand, EAP_AKA_RAND_LEN);
+ os_memcpy(id + 1 + EAP_AKA_RAND_LEN, data->autn, EAP_AKA_AUTN_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-AKA: Derived Session-Id", id, *len);
+
+ return id;
+}
+
+
int eap_server_aka_register(void)
{
struct eap_method *eap;
@@ -1313,6 +1335,7 @@
eap->getKey = eap_aka_getKey;
eap->isSuccess = eap_aka_isSuccess;
eap->get_emsk = eap_aka_get_emsk;
+ eap->getSessionId = eap_aka_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
@@ -1342,6 +1365,7 @@
eap->getKey = eap_aka_getKey;
eap->isSuccess = eap_aka_isSuccess;
eap->get_emsk = eap_aka_get_emsk;
+ eap->getSessionId = eap_aka_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
diff --git a/src/eap_server/eap_server_fast.c b/src/eap_server/eap_server_fast.c
index 2692bce..6745100 100644
--- a/src/eap_server/eap_server_fast.c
+++ b/src/eap_server/eap_server_fast.c
@@ -186,7 +186,6 @@
switch (*pos) {
case PAC_OPAQUE_TYPE_PAD:
- pos = end;
goto done;
case PAC_OPAQUE_TYPE_KEY:
if (pos[1] != EAP_FAST_PAC_KEY_LEN) {
@@ -820,6 +819,9 @@
encr = eap_server_tls_encrypt(sm, &data->ssl, plain);
wpabuf_free(plain);
+ if (!encr)
+ return -1;
+
if (data->ssl.tls_out && piggyback) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Piggyback Phase 2 data "
"(len=%d) with last Phase 1 Message (len=%d "
@@ -1017,7 +1019,7 @@
if (m->check(sm, priv, &buf)) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 check() asked to "
"ignore the packet");
- next_type = eap_fast_req_failure(sm, data);
+ eap_fast_req_failure(sm, data);
return;
}
@@ -1590,6 +1592,18 @@
}
+static u8 * eap_fast_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_fast_data *data = priv;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ return eap_server_tls_derive_session_id(sm, &data->ssl, EAP_TYPE_FAST,
+ len);
+}
+
+
int eap_server_fast_register(void)
{
struct eap_method *eap;
@@ -1609,6 +1623,7 @@
eap->getKey = eap_fast_getKey;
eap->get_emsk = eap_fast_get_emsk;
eap->isSuccess = eap_fast_isSuccess;
+ eap->getSessionId = eap_fast_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
diff --git a/src/eap_server/eap_server_gpsk.c b/src/eap_server/eap_server_gpsk.c
index cb369e4..50f15c3 100644
--- a/src/eap_server/eap_server_gpsk.c
+++ b/src/eap_server/eap_server_gpsk.c
@@ -24,6 +24,8 @@
size_t sk_len;
u8 pk[EAP_GPSK_MAX_PK_LEN];
size_t pk_len;
+ u8 session_id[128];
+ size_t id_len;
u8 *id_peer;
size_t id_peer_len;
#define MAX_NUM_CSUITES 2
@@ -417,6 +419,21 @@
return;
}
+ if (eap_gpsk_derive_session_id(sm->user->password,
+ sm->user->password_len,
+ data->vendor, data->specifier,
+ data->rand_peer, data->rand_server,
+ data->id_peer, data->id_peer_len,
+ sm->server_id, sm->server_id_len,
+ EAP_TYPE_GPSK,
+ data->session_id, &data->id_len) < 0) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive Session-Id");
+ eap_gpsk_state(data, FAILURE);
+ return;
+ }
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Derived Session-Id",
+ data->session_id, data->id_len);
+
miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
if (end - pos < (int) miclen) {
wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
@@ -593,6 +610,24 @@
}
+static u8 * eap_gpsk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_gpsk_data *data = priv;
+ u8 *sid;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ sid = os_malloc(data->id_len);
+ if (sid == NULL)
+ return NULL;
+ os_memcpy(sid, data->session_id, data->id_len);
+ *len = data->id_len;
+
+ return sid;
+}
+
+
int eap_server_gpsk_register(void)
{
struct eap_method *eap;
@@ -612,6 +647,7 @@
eap->getKey = eap_gpsk_getKey;
eap->isSuccess = eap_gpsk_isSuccess;
eap->get_emsk = eap_gpsk_get_emsk;
+ eap->getSessionId = eap_gpsk_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
diff --git a/src/eap_server/eap_server_ikev2.c b/src/eap_server/eap_server_ikev2.c
index 65b2ef6..16e6276 100644
--- a/src/eap_server/eap_server_ikev2.c
+++ b/src/eap_server/eap_server_ikev2.c
@@ -309,6 +309,12 @@
if (data->in_buf == NULL) {
/* First fragment of the message */
+ if (message_length > 50000) {
+ /* Limit maximum memory allocation */
+ wpa_printf(MSG_DEBUG,
+ "EAP-IKEV2: Ignore too long message");
+ return -1;
+ }
data->in_buf = wpabuf_alloc(message_length);
if (data->in_buf == NULL) {
wpa_printf(MSG_DEBUG, "EAP-IKEV2: No memory for "
@@ -511,6 +517,36 @@
}
+static u8 * eap_ikev2_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_ikev2_data *data = priv;
+ u8 *sid;
+ size_t sid_len;
+ size_t offset;
+
+ if (data->state != DONE || !data->keymat_ok)
+ return NULL;
+
+ sid_len = 1 + data->ikev2.i_nonce_len + data->ikev2.r_nonce_len;
+ sid = os_malloc(sid_len);
+ if (sid) {
+ offset = 0;
+ sid[offset] = EAP_TYPE_IKEV2;
+ offset++;
+ os_memcpy(sid + offset, data->ikev2.i_nonce,
+ data->ikev2.i_nonce_len);
+ offset += data->ikev2.i_nonce_len;
+ os_memcpy(sid + offset, data->ikev2.r_nonce,
+ data->ikev2.r_nonce_len);
+ *len = sid_len;
+ wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Derived Session-Id",
+ sid, sid_len);
+ }
+
+ return sid;
+}
+
+
int eap_server_ikev2_register(void)
{
struct eap_method *eap;
@@ -531,6 +567,7 @@
eap->getKey = eap_ikev2_getKey;
eap->isSuccess = eap_ikev2_isSuccess;
eap->get_emsk = eap_ikev2_get_emsk;
+ eap->getSessionId = eap_ikev2_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
diff --git a/src/eap_server/eap_server_methods.c b/src/eap_server/eap_server_methods.c
index 0209fad..9e9dc93 100644
--- a/src/eap_server/eap_server_methods.c
+++ b/src/eap_server/eap_server_methods.c
@@ -153,7 +153,7 @@
* eap_server_get_name - Get EAP method name for the given EAP type
* @vendor: EAP Vendor-Id (0 = IETF)
* @type: EAP method type
- * Returns: EAP method name, e.g., TLS, or %NULL if not found
+ * Returns: EAP method name, e.g., TLS, or "unknown" if not found
*
* This function maps EAP type numbers into EAP type names based on the list of
* EAP methods included in the build.
@@ -167,5 +167,5 @@
if (m->vendor == vendor && m->method == type)
return m->name;
}
- return NULL;
+ return "unknown";
}
diff --git a/src/eap_server/eap_server_mschapv2.c b/src/eap_server/eap_server_mschapv2.c
index f7a753d..05848d2 100644
--- a/src/eap_server/eap_server_mschapv2.c
+++ b/src/eap_server/eap_server_mschapv2.c
@@ -414,13 +414,16 @@
}
pw_hash = pw_hash_buf;
}
- generate_authenticator_response_pwhash(
- pw_hash, peer_challenge, data->auth_challenge,
- username, username_len, nt_response,
- data->auth_response);
-
- hash_nt_password_hash(pw_hash, pw_hash_hash);
- get_master_key(pw_hash_hash, nt_response, data->master_key);
+ if (generate_authenticator_response_pwhash(
+ pw_hash, peer_challenge, data->auth_challenge,
+ username, username_len, nt_response,
+ data->auth_response) < 0 ||
+ hash_nt_password_hash(pw_hash, pw_hash_hash) < 0 ||
+ get_master_key(pw_hash_hash, nt_response,
+ data->master_key)) {
+ data->state = FAILURE;
+ return;
+ }
data->master_key_valid = 1;
wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived Master Key",
data->master_key, MSCHAPV2_KEY_LEN);
diff --git a/src/eap_server/eap_server_pax.c b/src/eap_server/eap_server_pax.c
index d9d4375..0e6b4a0 100644
--- a/src/eap_server/eap_server_pax.c
+++ b/src/eap_server/eap_server_pax.c
@@ -36,6 +36,7 @@
u8 mk[EAP_PAX_MK_LEN];
u8 ck[EAP_PAX_CK_LEN];
u8 ick[EAP_PAX_ICK_LEN];
+ u8 mid[EAP_PAX_MID_LEN];
int keys_set;
char *cid;
size_t cid_len;
@@ -148,7 +149,6 @@
(u8 *) data->cid, data->cid_len, NULL, 0, pos);
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(B, CID)",
pos, EAP_PAX_MAC_LEN);
- pos += EAP_PAX_MAC_LEN;
/* Optional ADE could be added here, if needed */
@@ -388,7 +388,7 @@
if (eap_pax_initial_key_derivation(data->mac_id, data->ak,
data->rand.e, data->mk, data->ck,
- data->ick) < 0) {
+ data->ick, data->mid) < 0) {
wpa_printf(MSG_INFO, "EAP-PAX: Failed to complete initial "
"key derivation");
data->state = FAILURE;
@@ -542,6 +542,26 @@
}
+static u8 * eap_pax_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_pax_data *data = priv;
+ u8 *sid;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ sid = os_malloc(1 + EAP_PAX_MID_LEN);
+ if (sid == NULL)
+ return NULL;
+
+ *len = 1 + EAP_PAX_MID_LEN;
+ sid[0] = EAP_TYPE_PAX;
+ os_memcpy(sid + 1, data->mid, EAP_PAX_MID_LEN);
+
+ return sid;
+}
+
+
int eap_server_pax_register(void)
{
struct eap_method *eap;
@@ -561,6 +581,7 @@
eap->getKey = eap_pax_getKey;
eap->isSuccess = eap_pax_isSuccess;
eap->get_emsk = eap_pax_get_emsk;
+ eap->getSessionId = eap_pax_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
diff --git a/src/eap_server/eap_server_peap.c b/src/eap_server/eap_server_peap.c
index 594e02d..98d608b 100644
--- a/src/eap_server/eap_server_peap.c
+++ b/src/eap_server/eap_server_peap.c
@@ -1229,6 +1229,18 @@
}
+static u8 * eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_peap_data *data = priv;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ return eap_server_tls_derive_session_id(sm, &data->ssl, EAP_TYPE_PEAP,
+ len);
+}
+
+
int eap_server_peap_register(void)
{
struct eap_method *eap;
@@ -1247,6 +1259,7 @@
eap->isDone = eap_peap_isDone;
eap->getKey = eap_peap_getKey;
eap->isSuccess = eap_peap_isSuccess;
+ eap->getSessionId = eap_peap_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
diff --git a/src/eap_server/eap_server_psk.c b/src/eap_server/eap_server_psk.c
index db394e9..12b5d25 100644
--- a/src/eap_server/eap_server_psk.c
+++ b/src/eap_server/eap_server_psk.c
@@ -485,6 +485,28 @@
}
+static u8 * eap_psk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_psk_data *data = priv;
+ u8 *id;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ *len = 1 + 2 * EAP_PSK_RAND_LEN;
+ id = os_malloc(*len);
+ if (id == NULL)
+ return NULL;
+
+ id[0] = EAP_TYPE_PSK;
+ os_memcpy(id + 1, data->rand_p, EAP_PSK_RAND_LEN);
+ os_memcpy(id + 1 + EAP_PSK_RAND_LEN, data->rand_s, EAP_PSK_RAND_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-PSK: Derived Session-Id", id, *len);
+
+ return id;
+}
+
+
int eap_server_psk_register(void)
{
struct eap_method *eap;
@@ -504,6 +526,7 @@
eap->getKey = eap_psk_getKey;
eap->isSuccess = eap_psk_isSuccess;
eap->get_emsk = eap_psk_get_emsk;
+ eap->getSessionId = eap_psk_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
diff --git a/src/eap_server/eap_server_pwd.c b/src/eap_server/eap_server_pwd.c
index 7e1278d..943af0d 100644
--- a/src/eap_server/eap_server_pwd.c
+++ b/src/eap_server/eap_server_pwd.c
@@ -1020,6 +1020,25 @@
}
+static u8 * eap_pwd_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_pwd_data *data = priv;
+ u8 *id;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ id = os_malloc(1 + SHA256_MAC_LEN);
+ if (id == NULL)
+ return NULL;
+
+ os_memcpy(id, data->session_id, 1 + SHA256_MAC_LEN);
+ *len = 1 + SHA256_MAC_LEN;
+
+ return id;
+}
+
+
int eap_server_pwd_register(void)
{
struct eap_method *eap;
@@ -1028,8 +1047,6 @@
struct timezone tz;
u32 sr;
- EVP_add_digest(EVP_sha256());
-
sr = 0xdeaddada;
(void) gettimeofday(&tp, &tz);
sr ^= (tp.tv_sec ^ tp.tv_usec);
@@ -1050,6 +1067,7 @@
eap->getKey = eap_pwd_getkey;
eap->get_emsk = eap_pwd_get_emsk;
eap->isSuccess = eap_pwd_is_success;
+ eap->getSessionId = eap_pwd_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
diff --git a/src/eap_server/eap_server_sake.c b/src/eap_server/eap_server_sake.c
index 1937621..de70777 100644
--- a/src/eap_server/eap_server_sake.c
+++ b/src/eap_server/eap_server_sake.c
@@ -495,6 +495,28 @@
}
+static u8 * eap_sake_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_sake_data *data = priv;
+ u8 *id;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ *len = 1 + 2 * EAP_SAKE_RAND_LEN;
+ id = os_malloc(*len);
+ if (id == NULL)
+ return NULL;
+
+ id[0] = EAP_TYPE_SAKE;
+ os_memcpy(id + 1, data->rand_s, EAP_SAKE_RAND_LEN);
+ os_memcpy(id + 1 + EAP_SAKE_RAND_LEN, data->rand_s, EAP_SAKE_RAND_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Derived Session-Id", id, *len);
+
+ return id;
+}
+
+
int eap_server_sake_register(void)
{
struct eap_method *eap;
@@ -514,6 +536,7 @@
eap->getKey = eap_sake_getKey;
eap->isSuccess = eap_sake_isSuccess;
eap->get_emsk = eap_sake_get_emsk;
+ eap->getSessionId = eap_sake_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
diff --git a/src/eap_server/eap_server_sim.c b/src/eap_server/eap_server_sim.c
index 23ee2b6..ddfb71c 100644
--- a/src/eap_server/eap_server_sim.c
+++ b/src/eap_server/eap_server_sim.c
@@ -820,6 +820,29 @@
}
+static u8 * eap_sim_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_sim_data *data = priv;
+ u8 *id;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ *len = 1 + data->num_chal * GSM_RAND_LEN + EAP_SIM_NONCE_MT_LEN;
+ id = os_malloc(*len);
+ if (id == NULL)
+ return NULL;
+
+ id[0] = EAP_TYPE_SIM;
+ os_memcpy(id + 1, data->rand, data->num_chal * GSM_RAND_LEN);
+ os_memcpy(id + 1 + data->num_chal * GSM_RAND_LEN, data->nonce_mt,
+ EAP_SIM_NONCE_MT_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-SIM: Derived Session-Id", id, *len);
+
+ return id;
+}
+
+
int eap_server_sim_register(void)
{
struct eap_method *eap;
@@ -839,6 +862,7 @@
eap->getKey = eap_sim_getKey;
eap->isSuccess = eap_sim_isSuccess;
eap->get_emsk = eap_sim_get_emsk;
+ eap->getSessionId = eap_sim_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
diff --git a/src/eap_server/eap_server_tls.c b/src/eap_server/eap_server_tls.c
index 6bed62f..58cfe8a 100644
--- a/src/eap_server/eap_server_tls.c
+++ b/src/eap_server/eap_server_tls.c
@@ -287,7 +287,7 @@
if (emsk)
os_memcpy(emsk, eapKeyData + EAP_TLS_KEY_LEN,
EAP_EMSK_LEN);
- os_free(eapKeyData);
+ bin_clear_free(eapKeyData, EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
} else
emsk = NULL;
@@ -310,6 +310,18 @@
}
+static u8 * eap_tls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_tls_data *data = priv;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ return eap_server_tls_derive_session_id(sm, &data->ssl, EAP_TYPE_TLS,
+ len);
+}
+
+
int eap_server_tls_register(void)
{
struct eap_method *eap;
@@ -329,6 +341,7 @@
eap->getKey = eap_tls_getKey;
eap->isSuccess = eap_tls_isSuccess;
eap->get_emsk = eap_tls_get_emsk;
+ eap->getSessionId = eap_tls_get_session_id;
ret = eap_server_method_register(eap);
if (ret)
diff --git a/src/eap_server/eap_server_tls_common.c b/src/eap_server/eap_server_tls_common.c
index 01853e6..56916c4 100644
--- a/src/eap_server/eap_server_tls_common.c
+++ b/src/eap_server/eap_server_tls_common.c
@@ -140,6 +140,47 @@
}
+/**
+ * eap_server_tls_derive_session_id - Derive a Session-Id based on TLS data
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @data: Data for TLS processing
+ * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST)
+ * @len: Pointer to length of the session ID generated
+ * Returns: Pointer to allocated Session-Id on success or %NULL on failure
+ *
+ * This function derive the Session-Id based on the TLS session data
+ * (client/server random and method type).
+ *
+ * The caller is responsible for freeing the returned buffer.
+ */
+u8 * eap_server_tls_derive_session_id(struct eap_sm *sm,
+ struct eap_ssl_data *data, u8 eap_type,
+ size_t *len)
+{
+ struct tls_keys keys;
+ u8 *out;
+
+ if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
+ return NULL;
+
+ if (keys.client_random == NULL || keys.server_random == NULL)
+ return NULL;
+
+ *len = 1 + keys.client_random_len + keys.server_random_len;
+ out = os_malloc(*len);
+ if (out == NULL)
+ return NULL;
+
+ /* Session-Id = EAP type || client.random || server.random */
+ out[0] = eap_type;
+ os_memcpy(out + 1, keys.client_random, keys.client_random_len);
+ os_memcpy(out + 1 + keys.client_random_len, keys.server_random,
+ keys.server_random_len);
+
+ return out;
+}
+
+
struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data,
int eap_type, int version, u8 id)
{
diff --git a/src/eap_server/eap_server_ttls.c b/src/eap_server/eap_server_ttls.c
index 31e3871..12a31b0 100644
--- a/src/eap_server/eap_server_ttls.c
+++ b/src/eap_server/eap_server_ttls.c
@@ -409,7 +409,7 @@
RADIUS_VENDOR_ID_MICROSOFT, 1, 43);
*pos++ = data->mschapv2_ident;
ret = os_snprintf((char *) pos, end - pos, "S=");
- if (ret >= 0 && ret < end - pos)
+ if (!os_snprintf_error(end - pos, ret))
pos += ret;
pos += wpa_snprintf_hex_uppercase(
(char *) pos, end - pos, data->mschapv2_auth_response,
@@ -1181,6 +1181,50 @@
}
+static u8 * eap_ttls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_ttls_data *data = priv;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ return eap_server_tls_derive_session_id(sm, &data->ssl, EAP_TYPE_TTLS,
+ len);
+}
+
+
+static u8 * eap_ttls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_ttls_data *data = priv;
+ u8 *eapKeyData, *emsk;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
+ "ttls keying material",
+ EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
+ if (eapKeyData) {
+ emsk = os_malloc(EAP_EMSK_LEN);
+ if (emsk)
+ os_memcpy(emsk, eapKeyData + EAP_TLS_KEY_LEN,
+ EAP_EMSK_LEN);
+ bin_clear_free(eapKeyData, EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
+ } else
+ emsk = NULL;
+
+ if (emsk) {
+ *len = EAP_EMSK_LEN;
+ wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Derived EMSK",
+ emsk, EAP_EMSK_LEN);
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive EMSK");
+ }
+
+ return emsk;
+}
+
+
int eap_server_ttls_register(void)
{
struct eap_method *eap;
@@ -1199,6 +1243,8 @@
eap->isDone = eap_ttls_isDone;
eap->getKey = eap_ttls_getKey;
eap->isSuccess = eap_ttls_isSuccess;
+ eap->getSessionId = eap_ttls_get_session_id;
+ eap->get_emsk = eap_ttls_get_emsk;
ret = eap_server_method_register(eap);
if (ret)
diff --git a/src/eap_server/eap_server_wsc.c b/src/eap_server/eap_server_wsc.c
index 97ec0c0..9d9c28d 100644
--- a/src/eap_server/eap_server_wsc.c
+++ b/src/eap_server/eap_server_wsc.c
@@ -380,7 +380,7 @@
message_length = WPA_GET_BE16(pos);
pos += 2;
- if (message_length < end - pos) {
+ if (message_length < end - pos || message_length > 50000) {
wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message "
"Length");
return;
diff --git a/src/eap_server/eap_sim_db.c b/src/eap_server/eap_sim_db.c
index bc2cbe5..acf5435 100644
--- a/src/eap_server/eap_sim_db.c
+++ b/src/eap_server/eap_sim_db.c
@@ -573,16 +573,14 @@
char buf[1000], *pos, *cmd, *imsi;
int res;
- res = recv(sock, buf, sizeof(buf), 0);
+ res = recv(sock, buf, sizeof(buf) - 1, 0);
if (res < 0)
return;
+ buf[res] = '\0';
wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-SIM DB: Received from an "
"external source", (u8 *) buf, res);
if (res == 0)
return;
- if (res >= (int) sizeof(buf))
- res = sizeof(buf) - 1;
- buf[res] = '\0';
if (data->get_complete_cb == NULL) {
wpa_printf(MSG_DEBUG, "EAP-SIM DB: No get_complete_cb "
@@ -924,12 +922,13 @@
imsi_len = os_strlen(imsi);
len = os_snprintf(msg, sizeof(msg), "SIM-REQ-AUTH ");
- if (len < 0 || len + imsi_len >= sizeof(msg))
+ if (os_snprintf_error(sizeof(msg), len) ||
+ len + imsi_len >= sizeof(msg))
return EAP_SIM_DB_FAILURE;
os_memcpy(msg + len, imsi, imsi_len);
len += imsi_len;
ret = os_snprintf(msg + len, sizeof(msg) - len, " %d", max_chal);
- if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
+ if (os_snprintf_error(sizeof(msg) - len, ret))
return EAP_SIM_DB_FAILURE;
len += ret;
@@ -966,7 +965,7 @@
pos = id;
end = id + sizeof(buf) * 2 + 2;
*pos++ = prefix;
- pos += wpa_snprintf_hex(pos, end - pos, buf, sizeof(buf));
+ wpa_snprintf_hex(pos, end - pos, buf, sizeof(buf));
return id;
}
@@ -1387,7 +1386,8 @@
imsi_len = os_strlen(imsi);
len = os_snprintf(msg, sizeof(msg), "AKA-REQ-AUTH ");
- if (len < 0 || len + imsi_len >= sizeof(msg))
+ if (os_snprintf_error(sizeof(msg), len) ||
+ len + imsi_len >= sizeof(msg))
return EAP_SIM_DB_FAILURE;
os_memcpy(msg + len, imsi, imsi_len);
len += imsi_len;
@@ -1451,19 +1451,20 @@
imsi_len = os_strlen(imsi);
len = os_snprintf(msg, sizeof(msg), "AKA-AUTS ");
- if (len < 0 || len + imsi_len >= sizeof(msg))
+ if (os_snprintf_error(sizeof(msg), len) ||
+ len + imsi_len >= sizeof(msg))
return -1;
os_memcpy(msg + len, imsi, imsi_len);
len += imsi_len;
ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
- if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
+ if (os_snprintf_error(sizeof(msg) - len, ret))
return -1;
len += ret;
len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
auts, EAP_AKA_AUTS_LEN);
ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
- if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
+ if (os_snprintf_error(sizeof(msg) - len, ret))
return -1;
len += ret;
len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
diff --git a/src/eap_server/eap_tls_common.h b/src/eap_server/eap_tls_common.h
index 91449af..ddf90b8 100644
--- a/src/eap_server/eap_tls_common.h
+++ b/src/eap_server/eap_tls_common.h
@@ -74,6 +74,9 @@
void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data);
u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
char *label, size_t len);
+u8 * eap_server_tls_derive_session_id(struct eap_sm *sm,
+ struct eap_ssl_data *data, u8 eap_type,
+ size_t *len);
struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data,
int eap_type, int version, u8 id);
struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int version);
diff --git a/src/eapol_auth/eapol_auth_dump.c b/src/eapol_auth/eapol_auth_dump.c
index 6c6969b..5579582 100644
--- a/src/eapol_auth/eapol_auth_dump.c
+++ b/src/eapol_auth/eapol_auth_dump.c
@@ -130,7 +130,7 @@
ret = os_snprintf(pos, end - pos, "aWhile=%d\nquietWhile=%d\n"
"reAuthWhen=%d\n",
sm->aWhile, sm->quietWhile, sm->reAuthWhen);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -173,7 +173,7 @@
_SB(sm->eap_if->portEnabled),
_SB(sm->portValid),
_SB(sm->reAuthenticate));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -215,7 +215,7 @@
sm->authAuthReauthsWhileAuthenticated,
sm->authAuthEapStartsWhileAuthenticated,
sm->authAuthEapLogoffWhileAuthenticated);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -240,7 +240,7 @@
sm->backendOtherRequestsToSupplicant,
sm->backendAuthSuccesses,
sm->backendAuthFails);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -251,14 +251,14 @@
reauth_timer_state_txt(sm->reauth_timer_state),
sm->reAuthPeriod,
_SB(sm->reAuthEnabled));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
ret = os_snprintf(pos, end - pos,
"auth_key_tx_state=%s\n",
auth_key_tx_state_txt(sm->auth_key_tx_state));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -267,7 +267,7 @@
"rxKey=%s\n",
key_rx_state_txt(sm->key_rx_state),
_SB(sm->rxKey));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -280,7 +280,7 @@
ctrl_dir_txt(sm->adminControlledDirections),
ctrl_dir_txt(sm->operControlledDirections),
_SB(sm->operEdge));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
#undef _SB
diff --git a/src/eapol_auth/eapol_auth_sm.c b/src/eapol_auth/eapol_auth_sm.c
index a76fa13..0df6eb5 100644
--- a/src/eapol_auth/eapol_auth_sm.c
+++ b/src/eapol_auth/eapol_auth_sm.c
@@ -1,6 +1,6 @@
/*
* IEEE 802.1X-2004 Authenticator - EAPOL state machine
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -43,6 +43,7 @@
static void eapol_sm_step_run(struct eapol_state_machine *sm);
static void eapol_sm_step_cb(void *eloop_ctx, void *timeout_ctx);
static void eapol_auth_initialize(struct eapol_state_machine *sm);
+static void eapol_auth_conf_free(struct eapol_auth_config *conf);
static void eapol_auth_logger(struct eapol_authenticator *eapol,
@@ -833,6 +834,7 @@
eap_conf.pbc_in_m1 = eapol->conf.pbc_in_m1;
eap_conf.server_id = eapol->conf.server_id;
eap_conf.server_id_len = eapol->conf.server_id_len;
+ eap_conf.erp = eapol->conf.erp;
sm->eap = eap_server_sm_init(sm, &eapol_cb, &eap_conf);
if (sm->eap == NULL) {
eapol_auth_free(sm);
@@ -851,6 +853,11 @@
sm->radius_cui = wpabuf_alloc_copy(radius_cui,
os_strlen(radius_cui));
+ sm->acct_multi_session_id_lo = eapol->acct_multi_session_id_lo++;
+ if (eapol->acct_multi_session_id_lo == 0)
+ eapol->acct_multi_session_id_hi++;
+ sm->acct_multi_session_id_hi = eapol->acct_multi_session_id_hi;
+
return sm;
}
@@ -1020,11 +1027,44 @@
}
+static int eapol_sm_get_erp_send_reauth_start(void *ctx)
+{
+ struct eapol_state_machine *sm = ctx;
+ return sm->eapol->conf.erp_send_reauth_start;
+}
+
+
+static const char * eapol_sm_get_erp_domain(void *ctx)
+{
+ struct eapol_state_machine *sm = ctx;
+ return sm->eapol->conf.erp_domain;
+}
+
+
+static struct eap_server_erp_key * eapol_sm_erp_get_key(void *ctx,
+ const char *keyname)
+{
+ struct eapol_state_machine *sm = ctx;
+ return sm->eapol->cb.erp_get_key(sm->eapol->conf.ctx, keyname);
+}
+
+
+static int eapol_sm_erp_add_key(void *ctx, struct eap_server_erp_key *erp)
+{
+ struct eapol_state_machine *sm = ctx;
+ return sm->eapol->cb.erp_add_key(sm->eapol->conf.ctx, erp);
+}
+
+
static struct eapol_callbacks eapol_cb =
{
eapol_sm_get_eap_user,
eapol_sm_get_eap_req_id_text,
- NULL
+ NULL,
+ eapol_sm_get_erp_send_reauth_start,
+ eapol_sm_get_erp_domain,
+ eapol_sm_erp_get_key,
+ eapol_sm_erp_add_key,
};
@@ -1069,21 +1109,16 @@
}
if (src->pac_opaque_encr_key) {
dst->pac_opaque_encr_key = os_malloc(16);
- if (dst->pac_opaque_encr_key == NULL) {
- os_free(dst->eap_req_id_text);
- return -1;
- }
+ if (dst->pac_opaque_encr_key == NULL)
+ goto fail;
os_memcpy(dst->pac_opaque_encr_key, src->pac_opaque_encr_key,
16);
} else
dst->pac_opaque_encr_key = NULL;
if (src->eap_fast_a_id) {
dst->eap_fast_a_id = os_malloc(src->eap_fast_a_id_len);
- if (dst->eap_fast_a_id == NULL) {
- os_free(dst->eap_req_id_text);
- os_free(dst->pac_opaque_encr_key);
- return -1;
- }
+ if (dst->eap_fast_a_id == NULL)
+ goto fail;
os_memcpy(dst->eap_fast_a_id, src->eap_fast_a_id,
src->eap_fast_a_id_len);
dst->eap_fast_a_id_len = src->eap_fast_a_id_len;
@@ -1091,12 +1126,8 @@
dst->eap_fast_a_id = NULL;
if (src->eap_fast_a_id_info) {
dst->eap_fast_a_id_info = os_strdup(src->eap_fast_a_id_info);
- if (dst->eap_fast_a_id_info == NULL) {
- os_free(dst->eap_req_id_text);
- os_free(dst->pac_opaque_encr_key);
- os_free(dst->eap_fast_a_id);
- return -1;
- }
+ if (dst->eap_fast_a_id_info == NULL)
+ goto fail;
} else
dst->eap_fast_a_id_info = NULL;
dst->eap_fast_prov = src->eap_fast_prov;
@@ -1106,7 +1137,23 @@
dst->tnc = src->tnc;
dst->wps = src->wps;
dst->fragment_size = src->fragment_size;
+
+ os_free(dst->erp_domain);
+ if (src->erp_domain) {
+ dst->erp_domain = os_strdup(src->erp_domain);
+ if (dst->erp_domain == NULL)
+ goto fail;
+ } else {
+ dst->erp_domain = NULL;
+ }
+ dst->erp_send_reauth_start = src->erp_send_reauth_start;
+ dst->erp = src->erp;
+
return 0;
+
+fail:
+ eapol_auth_conf_free(dst);
+ return -1;
}
@@ -1120,6 +1167,8 @@
conf->eap_fast_a_id = NULL;
os_free(conf->eap_fast_a_id_info);
conf->eap_fast_a_id_info = NULL;
+ os_free(conf->erp_domain);
+ conf->erp_domain = NULL;
}
@@ -1127,6 +1176,7 @@
struct eapol_auth_cb *cb)
{
struct eapol_authenticator *eapol;
+ struct os_time now;
eapol = os_zalloc(sizeof(*eapol));
if (eapol == NULL)
@@ -1152,6 +1202,14 @@
eapol->cb.abort_auth = cb->abort_auth;
eapol->cb.tx_key = cb->tx_key;
eapol->cb.eapol_event = cb->eapol_event;
+ eapol->cb.erp_get_key = cb->erp_get_key;
+ eapol->cb.erp_add_key = cb->erp_add_key;
+
+ /* Acct-Multi-Session-Id should be unique over reboots. If reliable
+ * clock is not available, this could be replaced with reboot counter,
+ * etc. */
+ os_get_time(&now);
+ eapol->acct_multi_session_id_hi = now.sec;
return eapol;
}
diff --git a/src/eapol_auth/eapol_auth_sm.h b/src/eapol_auth/eapol_auth_sm.h
index 320a0ad..ebed19a 100644
--- a/src/eapol_auth/eapol_auth_sm.h
+++ b/src/eapol_auth/eapol_auth_sm.h
@@ -24,6 +24,9 @@
void *eap_sim_db_priv;
char *eap_req_id_text; /* a copy of this will be allocated */
size_t eap_req_id_text_len;
+ int erp_send_reauth_start;
+ char *erp_domain; /* a copy of this will be allocated */
+ int erp; /* Whether ERP is enabled on authentication server */
u8 *pac_opaque_encr_key;
u8 *eap_fast_a_id;
size_t eap_fast_a_id_len;
@@ -45,6 +48,7 @@
};
struct eap_user;
+struct eap_server_erp_key;
typedef enum {
EAPOL_LOGGER_DEBUG, EAPOL_LOGGER_INFO, EAPOL_LOGGER_WARNING
@@ -71,6 +75,9 @@
void (*abort_auth)(void *ctx, void *sta_ctx);
void (*tx_key)(void *ctx, void *sta_ctx);
void (*eapol_event)(void *ctx, void *sta_ctx, enum eapol_event type);
+ struct eap_server_erp_key * (*erp_get_key)(void *ctx,
+ const char *keyname);
+ int (*erp_add_key)(void *ctx, struct eap_server_erp_key *erp);
};
diff --git a/src/eapol_auth/eapol_auth_sm_i.h b/src/eapol_auth/eapol_auth_sm_i.h
index 25baddb..a29b49c 100644
--- a/src/eapol_auth/eapol_auth_sm_i.h
+++ b/src/eapol_auth/eapol_auth_sm_i.h
@@ -30,6 +30,9 @@
u8 *default_wep_key;
u8 default_wep_key_idx;
+
+ u32 acct_multi_session_id_hi;
+ u32 acct_multi_session_id_lo;
};
@@ -175,6 +178,9 @@
void *sta; /* station context pointer to use in callbacks */
int remediation;
+
+ u32 acct_multi_session_id_hi;
+ u32 acct_multi_session_id_lo;
};
#endif /* EAPOL_AUTH_SM_I_H */
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index 70258be..621318e 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -128,6 +128,7 @@
struct wpabuf *eapReqData; /* for EAP */
Boolean altAccept; /* for EAP */
Boolean altReject; /* for EAP */
+ Boolean eapTriggerStart;
Boolean replay_counter_valid;
u8 last_replay_counter[16];
struct eapol_config conf;
@@ -222,6 +223,7 @@
SM_ENTRY(SUPP_PAE, DISCONNECTED);
sm->sPortMode = Auto;
sm->startCount = 0;
+ sm->eapTriggerStart = FALSE;
sm->logoffSent = FALSE;
eapol_sm_set_port_unauthorized(sm);
sm->suppAbort = TRUE;
@@ -244,6 +246,11 @@
{
int send_start = sm->SUPP_PAE_state == SUPP_PAE_CONNECTING;
SM_ENTRY(SUPP_PAE, CONNECTING);
+
+ if (sm->eapTriggerStart)
+ send_start = 1;
+ sm->eapTriggerStart = FALSE;
+
if (send_start) {
sm->startWhen = sm->startPeriod;
sm->startCount++;
@@ -255,7 +262,7 @@
* delay authentication. Use a short timeout to send the first
* EAPOL-Start if Authenticator does not start authentication.
*/
- if (sm->conf.wps) {
+ if (sm->conf.wps && !(sm->conf.wps & EAPOL_PEER_IS_WPS20_AP)) {
/* Reduce latency on starting WPS negotiation. */
wpa_printf(MSG_DEBUG,
"EAPOL: Using shorter startWhen for WPS");
@@ -386,6 +393,8 @@
SM_ENTER(SUPP_PAE, HELD);
else if (sm->suppTimeout)
SM_ENTER(SUPP_PAE, CONNECTING);
+ else if (sm->eapTriggerStart)
+ SM_ENTER(SUPP_PAE, CONNECTING);
break;
case SUPP_PAE_HELD:
if (sm->heldWhile == 0)
@@ -1099,7 +1108,7 @@
"suppPortStatus=%s\n",
eapol_supp_pae_state(sm->SUPP_PAE_state),
eapol_port_status(sm->suppPortStatus));
- if (len < 0 || (size_t) len >= buflen)
+ if (os_snprintf_error(buflen, len))
return 0;
if (verbose) {
@@ -1116,7 +1125,7 @@
sm->maxStart,
eapol_port_control(sm->portControl),
eapol_supp_be_state(sm->SUPP_BE_state));
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
}
@@ -1170,7 +1179,7 @@
"Authorized" : "Unauthorized",
sm->SUPP_BE_state);
- if (ret < 0 || (size_t) ret >= buflen)
+ if (os_snprintf_error(buflen, ret))
return 0;
len = ret;
@@ -1198,7 +1207,7 @@
sm->dot1xSuppLastEapolFrameVersion,
MAC2STR(sm->dot1xSuppLastEapolFrameSource));
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
@@ -1822,6 +1831,8 @@
return sm->altAccept;
case EAPOL_altReject:
return sm->altReject;
+ case EAPOL_eapTriggerStart:
+ return sm->eapTriggerStart;
}
return FALSE;
}
@@ -1861,6 +1872,9 @@
case EAPOL_altReject:
sm->altReject = value;
break;
+ case EAPOL_eapTriggerStart:
+ sm->eapTriggerStart = value;
+ break;
}
}
@@ -1948,13 +1962,14 @@
#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
static void eapol_sm_notify_cert(void *ctx, int depth, const char *subject,
- const char *cert_hash,
+ const char *altsubject[],
+ int num_altsubject, const char *cert_hash,
const struct wpabuf *cert)
{
struct eapol_sm *sm = ctx;
if (sm->ctx->cert_cb)
- sm->ctx->cert_cb(sm->ctx->ctx, depth, subject,
- cert_hash, cert);
+ sm->ctx->cert_cb(sm->ctx->ctx, depth, subject, altsubject,
+ num_altsubject, cert_hash, cert);
}
@@ -2026,6 +2041,7 @@
conf.opensc_engine_path = ctx->opensc_engine_path;
conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
conf.pkcs11_module_path = ctx->pkcs11_module_path;
+ conf.openssl_ciphers = ctx->openssl_ciphers;
conf.wps = ctx->wps;
conf.cert_in_cb = ctx->cert_in_cb;
@@ -2106,3 +2122,10 @@
return -1;
#endif /* CONFIG_EAP_PROXY */
}
+
+
+void eapol_sm_erp_flush(struct eapol_sm *sm)
+{
+ if (sm)
+ eap_peer_erp_free_keys(sm->eap);
+}
diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h
index 5b37314..d8ae9d4 100644
--- a/src/eapol_supp/eapol_supp_sm.h
+++ b/src/eapol_supp/eapol_supp_sm.h
@@ -59,6 +59,8 @@
*/
int external_sim;
+#define EAPOL_LOCAL_WPS_IN_USE BIT(0)
+#define EAPOL_PEER_IS_WPS20_AP BIT(1)
/**
* wps - Whether this connection is used for WPS
*/
@@ -210,6 +212,15 @@
const char *pkcs11_module_path;
/**
+ * openssl_ciphers - OpenSSL cipher string
+ *
+ * This is an OpenSSL specific configuration option for configuring the
+ * default ciphers. If not set, "DEFAULT:!EXP:!LOW" is used as the
+ * default.
+ */
+ const char *openssl_ciphers;
+
+ /**
* wps - WPS context data
*
* This is only used by EAP-WSC and can be left %NULL if not available.
@@ -237,10 +248,13 @@
* @ctx: Callback context (ctx)
* @depth: Depth in certificate chain (0 = server)
* @subject: Subject of the peer certificate
+ * @altsubject: Select fields from AltSubject of the peer certificate
+ * @num_altsubject: Number of altsubject values
* @cert_hash: SHA-256 hash of the certificate
* @cert: Peer certificate
*/
void (*cert_cb)(void *ctx, int depth, const char *subject,
+ const char *altsubject[], int num_altsubject,
const char *cert_hash, const struct wpabuf *cert);
/**
@@ -305,6 +319,7 @@
void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm,
struct ext_password_data *ext);
int eapol_sm_failed(struct eapol_sm *sm);
+void eapol_sm_erp_flush(struct eapol_sm *sm);
int eapol_sm_get_eap_proxy_imsi(struct eapol_sm *sm, char *imsi, size_t *len);
#else /* IEEE8021X_EAPOL */
static inline struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
@@ -405,6 +420,9 @@
{
return 0;
}
+static inline void eapol_sm_erp_flush(struct eapol_sm *sm)
+{
+}
#endif /* IEEE8021X_EAPOL */
#endif /* EAPOL_SUPP_SM_H */
diff --git a/src/l2_packet/l2_packet.h b/src/l2_packet/l2_packet.h
index dd825b5..7537f93 100644
--- a/src/l2_packet/l2_packet.h
+++ b/src/l2_packet/l2_packet.h
@@ -39,6 +39,11 @@
#pragma pack(pop)
#endif /* _MSC_VER */
+enum l2_packet_filter_type {
+ L2_PACKET_FILTER_DHCP,
+ L2_PACKET_FILTER_NDISC,
+};
+
/**
* l2_packet_init - Initialize l2_packet interface
* @ifname: Interface name
@@ -121,4 +126,16 @@
*/
void l2_packet_notify_auth_start(struct l2_packet_data *l2);
+/**
+ * l2_packet_set_packet_filter - Set socket filter for l2_packet
+ * @l2: Pointer to internal l2_packet data from l2_packet_init()
+ * @type: enum l2_packet_filter_type, type of filter
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to set the socket filter for l2_packet socket.
+ *
+ */
+int l2_packet_set_packet_filter(struct l2_packet_data *l2,
+ enum l2_packet_filter_type type);
+
#endif /* L2_PACKET_H */
diff --git a/src/l2_packet/l2_packet_freebsd.c b/src/l2_packet/l2_packet_freebsd.c
index 2e9a04c..d87c32b 100644
--- a/src/l2_packet/l2_packet_freebsd.c
+++ b/src/l2_packet/l2_packet_freebsd.c
@@ -308,3 +308,10 @@
void l2_packet_notify_auth_start(struct l2_packet_data *l2)
{
}
+
+
+int l2_packet_set_packet_filter(struct l2_packet_data *l2,
+ enum l2_packet_filter_type type)
+{
+ return -1;
+}
diff --git a/src/l2_packet/l2_packet_linux.c b/src/l2_packet/l2_packet_linux.c
index 1419830..89ff7db 100644
--- a/src/l2_packet/l2_packet_linux.c
+++ b/src/l2_packet/l2_packet_linux.c
@@ -10,6 +10,7 @@
#include <sys/ioctl.h>
#include <netpacket/packet.h>
#include <net/if.h>
+#include <linux/filter.h>
#include "common.h"
#include "eloop.h"
@@ -28,6 +29,50 @@
* buffers */
};
+/* Generated by 'sudo tcpdump -s 3000 -dd greater 278 and ip and udp and
+ * src port bootps and dst port bootpc'
+ */
+static struct sock_filter dhcp_sock_filter_insns[] = {
+ { 0x80, 0, 0, 0x00000000 },
+ { 0x35, 0, 12, 0x00000116 },
+ { 0x28, 0, 0, 0x0000000c },
+ { 0x15, 0, 10, 0x00000800 },
+ { 0x30, 0, 0, 0x00000017 },
+ { 0x15, 0, 8, 0x00000011 },
+ { 0x28, 0, 0, 0x00000014 },
+ { 0x45, 6, 0, 0x00001fff },
+ { 0xb1, 0, 0, 0x0000000e },
+ { 0x48, 0, 0, 0x0000000e },
+ { 0x15, 0, 3, 0x00000043 },
+ { 0x48, 0, 0, 0x00000010 },
+ { 0x15, 0, 1, 0x00000044 },
+ { 0x6, 0, 0, 0x00000bb8 },
+ { 0x6, 0, 0, 0x00000000 },
+};
+
+static const struct sock_fprog dhcp_sock_filter = {
+ .len = ARRAY_SIZE(dhcp_sock_filter_insns),
+ .filter = dhcp_sock_filter_insns,
+};
+
+
+/* Generated by 'sudo tcpdump -dd -s 1500 multicast and ip6[6]=58' */
+static struct sock_filter ndisc_sock_filter_insns[] = {
+ { 0x30, 0, 0, 0x00000000 },
+ { 0x45, 0, 5, 0x00000001 },
+ { 0x28, 0, 0, 0x0000000c },
+ { 0x15, 0, 3, 0x000086dd },
+ { 0x30, 0, 0, 0x00000014 },
+ { 0x15, 0, 1, 0x0000003a },
+ { 0x6, 0, 0, 0x000005dc },
+ { 0x6, 0, 0, 0x00000000 },
+};
+
+static const struct sock_fprog ndisc_sock_filter = {
+ .len = ARRAY_SIZE(ndisc_sock_filter_insns),
+ .filter = ndisc_sock_filter_insns,
+};
+
int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
{
@@ -202,3 +247,31 @@
void l2_packet_notify_auth_start(struct l2_packet_data *l2)
{
}
+
+
+int l2_packet_set_packet_filter(struct l2_packet_data *l2,
+ enum l2_packet_filter_type type)
+{
+ const struct sock_fprog *sock_filter;
+
+ switch (type) {
+ case L2_PACKET_FILTER_DHCP:
+ sock_filter = &dhcp_sock_filter;
+ break;
+ case L2_PACKET_FILTER_NDISC:
+ sock_filter = &ndisc_sock_filter;
+ break;
+ default:
+ return -1;
+ }
+
+ if (setsockopt(l2->fd, SOL_SOCKET, SO_ATTACH_FILTER,
+ sock_filter, sizeof(struct sock_fprog))) {
+ wpa_printf(MSG_ERROR,
+ "l2_packet_linux: setsockopt(SO_ATTACH_FILTER) failed: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/l2_packet/l2_packet_ndis.c b/src/l2_packet/l2_packet_ndis.c
index 23b8ddc..39a62a0 100644
--- a/src/l2_packet/l2_packet_ndis.c
+++ b/src/l2_packet/l2_packet_ndis.c
@@ -514,3 +514,10 @@
void l2_packet_notify_auth_start(struct l2_packet_data *l2)
{
}
+
+
+int l2_packet_set_packet_filter(struct l2_packet_data *l2,
+ enum l2_packet_filter_type type)
+{
+ return -1;
+}
diff --git a/src/l2_packet/l2_packet_none.c b/src/l2_packet/l2_packet_none.c
index 6896c4e..0501925 100644
--- a/src/l2_packet/l2_packet_none.c
+++ b/src/l2_packet/l2_packet_none.c
@@ -116,3 +116,10 @@
{
/* This function can be left empty */
}
+
+
+int l2_packet_set_packet_filter(struct l2_packet_data *l2,
+ enum l2_packet_filter_type type)
+{
+ return -1;
+}
diff --git a/src/l2_packet/l2_packet_pcap.c b/src/l2_packet/l2_packet_pcap.c
index 45aef56..bb4f4a3 100644
--- a/src/l2_packet/l2_packet_pcap.c
+++ b/src/l2_packet/l2_packet_pcap.c
@@ -54,15 +54,16 @@
l2->eth = eth_open(l2->ifname);
if (!l2->eth) {
- printf("Failed to open interface '%s'.\n", l2->ifname);
- perror("eth_open");
+ wpa_printf(MSG_ERROR,
+ "Failed to open interface '%s' - eth_open: %s",
+ l2->ifname, strerror(errno));
return -1;
}
if (eth_get(l2->eth, &own_addr) < 0) {
- printf("Failed to get own hw address from interface '%s'.\n",
- l2->ifname);
- perror("eth_get");
+ wpa_printf(MSG_ERROR,
+ "Failed to get own hw address from interface '%s' - eth_get: %s",
+ l2->ifname, strerror(errno));
eth_close(l2->eth);
l2->eth = NULL;
return -1;
@@ -378,3 +379,10 @@
l2, l2->pcap);
#endif /* CONFIG_WINPCAP */
}
+
+
+int l2_packet_set_packet_filter(struct l2_packet_data *l2,
+ enum l2_packet_filter_type type)
+{
+ return -1;
+}
diff --git a/src/l2_packet/l2_packet_privsep.c b/src/l2_packet/l2_packet_privsep.c
index 6b117ca..76dcccc 100644
--- a/src/l2_packet/l2_packet_privsep.c
+++ b/src/l2_packet/l2_packet_privsep.c
@@ -44,7 +44,7 @@
msg.msg_namelen = sizeof(l2->priv_addr);
if (sendmsg(l2->fd, &msg, 0) < 0) {
- perror("L2: sendmsg(cmd)");
+ wpa_printf(MSG_ERROR, "L2: sendmsg(cmd): %s", strerror(errno));
return -1;
}
@@ -82,7 +82,8 @@
msg.msg_namelen = sizeof(l2->priv_addr);
if (sendmsg(l2->fd, &msg, 0) < 0) {
- perror("L2: sendmsg(packet_send)");
+ wpa_printf(MSG_ERROR, "L2: sendmsg(packet_send): %s",
+ strerror(errno));
return -1;
}
@@ -102,7 +103,8 @@
res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &from,
&fromlen);
if (res < 0) {
- perror("l2_packet_receive - recvfrom");
+ wpa_printf(MSG_ERROR, "l2_packet_receive - recvfrom: %s",
+ strerror(errno));
return;
}
if (res < ETH_ALEN) {
@@ -162,7 +164,7 @@
l2->fd = socket(PF_UNIX, SOCK_DGRAM, 0);
if (l2->fd < 0) {
- perror("socket(PF_UNIX)");
+ wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
os_free(l2->own_socket_path);
l2->own_socket_path = NULL;
os_free(l2);
@@ -173,7 +175,8 @@
addr.sun_family = AF_UNIX;
os_strlcpy(addr.sun_path, l2->own_socket_path, sizeof(addr.sun_path));
if (bind(l2->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("l2-pkt-privsep: bind(PF_UNIX)");
+ wpa_printf(MSG_ERROR, "l2-pkt-privsep: bind(PF_UNIX): %s",
+ strerror(errno));
goto fail;
}
@@ -191,14 +194,14 @@
tv.tv_usec = 0;
res = select(l2->fd + 1, &rfds, NULL, NULL, &tv);
if (res < 0 && errno != EINTR) {
- perror("select");
+ wpa_printf(MSG_ERROR, "select: %s", strerror(errno));
goto fail;
}
if (FD_ISSET(l2->fd, &rfds)) {
res = recv(l2->fd, reply, sizeof(reply), 0);
if (res < 0) {
- perror("recv");
+ wpa_printf(MSG_ERROR, "recv: %s", strerror(errno));
goto fail;
}
} else {
@@ -259,3 +262,10 @@
{
wpa_priv_cmd(l2, PRIVSEP_CMD_L2_NOTIFY_AUTH_START, NULL, 0);
}
+
+
+int l2_packet_set_packet_filter(struct l2_packet_data *l2,
+ enum l2_packet_filter_type type)
+{
+ return -1;
+}
diff --git a/src/lib.rules b/src/lib.rules
index b260d25..0c79d99 100644
--- a/src/lib.rules
+++ b/src/lib.rules
@@ -15,6 +15,10 @@
Q=
E=true
endif
+ifeq ($(QUIET), 1)
+Q=@
+E=true
+endif
%.o: %.c
$(Q)$(CC) -c -o $@ $(CFLAGS) $<
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 7d4a03c..f3e31a8 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -211,29 +211,35 @@
}
-void p2p_go_neg_failed(struct p2p_data *p2p, struct p2p_device *peer,
- int status)
+void p2p_go_neg_failed(struct p2p_data *p2p, int status)
{
struct p2p_go_neg_results res;
- p2p_clear_timeout(p2p);
- p2p_set_state(p2p, P2P_IDLE);
- if (p2p->go_neg_peer) {
- p2p->go_neg_peer->flags &= ~P2P_DEV_PEER_WAITING_RESPONSE;
- p2p->go_neg_peer->wps_method = WPS_NOT_READY;
- p2p->go_neg_peer->oob_pw_id = 0;
+ struct p2p_device *peer = p2p->go_neg_peer;
+
+ if (!peer)
+ return;
+
+ eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
+ if (p2p->state != P2P_SEARCH) {
+ /*
+ * Clear timeouts related to GO Negotiation if no new p2p_find
+ * has been started.
+ */
+ p2p_clear_timeout(p2p);
+ p2p_set_state(p2p, P2P_IDLE);
}
+
+ peer->flags &= ~P2P_DEV_PEER_WAITING_RESPONSE;
+ peer->wps_method = WPS_NOT_READY;
+ peer->oob_pw_id = 0;
+ wpabuf_free(peer->go_neg_conf);
+ peer->go_neg_conf = NULL;
p2p->go_neg_peer = NULL;
os_memset(&res, 0, sizeof(res));
res.status = status;
- if (peer) {
- wpabuf_free(peer->go_neg_conf);
- peer->go_neg_conf = NULL;
- os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr,
- ETH_ALEN);
- os_memcpy(res.peer_interface_addr, peer->intended_addr,
- ETH_ALEN);
- }
+ os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr, ETH_ALEN);
+ os_memcpy(res.peer_interface_addr, peer->intended_addr, ETH_ALEN);
p2p->cfg->go_neg_completed(p2p->cfg->cb_ctx, &res);
}
@@ -348,8 +354,10 @@
static void p2p_device_clear_reported(struct p2p_data *p2p)
{
struct p2p_device *dev;
- dl_list_for_each(dev, &p2p->devices, struct p2p_device, list)
+ dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
dev->flags &= ~P2P_DEV_REPORTED;
+ dev->sd_reqs = 0;
+ }
}
@@ -650,6 +658,24 @@
}
+static int p2p_compare_wfd_info(struct p2p_device *dev,
+ const struct p2p_message *msg)
+{
+ if (dev->info.wfd_subelems && msg->wfd_subelems) {
+ if (dev->info.wfd_subelems->used != msg->wfd_subelems->used)
+ return 1;
+
+ return os_memcmp(dev->info.wfd_subelems->buf,
+ msg->wfd_subelems->buf,
+ dev->info.wfd_subelems->used);
+ }
+ if (dev->info.wfd_subelems || msg->wfd_subelems)
+ return 1;
+
+ return 0;
+}
+
+
/**
* p2p_add_device - Add peer entries based on scan results or P2P frames
* @p2p: P2P module context from p2p_init()
@@ -675,6 +701,7 @@
struct p2p_device *dev;
struct p2p_message msg;
const u8 *p2p_dev_addr;
+ int wfd_changed;
int i;
struct os_reltime time_now;
@@ -786,6 +813,8 @@
break;
}
+ wfd_changed = p2p_compare_wfd_info(dev, &msg);
+
if (msg.wfd_subelems) {
wpabuf_free(dev->info.wfd_subelems);
dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
@@ -800,7 +829,7 @@
p2p_update_peer_vendor_elems(dev, ies, ies_len);
- if (dev->flags & P2P_DEV_REPORTED)
+ if (dev->flags & P2P_DEV_REPORTED && !wfd_changed)
return 0;
p2p_dbg(p2p, "Peer found with Listen frequency %d MHz (rx_time=%u.%06u)",
@@ -848,8 +877,7 @@
/*
* If GO Negotiation is in progress, report that it has failed.
*/
- p2p_go_neg_failed(p2p, dev, -1);
- p2p->go_neg_peer = NULL;
+ p2p_go_neg_failed(p2p, -1);
}
if (p2p->invite_peer == dev)
p2p->invite_peer = NULL;
@@ -956,14 +984,8 @@
p2p->num_req_dev_types, p2p->req_dev_types,
p2p->find_dev_id, pw_id);
if (res < 0) {
- p2p_dbg(p2p, "Scan request failed");
+ p2p_dbg(p2p, "Scan request schedule failed");
p2p_continue_find(p2p);
- } else {
- p2p_dbg(p2p, "Running p2p_scan");
- p2p->p2p_scan_running = 1;
- eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
- eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout,
- p2p, NULL);
}
}
@@ -976,6 +998,22 @@
}
+void p2p_notify_scan_trigger_status(struct p2p_data *p2p, int status)
+{
+ if (status != 0) {
+ p2p_dbg(p2p, "Scan request failed");
+ /* Do continue find even for the first p2p_find_scan */
+ p2p_continue_find(p2p);
+ } else {
+ p2p_dbg(p2p, "Running p2p_scan");
+ p2p->p2p_scan_running = 1;
+ eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
+ eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout,
+ p2p, NULL);
+ }
+}
+
+
static int p2p_run_after_scan(struct p2p_data *p2p)
{
struct p2p_device *dev;
@@ -1106,17 +1144,11 @@
return -1;
}
- if (res == 0) {
- p2p_dbg(p2p, "Running p2p_scan");
- p2p->p2p_scan_running = 1;
- eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
- eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout,
- p2p, NULL);
- } else if (p2p->p2p_scan_running) {
+ if (res != 0 && p2p->p2p_scan_running) {
p2p_dbg(p2p, "Failed to start p2p_scan - another p2p_scan was already running");
/* wait for the previous p2p_scan to complete */
res = 0; /* do not report failure */
- } else {
+ } else if (res != 0) {
p2p_dbg(p2p, "Failed to start p2p_scan");
p2p_set_state(p2p, P2P_IDLE);
eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
@@ -1334,8 +1366,8 @@
if (go)
p2p_channels_remove_freqs(&p2p->channels, &p2p->no_go_freq);
else if (!force_freq)
- p2p_channels_union(&p2p->channels, &p2p->cfg->cli_channels,
- &p2p->channels);
+ p2p_channels_union_inplace(&p2p->channels,
+ &p2p->cfg->cli_channels);
p2p_channels_dump(p2p, "after go/cli filter/add", &p2p->channels);
p2p_dbg(p2p, "Own preference for operation channel: Operating Class %u Channel %u%s",
@@ -1616,8 +1648,6 @@
struct p2p_go_neg_results res;
int go = peer->go_state == LOCAL_GO;
struct p2p_channels intersection;
- int freqs;
- size_t i, j;
p2p_dbg(p2p, "GO Negotiation with " MACSTR " completed (%s will be GO)",
MAC2STR(peer->info.p2p_device_addr), go ? "local end" : "peer");
@@ -1658,21 +1688,9 @@
p2p_channels_dump(p2p, "intersection after no-GO removal",
&intersection);
}
- freqs = 0;
- for (i = 0; i < intersection.reg_classes; i++) {
- struct p2p_reg_class *c = &intersection.reg_class[i];
- if (freqs + 1 == P2P_MAX_CHANNELS)
- break;
- for (j = 0; j < c->channels; j++) {
- int freq;
- if (freqs + 1 == P2P_MAX_CHANNELS)
- break;
- freq = p2p_channel_to_freq(c->reg_class, c->channel[j]);
- if (freq < 0)
- continue;
- res.freq_list[freqs++] = freq;
- }
- }
+
+ p2p_channels_to_freqs(&intersection, res.freq_list,
+ P2P_MAX_CHANNELS);
res.peer_config_timeout = go ? peer->client_timeout : peer->go_timeout;
@@ -1713,7 +1731,6 @@
rx_freq);
break;
case P2P_INVITATION_RESP:
- p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
p2p_process_invitation_resp(p2p, sa, data + 1, len - 1);
break;
case P2P_PROV_DISC_REQ:
@@ -1992,11 +2009,12 @@
attr.num_req_dev_type))
return 1; /* Own Primary Device Type matches */
- for (i = 0; i < p2p->cfg->num_sec_dev_types; i++)
+ for (i = 0; i < p2p->cfg->num_sec_dev_types; i++) {
if (dev_type_list_match(p2p->cfg->sec_dev_type[i],
attr.req_dev_type,
attr.num_req_dev_type))
- return 1; /* Own Secondary Device Type matches */
+ return 1; /* Own Secondary Device Type matches */
+ }
/* No matching device type found */
return 0;
@@ -2541,6 +2559,7 @@
eloop_cancel_timeout(p2p_ext_listen_timeout, p2p, NULL);
eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
eloop_cancel_timeout(p2p_go_neg_start, p2p, NULL);
+ eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
p2p_flush(p2p);
p2p_free_req_dev_types(p2p);
os_free(p2p->cfg->dev_name);
@@ -2583,8 +2602,10 @@
p2p_dbg(p2p, "Unauthorizing " MACSTR, MAC2STR(addr));
- if (p2p->go_neg_peer == dev)
+ if (p2p->go_neg_peer == dev) {
+ eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
p2p->go_neg_peer = NULL;
+ }
dev->wps_method = WPS_NOT_READY;
dev->oob_pw_id = 0;
@@ -2742,28 +2763,64 @@
}
+static int p2p_pre_find_operation(struct p2p_data *p2p, struct p2p_device *dev)
+{
+ if (dev->sd_pending_bcast_queries == 0) {
+ /* Initialize with total number of registered broadcast
+ * SD queries. */
+ dev->sd_pending_bcast_queries = p2p->num_p2p_sd_queries;
+ }
+
+ if (p2p_start_sd(p2p, dev) == 0)
+ return 1;
+
+ if (dev->req_config_methods &&
+ !(dev->flags & P2P_DEV_PD_FOR_JOIN)) {
+ p2p_dbg(p2p, "Send pending Provision Discovery Request to "
+ MACSTR " (config methods 0x%x)",
+ MAC2STR(dev->info.p2p_device_addr),
+ dev->req_config_methods);
+ if (p2p_send_prov_disc_req(p2p, dev, 0, 0) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+
void p2p_continue_find(struct p2p_data *p2p)
{
struct p2p_device *dev;
- p2p_set_state(p2p, P2P_SEARCH);
- dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
- if (dev->sd_pending_bcast_queries == 0) {
- /* Initialize with total number of registered broadcast
- * SD queries. */
- dev->sd_pending_bcast_queries = p2p->num_p2p_sd_queries;
- }
+ int found;
- if (p2p_start_sd(p2p, dev) == 0)
- return;
- if (dev->req_config_methods &&
- !(dev->flags & P2P_DEV_PD_FOR_JOIN)) {
- p2p_dbg(p2p, "Send pending Provision Discovery Request to "
- MACSTR " (config methods 0x%x)",
- MAC2STR(dev->info.p2p_device_addr),
- dev->req_config_methods);
- if (p2p_send_prov_disc_req(p2p, dev, 0, 0) == 0)
- return;
+ p2p_set_state(p2p, P2P_SEARCH);
+
+ /* Continue from the device following the last iteration */
+ found = 0;
+ dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
+ if (dev == p2p->last_p2p_find_oper) {
+ found = 1;
+ continue;
}
+ if (!found)
+ continue;
+ if (p2p_pre_find_operation(p2p, dev) > 0) {
+ p2p->last_p2p_find_oper = dev;
+ return;
+ }
+ }
+
+ /*
+ * Wrap around to the beginning of the list and continue until the last
+ * iteration device.
+ */
+ dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
+ if (p2p_pre_find_operation(p2p, dev) > 0) {
+ p2p->last_p2p_find_oper = dev;
+ return;
+ }
+ if (dev == p2p->last_p2p_find_oper)
+ break;
}
p2p_listen_in_find(p2p, 1);
@@ -2777,6 +2834,8 @@
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
if (!success) {
+ if (p2p->sd_peer)
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
p2p->sd_peer = NULL;
p2p_continue_find(p2p);
return;
@@ -2788,7 +2847,7 @@
return;
}
- if (p2p->sd_query->for_all_peers) {
+ if (p2p->sd_query && p2p->sd_query->for_all_peers) {
/* Update the pending broadcast SD query count for this device
*/
p2p->sd_peer->sd_pending_bcast_queries--;
@@ -3057,8 +3116,7 @@
{
p2p_dbg(p2p, "GO Negotiation Response (failure) TX callback: success=%d", success);
if (p2p->go_neg_peer && p2p->go_neg_peer->status != P2P_SC_SUCCESS) {
- p2p_go_neg_failed(p2p, p2p->go_neg_peer,
- p2p->go_neg_peer->status);
+ p2p_go_neg_failed(p2p, p2p->go_neg_peer->status);
} else if (success) {
struct p2p_device *dev;
dev = p2p_get_device(p2p, addr);
@@ -3086,7 +3144,7 @@
p2p_dbg(p2p, "GO Negotiation Confirm TX callback: result=%d", result);
if (result == P2P_SEND_ACTION_FAILED) {
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
- p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
+ p2p_go_neg_failed(p2p, -1);
return;
}
@@ -3257,7 +3315,7 @@
if (p2p->state == P2P_CONNECT_LISTEN && p2p->go_neg_peer) {
if (p2p->go_neg_peer->connect_reqs >= 120) {
p2p_dbg(p2p, "Timeout on sending GO Negotiation Request without getting response");
- p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
+ p2p_go_neg_failed(p2p, -1);
return 0;
}
@@ -3308,7 +3366,7 @@
if (p2p->go_neg_peer &&
(p2p->go_neg_peer->flags & P2P_DEV_WAIT_GO_NEG_CONFIRM)) {
p2p_dbg(p2p, "Wait for GO Negotiation Confirm timed out - assume GO Negotiation failed");
- p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
+ p2p_go_neg_failed(p2p, -1);
return;
}
if (p2p->go_neg_peer &&
@@ -3339,7 +3397,7 @@
if (p2p->go_neg_peer->connect_reqs >= 120) {
p2p_dbg(p2p, "Timeout on sending GO Negotiation Request without getting response");
- p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
+ p2p_go_neg_failed(p2p, -1);
return;
}
@@ -3365,20 +3423,12 @@
static void p2p_timeout_wait_peer_idle(struct p2p_data *p2p)
{
struct p2p_device *dev = p2p->go_neg_peer;
- struct os_reltime now;
if (dev == NULL) {
p2p_dbg(p2p, "Unknown GO Neg peer - stop GO Neg wait");
return;
}
- os_get_reltime(&now);
- if (os_reltime_expired(&now, &dev->go_neg_wait_started, 120)) {
- p2p_dbg(p2p, "Timeout on waiting peer to become ready for GO Negotiation");
- p2p_go_neg_failed(p2p, dev, -1);
- return;
- }
-
p2p_dbg(p2p, "Go to Listen state while waiting for the peer to become ready for GO Negotiation");
p2p_set_state(p2p, P2P_WAIT_PEER_CONNECT);
p2p_listen_in_find(p2p, 0);
@@ -3489,6 +3539,10 @@
p2p_dbg(p2p, "Timeout (state=%s)", p2p_state_txt(p2p->state));
p2p->in_listen = 0;
+ if (p2p->drv_in_listen) {
+ p2p_dbg(p2p, "Driver is still in listen state - stop it");
+ p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
+ }
switch (p2p->state) {
case P2P_IDLE:
@@ -3704,7 +3758,7 @@
"[PD_FOR_JOIN]" : "",
dev->status,
dev->invitation_reqs);
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
@@ -3714,7 +3768,7 @@
"ext_listen_interval=%u\n",
dev->ext_listen_period,
dev->ext_listen_interval);
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
}
@@ -3724,7 +3778,7 @@
"oper_ssid=%s\n",
wpa_ssid_txt(dev->oper_ssid,
dev->oper_ssid_len));
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
}
@@ -3732,7 +3786,7 @@
#ifdef CONFIG_WIFI_DISPLAY
if (dev->info.wfd_subelems) {
res = os_snprintf(pos, end - pos, "wfd_subelems=");
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
@@ -3741,7 +3795,7 @@
wpabuf_len(dev->info.wfd_subelems));
res = os_snprintf(pos, end - pos, "\n");
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
}
@@ -4859,3 +4913,13 @@
{
p2p->vendor_elem = vendor_elem;
}
+
+
+void p2p_go_neg_wait_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct p2p_data *p2p = eloop_ctx;
+
+ p2p_dbg(p2p,
+ "Timeout on waiting peer to become ready for GO Negotiation");
+ p2p_go_neg_failed(p2p, -1);
+}
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 076a2ac..fa886f7 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -949,6 +949,13 @@
const u8 *dev_id, unsigned int search_delay);
/**
+ * p2p_notify_scan_trigger_status - Indicate scan trigger status
+ * @p2p: P2P module context from p2p_init()
+ * @status: 0 on success, -1 on failure
+ */
+void p2p_notify_scan_trigger_status(struct p2p_data *p2p, int status);
+
+/**
* p2p_stop_find - Stop P2P Find (Device Discovery)
* @p2p: P2P module context from p2p_init()
*/
@@ -1738,6 +1745,9 @@
int p2p_channels_includes_freq(const struct p2p_channels *channels,
unsigned int freq);
+int p2p_channels_to_freqs(const struct p2p_channels *channels,
+ int *freq_list, unsigned int max_len);
+
/**
* p2p_supported_freq - Check whether channel is supported for P2P
* @p2p: P2P module context from p2p_init()
@@ -1912,7 +1922,8 @@
/**
* p2p_in_progress - Check whether a P2P operation is progress
* @p2p: P2P module context from p2p_init()
- * Returns: 0 if P2P module is idle or 1 if an operation is in progress
+ * Returns: 0 if P2P module is idle, 1 if an operation is in progress but not
+ * in search state, or 2 if search state operation is in progress
*/
int p2p_in_progress(struct p2p_data *p2p);
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index 21fae3f..c654c5a 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -9,6 +9,7 @@
#include "includes.h"
#include "common.h"
+#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "common/wpa_ctrl.h"
#include "wps/wps_defs.h"
@@ -240,6 +241,7 @@
p2p_set_state(p2p, P2P_CONNECT);
p2p->pending_action_state = P2P_PENDING_GO_NEG_REQUEST;
p2p->go_neg_peer = dev;
+ eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
dev->flags |= P2P_DEV_WAIT_GO_NEG_RESPONSE;
dev->connect_reqs++;
if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
@@ -621,7 +623,7 @@
* Request frame.
*/
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
- p2p_go_neg_failed(p2p, dev, *msg.status);
+ p2p_go_neg_failed(p2p, *msg.status);
p2p_parse_free(&msg);
return;
}
@@ -645,6 +647,9 @@
p2p_add_dev_info(p2p, sa, dev, &msg);
}
+ if (p2p->go_neg_peer && p2p->go_neg_peer == dev)
+ eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
+
if (dev && dev->flags & P2P_DEV_USER_REJECTED) {
p2p_dbg(p2p, "User has rejected this peer");
status = P2P_SC_FAIL_REJECTED_BY_USER;
@@ -789,6 +794,7 @@
dev->dialog_token = msg.dialog_token;
os_memcpy(dev->intended_addr, msg.intended_addr, ETH_ALEN);
p2p->go_neg_peer = dev;
+ eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
status = P2P_SC_SUCCESS;
}
@@ -957,7 +963,10 @@
if (*msg.status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
p2p_dbg(p2p, "Wait for the peer to become ready for GO Negotiation");
dev->flags |= P2P_DEV_NOT_YET_READY;
- os_get_reltime(&dev->go_neg_wait_started);
+ eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p,
+ NULL);
+ eloop_register_timeout(120, 0, p2p_go_neg_wait_timeout,
+ p2p, NULL);
if (p2p->state == P2P_CONNECT_LISTEN)
p2p_set_state(p2p, P2P_WAIT_PEER_CONNECT);
else
@@ -965,7 +974,7 @@
p2p_set_timeout(p2p, 0, 0);
} else {
p2p_dbg(p2p, "Stop GO Negotiation attempt");
- p2p_go_neg_failed(p2p, dev, *msg.status);
+ p2p_go_neg_failed(p2p, *msg.status);
}
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
p2p_parse_free(&msg);
@@ -1147,13 +1156,13 @@
wpabuf_head(dev->go_neg_conf),
wpabuf_len(dev->go_neg_conf), 200) < 0) {
p2p_dbg(p2p, "Failed to send Action frame");
- p2p_go_neg_failed(p2p, dev, -1);
+ p2p_go_neg_failed(p2p, -1);
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
} else
dev->go_neg_conf_sent++;
if (status != P2P_SC_SUCCESS) {
p2p_dbg(p2p, "GO Negotiation failed");
- p2p_go_neg_failed(p2p, dev, status);
+ p2p_go_neg_failed(p2p, status);
}
}
@@ -1204,7 +1213,7 @@
}
if (*msg.status) {
p2p_dbg(p2p, "GO Negotiation rejected: status %d", *msg.status);
- p2p_go_neg_failed(p2p, dev, *msg.status);
+ p2p_go_neg_failed(p2p, *msg.status);
p2p_parse_free(&msg);
return;
}
@@ -1216,7 +1225,7 @@
} else if (dev->go_state == REMOTE_GO) {
p2p_dbg(p2p, "Mandatory P2P Group ID attribute missing from GO Negotiation Confirmation");
p2p->ssid_len = 0;
- p2p_go_neg_failed(p2p, dev, P2P_SC_FAIL_INVALID_PARAMS);
+ p2p_go_neg_failed(p2p, P2P_SC_FAIL_INVALID_PARAMS);
p2p_parse_free(&msg);
return;
}
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 3b60582..62711e7 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -101,10 +101,10 @@
unsigned int flags;
int status; /* enum p2p_status_code */
- struct os_reltime go_neg_wait_started;
unsigned int wait_count;
unsigned int connect_reqs;
unsigned int invitation_reqs;
+ unsigned int sd_reqs;
u16 ext_listen_period;
u16 ext_listen_interval;
@@ -260,10 +260,18 @@
*/
struct p2p_device *invite_peer;
+ /**
+ * last_p2p_find_oper - Pointer to last pre-find operation peer
+ */
+ struct p2p_device *last_p2p_find_oper;
+
const u8 *invite_go_dev_addr;
u8 invite_go_dev_addr_buf[ETH_ALEN];
int invite_dev_pw_id;
+ unsigned int retry_invite_req:1;
+ unsigned int retry_invite_req_sent:1;
+
/**
* sd_peer - Pointer to Service Discovery peer
*/
@@ -606,6 +614,8 @@
void p2p_channels_intersect(const struct p2p_channels *a,
const struct p2p_channels *b,
struct p2p_channels *res);
+void p2p_channels_union_inplace(struct p2p_channels *res,
+ const struct p2p_channels *b);
void p2p_channels_union(const struct p2p_channels *a,
const struct p2p_channels *b,
struct p2p_channels *res);
@@ -768,8 +778,7 @@
struct p2p_device * p2p_get_device(struct p2p_data *p2p, const u8 *addr);
struct p2p_device * p2p_get_device_interface(struct p2p_data *p2p,
const u8 *addr);
-void p2p_go_neg_failed(struct p2p_data *p2p, struct p2p_device *peer,
- int status);
+void p2p_go_neg_failed(struct p2p_data *p2p, int status);
void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer);
int p2p_match_dev_type(struct p2p_data *p2p, struct wpabuf *wps);
int dev_type_list_match(const u8 *dev_type, const u8 *req_dev_type[],
@@ -783,6 +792,7 @@
int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
unsigned int force_freq, unsigned int pref_freq,
int go);
+void p2p_go_neg_wait_timeout(void *eloop_ctx, void *timeout_ctx);
void p2p_dbg(struct p2p_data *p2p, const char *fmt, ...)
PRINTF_FORMAT(2, 3);
void p2p_info(struct p2p_data *p2p, const char *fmt, ...)
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index ef01a66..558c6dd 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -174,7 +174,7 @@
u8 group_bssid[ETH_ALEN], *bssid;
int op_freq = 0;
u8 reg_class = 0, channel = 0;
- struct p2p_channels intersection, *channels = NULL;
+ struct p2p_channels all_channels, intersection, *channels = NULL;
int persistent;
os_memset(group_bssid, 0, sizeof(group_bssid));
@@ -226,7 +226,10 @@
persistent = 1;
}
- if (p2p_peer_channels_check(p2p, &p2p->cfg->channels, dev,
+ p2p_channels_union(&p2p->cfg->channels, &p2p->cfg->cli_channels,
+ &all_channels);
+
+ if (p2p_peer_channels_check(p2p, &all_channels, dev,
msg.channel_list, msg.channel_list_len) <
0) {
p2p_dbg(p2p, "No common channels found");
@@ -235,8 +238,9 @@
}
p2p_channels_dump(p2p, "own channels", &p2p->cfg->channels);
+ p2p_channels_dump(p2p, "own client channels", &all_channels);
p2p_channels_dump(p2p, "peer channels", &dev->channels);
- p2p_channels_intersect(&p2p->cfg->channels, &dev->channels,
+ p2p_channels_intersect(&all_channels, &dev->channels,
&intersection);
p2p_channels_dump(p2p, "intersection", &intersection);
@@ -248,6 +252,17 @@
msg.dev_password_id_present ? msg.dev_password_id : -1);
}
+ if (go) {
+ p2p_channels_intersect(&p2p->cfg->channels, &dev->channels,
+ &intersection);
+ p2p_channels_dump(p2p, "intersection(GO)", &intersection);
+ if (intersection.reg_classes == 0) {
+ p2p_dbg(p2p, "No common channels found (GO)");
+ status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
+ goto fail;
+ }
+ }
+
if (op_freq) {
p2p_dbg(p2p, "Invitation processing forced frequency %d MHz",
op_freq);
@@ -412,25 +427,68 @@
if (dev == NULL) {
p2p_dbg(p2p, "Ignore Invitation Response from unknown peer "
MACSTR, MAC2STR(sa));
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
return;
}
if (dev != p2p->invite_peer) {
p2p_dbg(p2p, "Ignore unexpected Invitation Response from peer "
MACSTR, MAC2STR(sa));
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
return;
}
- if (p2p_parse(data, len, &msg))
+ if (p2p_parse(data, len, &msg)) {
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
return;
+ }
if (!msg.status) {
p2p_dbg(p2p, "Mandatory Status attribute missing in Invitation Response from "
MACSTR, MAC2STR(sa));
p2p_parse_free(&msg);
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
return;
}
+ /*
+ * We should not really receive a replayed response twice since
+ * duplicate frames are supposed to be dropped. However, not all drivers
+ * do that for pre-association frames. We did not use to verify dialog
+ * token matches for invitation response frames, but that check can be
+ * safely used to drop a replayed response to the previous Invitation
+ * Request in case the suggested operating channel was changed. This
+ * allows a duplicated reject frame to be dropped with the assumption
+ * that the real response follows after it.
+ */
+ if (*msg.status == P2P_SC_FAIL_NO_COMMON_CHANNELS &&
+ p2p->retry_invite_req_sent &&
+ msg.dialog_token != dev->dialog_token) {
+ p2p_dbg(p2p, "Unexpected Dialog Token %u (expected %u)",
+ msg.dialog_token, dev->dialog_token);
+ p2p_parse_free(&msg);
+ return;
+ }
+
+ if (*msg.status == P2P_SC_FAIL_NO_COMMON_CHANNELS &&
+ p2p->retry_invite_req &&
+ p2p_channel_random_social(&p2p->cfg->channels, &p2p->op_reg_class,
+ &p2p->op_channel) == 0) {
+ p2p->retry_invite_req = 0;
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+ p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
+ p2p_set_state(p2p, P2P_INVITE);
+ p2p_dbg(p2p, "Resend Invitation Request setting op_class %u channel %u as operating channel",
+ p2p->op_reg_class, p2p->op_channel);
+ p2p->retry_invite_req_sent = 1;
+ p2p_invite_send(p2p, p2p->invite_peer, p2p->invite_go_dev_addr,
+ p2p->invite_dev_pw_id);
+ p2p_parse_free(&msg);
+ return;
+ }
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+ p2p->retry_invite_req = 0;
+
if (!msg.channel_list && *msg.status == P2P_SC_SUCCESS) {
p2p_dbg(p2p, "Mandatory Channel List attribute missing in Invitation Response from "
MACSTR, MAC2STR(sa));
@@ -592,6 +650,9 @@
dev_pw_id);
}
p2p->invite_dev_pw_id = dev_pw_id;
+ p2p->retry_invite_req = role == P2P_INVITE_ROLE_GO &&
+ persistent_group && !force_freq;
+ p2p->retry_invite_req_sent = 0;
dev = p2p_get_device(p2p, peer);
if (dev == NULL || (dev->listen_freq <= 0 && dev->oper_freq <= 0 &&
diff --git a/src/p2p/p2p_parse.c b/src/p2p/p2p_parse.c
index d6144a0..52ba19e 100644
--- a/src/p2p/p2p_parse.c
+++ b/src/p2p/p2p_parse.c
@@ -309,23 +309,27 @@
while (pos < end) {
u16 attr_len;
- if (pos + 2 >= end) {
+ u8 id;
+
+ if (end - pos < 3) {
wpa_printf(MSG_DEBUG, "P2P: Invalid P2P attribute");
return -1;
}
- attr_len = WPA_GET_LE16(pos + 1);
+ id = *pos++;
+ attr_len = WPA_GET_LE16(pos);
+ pos += 2;
wpa_printf(MSG_DEBUG, "P2P: Attribute %d length %u",
- pos[0], attr_len);
- if (pos + 3 + attr_len > end) {
+ id, attr_len);
+ if (attr_len > end - pos) {
wpa_printf(MSG_DEBUG, "P2P: Attribute underflow "
"(len=%u left=%d)",
- attr_len, (int) (end - pos - 3));
+ attr_len, (int) (end - pos));
wpa_hexdump(MSG_MSGDUMP, "P2P: Data", pos, end - pos);
return -1;
}
- if (p2p_parse_attribute(pos[0], pos + 3, attr_len, msg))
+ if (p2p_parse_attribute(id, pos, attr_len, msg))
return -1;
- pos += 3 + attr_len;
+ pos += attr_len;
}
return 0;
@@ -603,7 +607,7 @@
"dev=" MACSTR " iface=" MACSTR,
MAC2STR(cli->p2p_device_addr),
MAC2STR(cli->p2p_interface_addr));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -614,7 +618,7 @@
wps_dev_type_bin2str(cli->pri_dev_type,
devtype,
sizeof(devtype)));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -623,7 +627,7 @@
wps_dev_type_bin2str(
&cli->sec_dev_types[s * 8],
devtype, sizeof(devtype)));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -638,7 +642,7 @@
}
ret = os_snprintf(pos, end - pos, " dev_name='%s'\n", name);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -672,7 +676,7 @@
"p2p_dev_capab=0x%x\n"
"p2p_group_capab=0x%x\n",
msg.capability[0], msg.capability[1]);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -684,14 +688,14 @@
wps_dev_type_bin2str(msg.pri_dev_type,
devtype,
sizeof(devtype)));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
ret = os_snprintf(pos, end - pos, "p2p_device_name=%s\n",
msg.device_name);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -699,14 +703,14 @@
ret = os_snprintf(pos, end - pos, "p2p_device_addr=" MACSTR
"\n",
MAC2STR(msg.p2p_device_addr));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
ret = os_snprintf(pos, end - pos, "p2p_config_methods=0x%x\n",
msg.config_methods);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
diff --git a/src/p2p/p2p_sd.c b/src/p2p/p2p_sd.c
index 13119c2..1a2af04 100644
--- a/src/p2p/p2p_sd.c
+++ b/src/p2p/p2p_sd.c
@@ -75,16 +75,25 @@
return NULL;
/* query number that needs to be send to the device */
if (count == dev->sd_pending_bcast_queries - 1)
- return q;
+ goto found;
count++;
}
if (!q->for_all_peers &&
os_memcmp(q->peer, dev->info.p2p_device_addr, ETH_ALEN) ==
0)
- return q;
+ goto found;
}
return NULL;
+
+found:
+ if (dev->sd_reqs > 100) {
+ p2p_dbg(p2p, "Too many SD request attempts to " MACSTR
+ " - skip remaining queries",
+ MAC2STR(dev->info.p2p_device_addr));
+ return NULL;
+ }
+ return q;
}
@@ -287,6 +296,7 @@
if (req == NULL)
return -1;
+ dev->sd_reqs++;
p2p->sd_peer = dev;
p2p->sd_query = query;
p2p->pending_action_state = P2P_PENDING_SD;
diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c
index 23acce7..f32751d 100644
--- a/src/p2p/p2p_utils.c
+++ b/src/p2p/p2p_utils.c
@@ -9,6 +9,7 @@
#include "includes.h"
#include "common.h"
+#include "common/ieee802_11_common.h"
#include "p2p_i.h"
@@ -54,56 +55,7 @@
*/
int p2p_channel_to_freq(int op_class, int channel)
{
- /* Table E-4 in IEEE Std 802.11-2012 - Global operating classes */
- /* TODO: more operating classes */
- switch (op_class) {
- case 81:
- /* channels 1..13 */
- if (channel < 1 || channel > 13)
- return -1;
- return 2407 + 5 * channel;
- case 82:
- /* channel 14 */
- if (channel != 14)
- return -1;
- return 2414 + 5 * channel;
- case 83: /* channels 1..9; 40 MHz */
- case 84: /* channels 5..13; 40 MHz */
- if (channel < 1 || channel > 13)
- return -1;
- return 2407 + 5 * channel;
- case 115: /* channels 36,40,44,48; indoor only */
- case 118: /* channels 52,56,60,64; dfs */
- if (channel < 36 || channel > 64)
- return -1;
- return 5000 + 5 * channel;
- case 124: /* channels 149,153,157,161 */
- case 125: /* channels 149,153,157,161,165,169 */
- if (channel < 149 || channel > 161)
- return -1;
- return 5000 + 5 * channel;
- case 116: /* channels 36,44; 40 MHz; indoor only */
- case 117: /* channels 40,48; 40 MHz; indoor only */
- case 119: /* channels 52,60; 40 MHz; dfs */
- case 120: /* channels 56,64; 40 MHz; dfs */
- if (channel < 36 || channel > 64)
- return -1;
- return 5000 + 5 * channel;
- case 126: /* channels 149,157; 40 MHz */
- case 127: /* channels 153,161; 40 MHz */
- if (channel < 149 || channel > 161)
- return -1;
- return 5000 + 5 * channel;
- case 128: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
- if (channel < 36 || channel > 161)
- return -1;
- return 5000 + 5 * channel;
- case 180: /* 60 GHz band, channels 1..4 */
- if (channel < 1 || channel > 4)
- return -1;
- return 56160 + 2160 * channel;
- }
- return -1;
+ return ieee80211_chan_to_freq(NULL, op_class, channel);
}
@@ -241,20 +193,15 @@
/**
- * p2p_channels_union - Union of channel lists
- * @a: First set of channels
+ * p2p_channels_union_inplace - Inplace union of channel lists
+ * @res: Input data and place for returning union of the channel sets
* @b: Second set of channels
- * @res: Data structure for returning the union of channels
*/
-void p2p_channels_union(const struct p2p_channels *a,
- const struct p2p_channels *b,
- struct p2p_channels *res)
+void p2p_channels_union_inplace(struct p2p_channels *res,
+ const struct p2p_channels *b)
{
size_t i, j;
- if (a != res)
- os_memcpy(res, a, sizeof(*res));
-
for (i = 0; i < res->reg_classes; i++) {
struct p2p_reg_class *cl = &res->reg_class[i];
for (j = 0; j < b->reg_classes; j++) {
@@ -284,6 +231,21 @@
}
+/**
+ * p2p_channels_union - Union of channel lists
+ * @a: First set of channels
+ * @b: Second set of channels
+ * @res: Data structure for returning the union of channels
+ */
+void p2p_channels_union(const struct p2p_channels *a,
+ const struct p2p_channels *b,
+ struct p2p_channels *res)
+{
+ os_memcpy(res, a, sizeof(*res));
+ p2p_channels_union_inplace(res, b);
+}
+
+
void p2p_channels_remove_freqs(struct p2p_channels *chan,
const struct wpa_freq_range_list *list)
{
@@ -428,7 +390,7 @@
const struct p2p_reg_class *c;
c = &chan->reg_class[i];
ret = os_snprintf(pos, end - pos, " %u:", c->reg_class);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
break;
pos += ret;
@@ -436,7 +398,7 @@
ret = os_snprintf(pos, end - pos, "%s%u",
j == 0 ? "" : ",",
c->channel[j]);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
break;
pos += ret;
}
@@ -517,3 +479,35 @@
return 0;
}
+
+
+int p2p_channels_to_freqs(const struct p2p_channels *channels, int *freq_list,
+ unsigned int max_len)
+{
+ unsigned int i, idx;
+
+ if (!channels || max_len == 0)
+ return 0;
+
+ for (i = 0, idx = 0; i < channels->reg_classes; i++) {
+ const struct p2p_reg_class *c = &channels->reg_class[i];
+ unsigned int j;
+
+ if (idx + 1 == max_len)
+ break;
+ for (j = 0; j < c->channels; j++) {
+ int freq;
+ if (idx + 1 == max_len)
+ break;
+ freq = p2p_channel_to_freq(c->reg_class,
+ c->channel[j]);
+ if (freq < 0)
+ continue;
+ freq_list[idx++] = freq;
+ }
+ }
+
+ freq_list[idx] = 0;
+
+ return idx;
+}
diff --git a/src/pae/ieee802_1x_kay.c b/src/pae/ieee802_1x_kay.c
index b1cf32d..ef74430 100644
--- a/src/pae/ieee802_1x_kay.c
+++ b/src/pae/ieee802_1x_kay.c
@@ -729,7 +729,8 @@
/* If the peer's MI is my MI, I will choose new MI */
if (os_memcmp(body->actor_mi, participant->mi, MI_LEN) == 0) {
- os_get_random(participant->mi, sizeof(participant->mi));
+ if (os_get_random(participant->mi, sizeof(participant->mi)) < 0)
+ return NULL;
participant->mn = 0;
}
@@ -1003,8 +1004,10 @@
if (os_memcmp(peer_mi, participant->mi, MI_LEN) == 0) {
/* My message id is used by other participant */
if (peer_mn > participant->mn) {
- os_get_random(participant->mi,
- sizeof(participant->mi));
+ if (os_get_random(participant->mi,
+ sizeof(participant->mi)) < 0)
+ wpa_printf(MSG_DEBUG,
+ "KaY: Could not update mi");
participant->mn = 0;
}
continue;
@@ -1054,8 +1057,10 @@
if (os_memcmp(peer_mi, participant->mi, MI_LEN) == 0) {
/* My message id is used by other participant */
if (peer_mn > participant->mn) {
- os_get_random(participant->mi,
- sizeof(participant->mi));
+ if (os_get_random(participant->mi,
+ sizeof(participant->mi)) < 0)
+ wpa_printf(MSG_DEBUG,
+ "KaY: Could not update mi");
participant->mn = 0;
}
continue;
@@ -1998,7 +2003,12 @@
return -1;
}
ctx_offset = 0;
- os_get_random(context + ctx_offset, conf->key_len);
+ if (os_get_random(context + ctx_offset, conf->key_len) < 0) {
+ os_free(context);
+ os_free(conf->key);
+ os_free(conf);
+ return -1;
+ }
ctx_offset += conf->key_len;
dl_list_for_each(peer, &participant->live_peers,
struct ieee802_1x_kay_peer, list) {
@@ -3159,7 +3169,7 @@
kay->macsec_capable = MACSEC_CAP_NOT_IMPLEMENTED;
kay->macsec_desired = FALSE;
kay->macsec_protect = FALSE;
- kay->macsec_validate = FALSE;
+ kay->macsec_validate = Disabled;
kay->macsec_replay_protect = FALSE;
kay->macsec_replay_window = 0;
kay->macsec_confidentiality = CONFIDENTIALITY_NONE;
@@ -3167,7 +3177,7 @@
kay->macsec_capable = MACSEC_CAP_INTEG_AND_CONF_0_30_50;
kay->macsec_desired = TRUE;
kay->macsec_protect = TRUE;
- kay->macsec_validate = TRUE;
+ kay->macsec_validate = Strict;
kay->macsec_replay_protect = FALSE;
kay->macsec_replay_window = 0;
kay->macsec_confidentiality = CONFIDENTIALITY_OFFSET_0;
@@ -3325,7 +3335,8 @@
participant->retry_count = 0;
participant->kay = kay;
- os_get_random(participant->mi, sizeof(participant->mi));
+ if (os_get_random(participant->mi, sizeof(participant->mi)) < 0)
+ goto fail;
participant->mn = 0;
participant->lrx = FALSE;
@@ -3340,6 +3351,9 @@
dl_list_init(&participant->rxsc_list);
participant->txsc = ieee802_1x_kay_init_transmit_sc(&kay->actor_sci,
kay->sc_ch);
+ secy_cp_control_protect_frames(kay, kay->macsec_protect);
+ secy_cp_control_replay(kay, kay->macsec_replay_protect,
+ kay->macsec_replay_window);
secy_create_transmit_sc(kay, participant->txsc);
/* to derive KEK from CAK and CKN */
diff --git a/src/radius/radius.c b/src/radius/radius.c
index f3b645d..8d878a4 100644
--- a/src/radius/radius.c
+++ b/src/radius/radius.c
@@ -233,6 +233,17 @@
{ RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 },
{ RADIUS_ATTR_ERROR_CAUSE, "Error-Cause", RADIUS_ATTR_INT32 },
{ RADIUS_ATTR_EAP_KEY_NAME, "EAP-Key-Name", RADIUS_ATTR_HEXDUMP },
+ { RADIUS_ATTR_OPERATOR_NAME, "Operator-Name", RADIUS_ATTR_TEXT },
+ { RADIUS_ATTR_LOCATION_INFO, "Location-Information",
+ RADIUS_ATTR_HEXDUMP },
+ { RADIUS_ATTR_LOCATION_DATA, "Location-Data", RADIUS_ATTR_HEXDUMP },
+ { RADIUS_ATTR_BASIC_LOCATION_POLICY_RULES,
+ "Basic-Location-Policy-Rules", RADIUS_ATTR_HEXDUMP },
+ { RADIUS_ATTR_EXTENDED_LOCATION_POLICY_RULES,
+ "Extended-Location-Policy-Rules", RADIUS_ATTR_HEXDUMP },
+ { RADIUS_ATTR_LOCATION_CAPABLE, "Location-Capable", RADIUS_ATTR_INT32 },
+ { RADIUS_ATTR_REQUESTED_LOCATION_INFO, "Requested-Location-Info",
+ RADIUS_ATTR_INT32 },
{ RADIUS_ATTR_MOBILITY_DOMAIN_ID, "Mobility-Domain-Id",
RADIUS_ATTR_INT32 },
{ RADIUS_ATTR_WLAN_HESSID, "WLAN-HESSID", RADIUS_ATTR_TEXT },
@@ -945,7 +956,6 @@
vhdr = (struct radius_attr_vendor *) pos;
if (vhdr->vendor_length > left ||
vhdr->vendor_length < sizeof(*vhdr)) {
- left = 0;
break;
}
if (vhdr->vendor_type != subtype) {
@@ -983,13 +993,16 @@
/* key: 16-bit salt followed by encrypted key info */
- if (len < 2 + 16)
+ if (len < 2 + 16) {
+ wpa_printf(MSG_DEBUG, "RADIUS: %s: Len is too small: %d",
+ __func__, (int) len);
return NULL;
+ }
pos = key + 2;
left = len - 2;
if (left % 16) {
- wpa_printf(MSG_INFO, "Invalid ms key len %lu",
+ wpa_printf(MSG_INFO, "RADIUS: Invalid ms key len %lu",
(unsigned long) left);
return NULL;
}
@@ -1024,7 +1037,7 @@
}
if (plain[0] == 0 || plain[0] > plen - 1) {
- wpa_printf(MSG_INFO, "Failed to decrypt MPPE key");
+ wpa_printf(MSG_INFO, "RADIUS: Failed to decrypt MPPE key");
os_free(plain);
return NULL;
}
@@ -1113,6 +1126,10 @@
sent_msg->hdr->authenticator,
secret, secret_len,
&keys->send_len);
+ if (!keys->send) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS: Failed to decrypt send key");
+ }
os_free(key);
}
@@ -1124,6 +1141,10 @@
sent_msg->hdr->authenticator,
secret, secret_len,
&keys->recv_len);
+ if (!keys->recv) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS: Failed to decrypt recv key");
+ }
os_free(key);
}
diff --git a/src/radius/radius.h b/src/radius/radius.h
index 62faae1..5977339 100644
--- a/src/radius/radius.h
+++ b/src/radius/radius.h
@@ -92,6 +92,13 @@
RADIUS_ATTR_NAS_IPV6_ADDRESS = 95,
RADIUS_ATTR_ERROR_CAUSE = 101,
RADIUS_ATTR_EAP_KEY_NAME = 102,
+ RADIUS_ATTR_OPERATOR_NAME = 126,
+ RADIUS_ATTR_LOCATION_INFO = 127,
+ RADIUS_ATTR_LOCATION_DATA = 128,
+ RADIUS_ATTR_BASIC_LOCATION_POLICY_RULES = 129,
+ RADIUS_ATTR_EXTENDED_LOCATION_POLICY_RULES = 130,
+ RADIUS_ATTR_LOCATION_CAPABLE = 131,
+ RADIUS_ATTR_REQUESTED_LOCATION_INFO = 132,
RADIUS_ATTR_MOBILITY_DOMAIN_ID = 177,
RADIUS_ATTR_WLAN_HESSID = 181,
RADIUS_ATTR_WLAN_PAIRWISE_CIPHER = 186,
diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c
index e2766e2..34f5685 100644
--- a/src/radius/radius_client.c
+++ b/src/radius/radius_client.c
@@ -658,7 +658,8 @@
}
if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) {
- if (conf->acct_server == NULL || radius->acct_sock < 0) {
+ if (conf->acct_server == NULL || radius->acct_sock < 0 ||
+ conf->acct_server->shared_secret == NULL) {
hostapd_logger(radius->ctx, NULL,
HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
@@ -672,7 +673,8 @@
s = radius->acct_sock;
conf->acct_server->requests++;
} else {
- if (conf->auth_server == NULL || radius->auth_sock < 0) {
+ if (conf->auth_server == NULL || radius->auth_sock < 0 ||
+ conf->auth_server->shared_secret == NULL) {
hostapd_logger(radius->ctx, NULL,
HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
@@ -1039,6 +1041,13 @@
return -1;
}
+ if (sel_sock < 0) {
+ wpa_printf(MSG_INFO,
+ "RADIUS: No server socket available (af=%d sock=%d sock6=%d auth=%d",
+ nserv->addr.af, sock, sock6, auth);
+ return -1;
+ }
+
if (conf->force_client_addr) {
switch (conf->client_addr.af) {
case AF_INET:
diff --git a/src/radius/radius_das.c b/src/radius/radius_das.c
index 9655f4c..39ceea8 100644
--- a/src/radius/radius_das.c
+++ b/src/radius/radius_das.c
@@ -42,6 +42,7 @@
RADIUS_ATTR_CALLING_STATION_ID,
RADIUS_ATTR_NAS_IDENTIFIER,
RADIUS_ATTR_ACCT_SESSION_ID,
+ RADIUS_ATTR_ACCT_MULTI_SESSION_ID,
RADIUS_ATTR_EVENT_TIMESTAMP,
RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
@@ -129,6 +130,12 @@
attrs.acct_session_id_len = len;
}
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_ACCT_MULTI_SESSION_ID,
+ &buf, &len, NULL) == 0) {
+ attrs.acct_multi_session_id = buf;
+ attrs.acct_multi_session_id_len = len;
+ }
+
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
&buf, &len, NULL) == 0) {
attrs.cui = buf;
@@ -147,6 +154,12 @@
"%s:%d", abuf, from_port);
error = 503;
break;
+ case RADIUS_DAS_MULTI_SESSION_MATCH:
+ wpa_printf(MSG_INFO,
+ "DAS: Multiple sessions match for request from %s:%d",
+ abuf, from_port);
+ error = 508;
+ break;
case RADIUS_DAS_SUCCESS:
error = 0;
break;
diff --git a/src/radius/radius_das.h b/src/radius/radius_das.h
index e3ed540..ce731d4 100644
--- a/src/radius/radius_das.h
+++ b/src/radius/radius_das.h
@@ -14,7 +14,8 @@
enum radius_das_res {
RADIUS_DAS_SUCCESS,
RADIUS_DAS_NAS_MISMATCH,
- RADIUS_DAS_SESSION_NOT_FOUND
+ RADIUS_DAS_SESSION_NOT_FOUND,
+ RADIUS_DAS_MULTI_SESSION_MATCH,
};
struct radius_das_attrs {
@@ -30,6 +31,8 @@
size_t user_name_len;
const u8 *acct_session_id;
size_t acct_session_id_len;
+ const u8 *acct_multi_session_id;
+ size_t acct_multi_session_id_len;
const u8 *cui;
size_t cui_len;
};
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index 00394b4..85a485e 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -252,6 +252,20 @@
const char *server_id;
/**
+ * erp - Whether EAP Re-authentication Protocol (ERP) is enabled
+ *
+ * This controls whether the authentication server derives ERP key
+ * hierarchy (rRK and rIK) from full EAP authentication and allows
+ * these keys to be used to perform ERP to derive rMSK instead of full
+ * EAP authentication to derive MSK.
+ */
+ int erp;
+
+ const char *erp_domain;
+
+ struct dl_list erp_keys; /* struct eap_server_erp_key */
+
+ /**
* wps - Wi-Fi Protected Setup context
*
* If WPS is used with an external RADIUS server (which is quite
@@ -673,6 +687,7 @@
eap_conf.pwd_group = data->pwd_group;
eap_conf.server_id = (const u8 *) data->server_id;
eap_conf.server_id_len = os_strlen(data->server_id);
+ eap_conf.erp = data->erp;
radius_server_testing_options(sess, &eap_conf);
sess->eap = eap_server_sm_init(sess, &radius_server_eapol_cb,
&eap_conf);
@@ -1687,6 +1702,7 @@
if (data == NULL)
return NULL;
+ dl_list_init(&data->erp_keys);
os_get_reltime(&data->start_time);
data->conf_ctx = conf->conf_ctx;
data->eap_sim_db_priv = conf->eap_sim_db_priv;
@@ -1725,6 +1741,8 @@
data->eap_req_id_text_len = conf->eap_req_id_text_len;
}
}
+ data->erp = conf->erp;
+ data->erp_domain = conf->erp_domain;
if (conf->subscr_remediation_url) {
data->subscr_remediation_url =
@@ -1802,6 +1820,24 @@
/**
+ * radius_server_erp_flush - Flush all ERP keys
+ * @data: RADIUS server context from radius_server_init()
+ */
+void radius_server_erp_flush(struct radius_server_data *data)
+{
+ struct eap_server_erp_key *erp;
+
+ if (data == NULL)
+ return;
+ while ((erp = dl_list_first(&data->erp_keys, struct eap_server_erp_key,
+ list)) != NULL) {
+ dl_list_del(&erp->list);
+ bin_clear_free(erp, sizeof(*erp));
+ }
+}
+
+
+/**
* radius_server_deinit - Deinitialize RADIUS server
* @data: RADIUS server context from radius_server_init()
*/
@@ -1836,6 +1872,8 @@
sqlite3_close(data->db);
#endif /* CONFIG_SQLITE */
+ radius_server_erp_flush(data);
+
os_free(data);
}
@@ -1874,7 +1912,7 @@
"radiusAuthServResetTime=0\n"
"radiusAuthServConfigReset=4\n",
uptime);
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
*pos = '\0';
return pos - buf;
}
@@ -1913,7 +1951,7 @@
data->counters.malformed_acct_requests,
data->counters.acct_bad_authenticators,
data->counters.unknown_acct_types);
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
*pos = '\0';
return pos - buf;
}
@@ -1971,7 +2009,7 @@
cli->counters.malformed_acct_requests,
cli->counters.acct_bad_authenticators,
cli->counters.unknown_acct_types);
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
*pos = '\0';
return pos - buf;
}
@@ -2017,11 +2055,57 @@
}
+#ifdef CONFIG_ERP
+
+static const char * radius_server_get_erp_domain(void *ctx)
+{
+ struct radius_session *sess = ctx;
+ struct radius_server_data *data = sess->server;
+
+ return data->erp_domain;
+}
+
+
+static struct eap_server_erp_key *
+radius_server_erp_get_key(void *ctx, const char *keyname)
+{
+ struct radius_session *sess = ctx;
+ struct radius_server_data *data = sess->server;
+ struct eap_server_erp_key *erp;
+
+ dl_list_for_each(erp, &data->erp_keys, struct eap_server_erp_key,
+ list) {
+ if (os_strcmp(erp->keyname_nai, keyname) == 0)
+ return erp;
+ }
+
+ return NULL;
+}
+
+
+static int radius_server_erp_add_key(void *ctx, struct eap_server_erp_key *erp)
+{
+ struct radius_session *sess = ctx;
+ struct radius_server_data *data = sess->server;
+
+ dl_list_add(&data->erp_keys, &erp->list);
+ return 0;
+}
+
+#endif /* CONFIG_ERP */
+
+
static struct eapol_callbacks radius_server_eapol_cb =
{
.get_eap_user = radius_server_get_eap_user,
.get_eap_req_id_text = radius_server_get_eap_req_id_text,
.log_msg = radius_server_log_msg,
+#ifdef CONFIG_ERP
+ .get_erp_send_reauth_start = NULL,
+ .get_erp_domain = radius_server_get_erp_domain,
+ .erp_get_key = radius_server_erp_get_key,
+ .erp_add_key = radius_server_erp_add_key,
+#endif /* CONFIG_ERP */
};
diff --git a/src/radius/radius_server.h b/src/radius/radius_server.h
index 46ac312..ca4e38c 100644
--- a/src/radius/radius_server.h
+++ b/src/radius/radius_server.h
@@ -159,6 +159,18 @@
const char *server_id;
/**
+ * erp - Whether EAP Re-authentication Protocol (ERP) is enabled
+ *
+ * This controls whether the authentication server derives ERP key
+ * hierarchy (rRK and rIK) from full EAP authentication and allows
+ * these keys to be used to perform ERP to derive rMSK instead of full
+ * EAP authentication to derive MSK.
+ */
+ int erp;
+
+ const char *erp_domain;
+
+ /**
* wps - Wi-Fi Protected Setup context
*
* If WPS is used with an external RADIUS server (which is quite
@@ -223,6 +235,7 @@
struct radius_server_data *
radius_server_init(struct radius_server_conf *conf);
+void radius_server_erp_flush(struct radius_server_data *data);
void radius_server_deinit(struct radius_server_data *data);
int radius_server_get_mib(struct radius_server_data *data, char *buf,
diff --git a/src/rsn_supp/peerkey.c b/src/rsn_supp/peerkey.c
index aab8b7e..79764d9 100644
--- a/src/rsn_supp/peerkey.c
+++ b/src/rsn_supp/peerkey.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - PeerKey for Direct Link Setup (DLS)
- * Copyright (c) 2006-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -65,6 +65,7 @@
{
size_t rlen;
struct wpa_eapol_key *err;
+ struct wpa_eapol_key_192 *err192;
struct rsn_error_kde error;
u8 *rbuf, *pos;
size_t kde_len;
@@ -79,6 +80,7 @@
(void *) &err);
if (rbuf == NULL)
return -1;
+ err192 = (struct wpa_eapol_key_192 *) err;
err->type = EAPOL_KEY_TYPE_RSN;
key_info = ver | WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC |
@@ -112,8 +114,8 @@
"(mui %d error_type %d)", mui, error_type);
}
- wpa_eapol_key_send(sm, sm->ptk.kck, ver, dst, ETH_P_EAPOL,
- rbuf, rlen, err->key_mic);
+ wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, dst,
+ ETH_P_EAPOL, rbuf, rlen, err192->key_mic);
return 0;
}
@@ -126,6 +128,7 @@
{
size_t rlen;
struct wpa_eapol_key *reply;
+ struct wpa_eapol_key_192 *reply192;
u8 *rbuf, *pos;
size_t kde_len;
u16 key_info;
@@ -140,6 +143,7 @@
(void *) &reply);
if (rbuf == NULL)
return -1;
+ reply192 = (struct wpa_eapol_key_192 *) reply;
reply->type = EAPOL_KEY_TYPE_RSN;
key_info = ver | WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC |
@@ -164,8 +168,8 @@
wpa_add_kde(pos, RSN_KEY_DATA_NONCE, peerkey->inonce, WPA_NONCE_LEN);
wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK M3");
- wpa_eapol_key_send(sm, sm->ptk.kck, ver, src_addr, ETH_P_EAPOL,
- rbuf, rlen, reply->key_mic);
+ wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, src_addr,
+ ETH_P_EAPOL, rbuf, rlen, reply192->key_mic);
return 0;
}
@@ -240,11 +244,7 @@
os_memcpy(peerkey->rsnie_i, kde.rsn_ie, kde.rsn_ie_len);
peerkey->rsnie_i_len = kde.rsn_ie_len;
peerkey->cipher = cipher;
-#ifdef CONFIG_IEEE80211W
- if (ie.key_mgmt & (WPA_KEY_MGMT_IEEE8021X_SHA256 |
- WPA_KEY_MGMT_PSK_SHA256))
- peerkey->use_sha256 = 1;
-#endif /* CONFIG_IEEE80211W */
+ peerkey->akmp = ie.key_mgmt;
if (random_get_bytes(peerkey->pnonce, WPA_NONCE_LEN)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
@@ -288,14 +288,14 @@
* @mac_p: Peer MAC address
* @inonce: Initiator Nonce
* @mac_i: Initiator MAC address
- * @use_sha256: Whether to use SHA256-based KDF
+ * @akmp: Negotiated AKM
*
* 8.5.1.4 Station to station (STK) key hierarchy
* SMKID = HMAC-SHA1-128(SMK, "SMK Name" || PNonce || MAC_P || INonce || MAC_I)
*/
static void rsn_smkid(const u8 *smk, const u8 *pnonce, const u8 *mac_p,
const u8 *inonce, const u8 *mac_i, u8 *smkid,
- int use_sha256)
+ int akmp)
{
char *title = "SMK Name";
const u8 *addr[5];
@@ -310,7 +310,7 @@
addr[4] = mac_i;
#ifdef CONFIG_IEEE80211W
- if (use_sha256)
+ if (wpa_key_mgmt_sha256(akmp))
hmac_sha256_vector(smk, PMK_LEN, 5, addr, len, hash);
else
#endif /* CONFIG_IEEE80211W */
@@ -371,7 +371,7 @@
wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key STK 1/4 to " MACSTR,
MAC2STR(peerkey->addr));
- wpa_eapol_key_send(sm, NULL, ver, peerkey->addr, ETH_P_EAPOL,
+ wpa_eapol_key_send(sm, NULL, 0, ver, peerkey->addr, ETH_P_EAPOL,
mbuf, mlen, NULL);
}
@@ -426,8 +426,9 @@
wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key STK 3/4 to " MACSTR,
MAC2STR(peerkey->addr));
- wpa_eapol_key_send(sm, peerkey->stk.kck, ver, peerkey->addr,
- ETH_P_EAPOL, mbuf, mlen, msg->key_mic);
+ wpa_eapol_key_send(sm, peerkey->stk.kck, peerkey->stk.kck_len, ver,
+ peerkey->addr, ETH_P_EAPOL, mbuf, mlen,
+ msg->key_mic);
}
@@ -575,12 +576,12 @@
if (peerkey->initiator) {
rsn_smkid(peerkey->smk, peerkey->pnonce, peerkey->addr,
peerkey->inonce, sm->own_addr, peerkey->smkid,
- peerkey->use_sha256);
+ peerkey->akmp);
wpa_supplicant_send_stk_1_of_4(sm, peerkey);
} else {
rsn_smkid(peerkey->smk, peerkey->pnonce, sm->own_addr,
peerkey->inonce, peerkey->addr, peerkey->smkid,
- peerkey->use_sha256);
+ peerkey->akmp);
}
wpa_hexdump(MSG_DEBUG, "RSN: SMKID", peerkey->smkid, PMKID_LEN);
@@ -694,12 +695,11 @@
wpa_pmk_to_ptk(peerkey->smk, PMK_LEN, "Peer key expansion",
sm->own_addr, peerkey->addr,
peerkey->pnonce, key->key_nonce,
- (u8 *) stk, sizeof(*stk),
- peerkey->use_sha256);
+ stk, peerkey->akmp, peerkey->cipher);
/* Supplicant: swap tx/rx Mic keys */
- os_memcpy(buf, stk->u.auth.tx_mic_key, 8);
- os_memcpy(stk->u.auth.tx_mic_key, stk->u.auth.rx_mic_key, 8);
- os_memcpy(stk->u.auth.rx_mic_key, buf, 8);
+ os_memcpy(buf, &stk->tk[16], 8);
+ os_memcpy(&stk->tk[16], &stk->tk[24], 8);
+ os_memcpy(&stk->tk[24], buf, 8);
peerkey->tstk_set = 1;
kde_buf_len = peerkey->rsnie_p_len +
@@ -855,12 +855,12 @@
&peerkey->stk))
return;
- _key = (u8 *) peerkey->stk.tk1;
+ _key = peerkey->stk.tk;
if (peerkey->cipher == WPA_CIPHER_TKIP) {
/* Swap Tx/Rx keys for Michael MIC */
os_memcpy(key_buf, _key, 16);
- os_memcpy(key_buf + 16, peerkey->stk.u.auth.rx_mic_key, 8);
- os_memcpy(key_buf + 24, peerkey->stk.u.auth.tx_mic_key, 8);
+ os_memcpy(key_buf + 16, _key + 24, 8);
+ os_memcpy(key_buf + 24, _key + 16, 8);
_key = key_buf;
key_len = 32;
} else
@@ -869,10 +869,12 @@
os_memset(rsc, 0, 6);
if (wpa_sm_set_key(sm, peerkey->cipher, peerkey->addr, 0, 1,
rsc, sizeof(rsc), _key, key_len) < 0) {
+ os_memset(key_buf, 0, sizeof(key_buf));
wpa_printf(MSG_WARNING, "RSN: Failed to set STK to the "
"driver.");
return;
}
+ os_memset(key_buf, 0, sizeof(key_buf));
}
@@ -888,7 +890,7 @@
os_memset(rsc, 0, 6);
if (wpa_sm_set_key(sm, peerkey->cipher, peerkey->addr, 0, 1,
- rsc, sizeof(rsc), (u8 *) peerkey->stk.tk1,
+ rsc, sizeof(rsc), peerkey->stk.tk,
peerkey->cipher == WPA_CIPHER_TKIP ? 32 : 16) < 0) {
wpa_printf(MSG_WARNING, "RSN: Failed to set STK to the "
"driver.");
@@ -909,27 +911,27 @@
*/
int peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
struct wpa_peerkey *peerkey,
- struct wpa_eapol_key *key, u16 ver,
+ struct wpa_eapol_key_192 *key, u16 ver,
const u8 *buf, size_t len)
{
- u8 mic[16];
+ u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
+ size_t mic_len = 16;
int ok = 0;
if (peerkey->initiator && !peerkey->stk_set) {
wpa_pmk_to_ptk(peerkey->smk, PMK_LEN, "Peer key expansion",
sm->own_addr, peerkey->addr,
peerkey->inonce, key->key_nonce,
- (u8 *) &peerkey->stk, sizeof(peerkey->stk),
- peerkey->use_sha256);
+ &peerkey->stk, peerkey->akmp, peerkey->cipher);
peerkey->stk_set = 1;
}
- os_memcpy(mic, key->key_mic, 16);
+ os_memcpy(mic, key->key_mic, mic_len);
if (peerkey->tstk_set) {
- os_memset(key->key_mic, 0, 16);
- wpa_eapol_key_mic(peerkey->tstk.kck, ver, buf, len,
- key->key_mic);
- if (os_memcmp_const(mic, key->key_mic, 16) != 0) {
+ os_memset(key->key_mic, 0, mic_len);
+ wpa_eapol_key_mic(peerkey->tstk.kck, peerkey->tstk.kck_len,
+ sm->key_mgmt, ver, buf, len, key->key_mic);
+ if (os_memcmp_const(mic, key->key_mic, mic_len) != 0) {
wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC "
"when using TSTK - ignoring TSTK");
} else {
@@ -938,14 +940,15 @@
peerkey->stk_set = 1;
os_memcpy(&peerkey->stk, &peerkey->tstk,
sizeof(peerkey->stk));
+ os_memset(&peerkey->tstk, 0, sizeof(peerkey->tstk));
}
}
if (!ok && peerkey->stk_set) {
- os_memset(key->key_mic, 0, 16);
- wpa_eapol_key_mic(peerkey->stk.kck, ver, buf, len,
- key->key_mic);
- if (os_memcmp_const(mic, key->key_mic, 16) != 0) {
+ os_memset(key->key_mic, 0, mic_len);
+ wpa_eapol_key_mic(peerkey->stk.kck, peerkey->stk.kck_len,
+ sm->key_mgmt, ver, buf, len, key->key_mic);
+ if (os_memcmp_const(mic, key->key_mic, mic_len) != 0) {
wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC "
"- dropping packet");
return -1;
@@ -1014,10 +1017,7 @@
return -1;
peerkey->initiator = 1;
os_memcpy(peerkey->addr, peer, ETH_ALEN);
-#ifdef CONFIG_IEEE80211W
- if (wpa_key_mgmt_sha256(sm->key_mgmt))
- peerkey->use_sha256 = 1;
-#endif /* CONFIG_IEEE80211W */
+ peerkey->akmp = sm->key_mgmt;
/* SMK M1:
* EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
@@ -1084,8 +1084,8 @@
wpa_printf(MSG_INFO, "RSN: Sending EAPOL-Key SMK M1 Request (peer "
MACSTR ")", MAC2STR(peer));
- wpa_eapol_key_send(sm, sm->ptk.kck, ver, bssid, ETH_P_EAPOL,
- rbuf, rlen, req->key_mic);
+ wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, bssid,
+ ETH_P_EAPOL, rbuf, rlen, req->key_mic);
peerkey->next = sm->peerkey;
sm->peerkey = peerkey;
diff --git a/src/rsn_supp/peerkey.h b/src/rsn_supp/peerkey.h
index 4c17eae..6ccd948 100644
--- a/src/rsn_supp/peerkey.h
+++ b/src/rsn_supp/peerkey.h
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - PeerKey for Direct Link Setup (DLS)
- * Copyright (c) 2006-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -27,7 +27,7 @@
int cipher; /* Selected cipher (WPA_CIPHER_*) */
u8 replay_counter[WPA_REPLAY_COUNTER_LEN];
int replay_counter_set;
- int use_sha256; /* whether AKMP indicate SHA256-based derivations */
+ int akmp;
struct wpa_ptk stk, tstk;
int stk_set, tstk_set;
@@ -38,7 +38,7 @@
int peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
struct wpa_peerkey *peerkey,
- struct wpa_eapol_key *key, u16 ver,
+ struct wpa_eapol_key_192 *key, u16 ver,
const u8 *buf, size_t len);
void peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey,
struct wpa_eapol_key *key, u16 key_info, u16 ver,
diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c
index 885291a..ef7b683 100644
--- a/src/rsn_supp/pmksa_cache.c
+++ b/src/rsn_supp/pmksa_cache.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - RSN PMKSA cache
- * Copyright (c) 2004-2009, 2011-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2009, 2011-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -109,6 +109,8 @@
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
* @pmk: The new pairwise master key
* @pmk_len: PMK length in bytes, usually PMK_LEN (32)
+ * @kck: Key confirmation key or %NULL if not yet derived
+ * @kck_len: KCK length in bytes
* @aa: Authenticator address
* @spa: Supplicant address
* @network_ctx: Network configuration context for this PMK
@@ -122,6 +124,7 @@
*/
struct rsn_pmksa_cache_entry *
pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
+ const u8 *kck, size_t kck_len,
const u8 *aa, const u8 *spa, void *network_ctx, int akmp)
{
struct rsn_pmksa_cache_entry *entry, *pos, *prev;
@@ -130,13 +133,21 @@
if (pmk_len > PMK_LEN)
return NULL;
+ if (wpa_key_mgmt_suite_b(akmp) && !kck)
+ return NULL;
+
entry = os_zalloc(sizeof(*entry));
if (entry == NULL)
return NULL;
os_memcpy(entry->pmk, pmk, pmk_len);
entry->pmk_len = pmk_len;
- rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
- wpa_key_mgmt_sha256(akmp));
+ 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);
+ else
+ rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
+ wpa_key_mgmt_sha256(akmp));
os_get_reltime(&now);
entry->expiration = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime;
entry->reauth_time = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime *
@@ -333,6 +344,7 @@
struct rsn_pmksa_cache_entry *new_entry;
new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len,
+ NULL, 0,
aa, pmksa->sm->own_addr,
old_entry->network_ctx, old_entry->akmp);
if (new_entry == NULL)
@@ -472,7 +484,7 @@
ret = os_snprintf(pos, buf + len - pos,
"Index / AA / PMKID / expiration (in seconds) / "
"opportunistic\n");
- if (ret < 0 || ret >= buf + len - pos)
+ if (os_snprintf_error(buf + len - pos, ret))
return pos - buf;
pos += ret;
i = 0;
@@ -481,7 +493,7 @@
i++;
ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ",
i, MAC2STR(entry->aa));
- if (ret < 0 || ret >= buf + len - pos)
+ if (os_snprintf_error(buf + len - pos, ret))
return pos - buf;
pos += ret;
pos += wpa_snprintf_hex(pos, buf + len - pos, entry->pmkid,
@@ -489,7 +501,7 @@
ret = os_snprintf(pos, buf + len - pos, " %d %d\n",
(int) (entry->expiration - now.sec),
entry->opportunistic);
- if (ret < 0 || ret >= buf + len - pos)
+ if (os_snprintf_error(buf + len - pos, ret))
return pos - buf;
pos += ret;
entry = entry->next;
diff --git a/src/rsn_supp/pmksa_cache.h b/src/rsn_supp/pmksa_cache.h
index 6cbf89a..f8e040e 100644
--- a/src/rsn_supp/pmksa_cache.h
+++ b/src/rsn_supp/pmksa_cache.h
@@ -57,6 +57,7 @@
int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len);
struct rsn_pmksa_cache_entry *
pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
+ const u8 *kck, size_t kck_len,
const u8 *aa, const u8 *spa, void *network_ctx, int akmp);
struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm);
void pmksa_cache_clear_current(struct wpa_sm *sm);
@@ -104,6 +105,7 @@
static inline struct rsn_pmksa_cache_entry *
pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
+ const u8 *kck, size_t kck_len,
const u8 *aa, const u8 *spa, void *network_ctx, int akmp)
{
return NULL;
diff --git a/src/rsn_supp/preauth.c b/src/rsn_supp/preauth.c
index 915f85e..6356912 100644
--- a/src/rsn_supp/preauth.c
+++ b/src/rsn_supp/preauth.c
@@ -1,6 +1,6 @@
/*
* RSN pre-authentication (supplicant)
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -94,6 +94,7 @@
pmk, pmk_len);
sm->pmk_len = pmk_len;
pmksa_cache_add(sm->pmksa, pmk, pmk_len,
+ NULL, 0,
sm->preauth_bssid, sm->own_addr,
sm->network_ctx,
WPA_KEY_MGMT_IEEE8021X);
@@ -298,7 +299,9 @@
sm->proto != WPA_PROTO_RSN ||
wpa_sm_get_state(sm) != WPA_COMPLETED ||
(sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X &&
- sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SHA256)) {
+ sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SHA256 &&
+ sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SUITE_B &&
+ sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)) {
wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: not in suitable "
"state for new pre-authentication");
return; /* invalid state for new pre-auth */
@@ -391,6 +394,18 @@
dl_list_for_each(pos, &sm->pmksa_candidates,
struct rsn_pmksa_candidate, list) {
if (cand->priority <= pos->priority) {
+ if (!pos->list.prev) {
+ /*
+ * This cannot really happen in pracrice since
+ * pos was fetched from the list and the prev
+ * pointer must be set. It looks like clang
+ * static analyzer gets confused with the
+ * dl_list_del(&cand->list) call above and ends
+ * up assuming pos->list.prev could be NULL.
+ */
+ os_free(cand);
+ return;
+ }
dl_list_add(pos->list.prev, &cand->list);
cand = NULL;
break;
@@ -487,7 +502,7 @@
if (sm->preauth_eapol) {
ret = os_snprintf(pos, end - pos, "Pre-authentication "
"EAPOL state machines:\n");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
res = eapol_sm_get_status(sm->preauth_eapol,
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index 8cb19a2..10413ed 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -148,6 +148,9 @@
size_t supp_oper_classes_len;
u8 wmm_capable;
+
+ /* channel switch currently enabled */
+ int chan_switch_enabled;
};
@@ -687,6 +690,7 @@
peer->qos_info = 0;
peer->wmm_capable = 0;
peer->tpk_set = peer->tpk_success = 0;
+ peer->chan_switch_enabled = 0;
os_memset(&peer->tpk, 0, sizeof(peer->tpk));
os_memset(peer->inonce, 0, WPA_NONCE_LEN);
os_memset(peer->rnonce, 0, WPA_NONCE_LEN);
@@ -742,6 +746,13 @@
return 0;
}
+ /* Cancel active channel switch before teardown */
+ if (peer->chan_switch_enabled) {
+ wpa_printf(MSG_DEBUG, "TDLS: First returning link with " MACSTR
+ " to base channel", MAC2STR(addr));
+ wpa_sm_tdls_disable_channel_switch(sm, peer->addr);
+ }
+
dialog_token = peer->dtoken;
wpa_printf(MSG_DEBUG, "TDLS: TDLS Teardown for " MACSTR,
@@ -858,9 +869,11 @@
if (wpa_tdls_is_external_setup(sm)) {
/*
- * Disable the link, send a teardown packet through the
- * AP, and then reset link data.
+ * Get us on the base channel, disable the link, send a
+ * teardown packet through the AP, and then reset link data.
*/
+ if (peer->chan_switch_enabled)
+ wpa_sm_tdls_disable_channel_switch(sm, peer->addr);
wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, addr);
wpa_tdls_send_teardown(sm, addr,
WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE);
@@ -2742,7 +2755,8 @@
* are assumed to perform everything internally
*/
if (wpa_sm_tdls_get_capa(sm, &sm->tdls_supported,
- &sm->tdls_external_setup) < 0) {
+ &sm->tdls_external_setup,
+ &sm->tdls_chan_switch) < 0) {
sm->tdls_supported = 1;
sm->tdls_external_setup = 0;
}
@@ -2751,6 +2765,8 @@
"driver", sm->tdls_supported ? "" : " not");
wpa_printf(MSG_DEBUG, "TDLS: Driver uses %s link setup",
sm->tdls_external_setup ? "external" : "internal");
+ wpa_printf(MSG_DEBUG, "TDLS: Driver %s TDLS channel switching",
+ sm->tdls_chan_switch ? "supports" : "does not support");
return 0;
}
@@ -2760,6 +2776,8 @@
{
struct wpa_tdls_peer *peer, *tmp;
+ if (!sm)
+ return;
peer = sm->tdls;
wpa_printf(MSG_DEBUG, "TDLS: Tear down peers");
@@ -2830,39 +2848,61 @@
}
-static int wpa_tdls_prohibited(const u8 *ies, size_t len)
+static int wpa_tdls_prohibited(struct wpa_eapol_ie_parse *elems)
{
- struct wpa_eapol_ie_parse elems;
+ /* bit 38 - TDLS Prohibited */
+ return !!(elems->ext_capab[2 + 4] & 0x40);
+}
- if (ies == NULL)
- return 0;
- if (wpa_supplicant_parse_ies(ies, len, &elems) < 0)
- return 0;
-
- if (elems.ext_capab == NULL || elems.ext_capab_len < 2 + 5)
- return 0;
-
- /* bit 38 - TDLS Prohibited */
- return !!(elems.ext_capab[2 + 4] & 0x40);
+static int wpa_tdls_chan_switch_prohibited(struct wpa_eapol_ie_parse *elems)
+{
+ /* bit 39 - TDLS Channel Switch Prohibited */
+ return !!(elems->ext_capab[2 + 4] & 0x80);
}
void wpa_tdls_ap_ies(struct wpa_sm *sm, const u8 *ies, size_t len)
{
- sm->tdls_prohibited = wpa_tdls_prohibited(ies, len);
+ struct wpa_eapol_ie_parse elems;
+
+ sm->tdls_prohibited = 0;
+ sm->tdls_chan_switch_prohibited = 0;
+
+ if (ies == NULL || wpa_supplicant_parse_ies(ies, len, &elems) < 0 ||
+ elems.ext_capab == NULL || elems.ext_capab_len < 2 + 5)
+ return;
+
+ sm->tdls_prohibited = wpa_tdls_prohibited(&elems);
wpa_printf(MSG_DEBUG, "TDLS: TDLS is %s in the target BSS",
sm->tdls_prohibited ? "prohibited" : "allowed");
+ sm->tdls_chan_switch_prohibited =
+ wpa_tdls_chan_switch_prohibited(&elems);
+ wpa_printf(MSG_DEBUG, "TDLS: TDLS channel switch %s in the target BSS",
+ sm->tdls_chan_switch_prohibited ? "prohibited" : "allowed");
}
void wpa_tdls_assoc_resp_ies(struct wpa_sm *sm, const u8 *ies, size_t len)
{
- if (!sm->tdls_prohibited && wpa_tdls_prohibited(ies, len)) {
+ struct wpa_eapol_ie_parse elems;
+
+ if (ies == NULL || wpa_supplicant_parse_ies(ies, len, &elems) < 0 ||
+ elems.ext_capab == NULL || elems.ext_capab_len < 2 + 5)
+ return;
+
+ if (!sm->tdls_prohibited && wpa_tdls_prohibited(&elems)) {
wpa_printf(MSG_DEBUG, "TDLS: TDLS prohibited based on "
"(Re)Association Response IEs");
sm->tdls_prohibited = 1;
}
+
+ if (!sm->tdls_chan_switch_prohibited &&
+ wpa_tdls_chan_switch_prohibited(&elems)) {
+ wpa_printf(MSG_DEBUG,
+ "TDLS: TDLS channel switch prohibited based on (Re)Association Response IEs");
+ sm->tdls_chan_switch_prohibited = 1;
+ }
}
@@ -2877,3 +2917,78 @@
{
return sm->tdls_external_setup;
}
+
+
+int wpa_tdls_enable_chan_switch(struct wpa_sm *sm, const u8 *addr,
+ u8 oper_class,
+ struct hostapd_freq_params *freq_params)
+{
+ struct wpa_tdls_peer *peer;
+ int ret;
+
+ if (sm->tdls_disabled || !sm->tdls_supported)
+ return -1;
+
+ if (!sm->tdls_chan_switch) {
+ wpa_printf(MSG_DEBUG,
+ "TDLS: Channel switching not supported by the driver");
+ return -1;
+ }
+
+ if (sm->tdls_chan_switch_prohibited) {
+ wpa_printf(MSG_DEBUG,
+ "TDLS: Channel switching is prohibited in this BSS - reject request to switch channel");
+ return -1;
+ }
+
+ for (peer = sm->tdls; peer; peer = peer->next) {
+ if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
+ break;
+ }
+
+ if (peer == NULL || !peer->tpk_success) {
+ wpa_printf(MSG_ERROR, "TDLS: Peer " MACSTR
+ " not found for channel switching", MAC2STR(addr));
+ return -1;
+ }
+
+ if (peer->chan_switch_enabled) {
+ wpa_printf(MSG_DEBUG, "TDLS: Peer " MACSTR
+ " already has channel switching enabled",
+ MAC2STR(addr));
+ return 0;
+ }
+
+ ret = wpa_sm_tdls_enable_channel_switch(sm, peer->addr,
+ oper_class, freq_params);
+ if (!ret)
+ peer->chan_switch_enabled = 1;
+
+ return ret;
+}
+
+
+int wpa_tdls_disable_chan_switch(struct wpa_sm *sm, const u8 *addr)
+{
+ struct wpa_tdls_peer *peer;
+
+ if (sm->tdls_disabled || !sm->tdls_supported)
+ return -1;
+
+ for (peer = sm->tdls; peer; peer = peer->next) {
+ if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
+ break;
+ }
+
+ if (!peer || !peer->chan_switch_enabled) {
+ wpa_printf(MSG_ERROR, "TDLS: Channel switching not enabled for "
+ MACSTR, MAC2STR(addr));
+ return -1;
+ }
+
+ /* ignore the return value */
+ wpa_sm_tdls_disable_channel_switch(sm, peer->addr);
+
+ peer->chan_switch_enabled = 0;
+ return 0;
+}
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 8f561b9..b892a66 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - WPA state machine and EAPOL-Key processing
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -27,6 +27,7 @@
* wpa_eapol_key_send - Send WPA/RSN EAPOL-Key message
* @sm: Pointer to WPA state machine data from wpa_sm_init()
* @kck: Key Confirmation Key (KCK, part of PTK)
+ * @kck_len: KCK length in octets
* @ver: Version field from Key Info
* @dest: Destination address for the frame
* @proto: Ethertype (usually ETH_P_EAPOL)
@@ -34,10 +35,12 @@
* @msg_len: Length of message
* @key_mic: Pointer to the buffer to which the EAPOL-Key MIC is written
*/
-void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck,
+void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, size_t kck_len,
int ver, const u8 *dest, u16 proto,
u8 *msg, size_t msg_len, u8 *key_mic)
{
+ size_t mic_len = wpa_mic_len(sm->key_mgmt);
+
if (is_zero_ether_addr(dest) && is_zero_ether_addr(sm->bssid)) {
/*
* Association event was not yet received; try to fetch
@@ -56,14 +59,15 @@
}
}
if (key_mic &&
- wpa_eapol_key_mic(kck, ver, msg, msg_len, key_mic)) {
+ wpa_eapol_key_mic(kck, kck_len, sm->key_mgmt, ver, msg, msg_len,
+ key_mic)) {
wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
- "WPA: Failed to generate EAPOL-Key "
- "version %d MIC", ver);
+ "WPA: Failed to generate EAPOL-Key version %d key_mgmt 0x%x MIC",
+ ver, sm->key_mgmt);
goto out;
}
- wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", kck, 16);
- wpa_hexdump(MSG_DEBUG, "WPA: Derived Key MIC", key_mic, 16);
+ wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", kck, kck_len);
+ wpa_hexdump(MSG_DEBUG, "WPA: Derived Key MIC", key_mic, mic_len);
wpa_hexdump(MSG_MSGDUMP, "WPA: TX EAPOL-Key", msg, msg_len);
wpa_sm_ether_send(sm, dest, proto, msg, msg_len);
eapol_sm_notify_tx_eapol_key(sm->eapol);
@@ -84,12 +88,14 @@
*/
void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
{
- size_t rlen;
+ size_t mic_len, hdrlen, rlen;
struct wpa_eapol_key *reply;
+ struct wpa_eapol_key_192 *reply192;
int key_info, ver;
- u8 bssid[ETH_ALEN], *rbuf;
+ u8 bssid[ETH_ALEN], *rbuf, *key_mic;
- if (sm->key_mgmt == WPA_KEY_MGMT_OSEN)
+ if (sm->key_mgmt == WPA_KEY_MGMT_OSEN ||
+ wpa_key_mgmt_suite_b(sm->key_mgmt))
ver = WPA_KEY_INFO_TYPE_AKM_DEFINED;
else if (wpa_key_mgmt_ft(sm->key_mgmt) ||
wpa_key_mgmt_sha256(sm->key_mgmt))
@@ -105,10 +111,13 @@
return;
}
+ mic_len = wpa_mic_len(sm->key_mgmt);
+ hdrlen = mic_len == 24 ? sizeof(*reply192) : sizeof(*reply);
rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
- sizeof(*reply), &rlen, (void *) &reply);
+ hdrlen, &rlen, (void *) &reply);
if (rbuf == NULL)
return;
+ reply192 = (struct wpa_eapol_key_192 *) reply;
reply->type = (sm->proto == WPA_PROTO_RSN ||
sm->proto == WPA_PROTO_OSEN) ?
@@ -126,15 +135,39 @@
WPA_REPLAY_COUNTER_LEN);
inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN);
- WPA_PUT_BE16(reply->key_data_length, 0);
+ if (mic_len == 24)
+ WPA_PUT_BE16(reply192->key_data_length, 0);
+ else
+ WPA_PUT_BE16(reply->key_data_length, 0);
+ if (!(key_info & WPA_KEY_INFO_MIC))
+ key_mic = NULL;
+ else
+ key_mic = reply192->key_mic; /* same offset in reply */
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: Sending EAPOL-Key Request (error=%d "
"pairwise=%d ptk_set=%d len=%lu)",
error, pairwise, sm->ptk_set, (unsigned long) rlen);
- wpa_eapol_key_send(sm, sm->ptk.kck, ver, bssid, ETH_P_EAPOL,
- rbuf, rlen, key_info & WPA_KEY_INFO_MIC ?
- reply->key_mic : NULL);
+ wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, bssid,
+ ETH_P_EAPOL, rbuf, rlen, key_mic);
+}
+
+
+static void wpa_supplicant_key_mgmt_set_pmk(struct wpa_sm *sm)
+{
+#ifdef CONFIG_IEEE80211R
+ if (sm->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
+ if (wpa_sm_key_mgmt_set_pmk(sm, sm->xxkey, sm->xxkey_len))
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "RSN: Cannot set low order 256 bits of MSK for key management offload");
+ } else {
+#endif /* CONFIG_IEEE80211R */
+ if (wpa_sm_key_mgmt_set_pmk(sm, sm->pmk, sm->pmk_len))
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "RSN: Cannot set PMK for key management offload");
+#ifdef CONFIG_IEEE80211R
+ }
+#endif /* CONFIG_IEEE80211R */
}
@@ -198,10 +231,13 @@
wpa_hexdump_key(MSG_DEBUG, "WPA: PMK from EAPOL state "
"machines", sm->pmk, pmk_len);
sm->pmk_len = pmk_len;
+ wpa_supplicant_key_mgmt_set_pmk(sm);
if (sm->proto == WPA_PROTO_RSN &&
+ !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
!wpa_key_mgmt_ft(sm->key_mgmt)) {
sa = pmksa_cache_add(sm->pmksa,
sm->pmk, pmk_len,
+ NULL, 0,
src_addr, sm->own_addr,
sm->network_ctx,
sm->key_mgmt);
@@ -235,6 +271,7 @@
}
if (abort_cached && wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) &&
+ !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
!wpa_key_mgmt_ft(sm->key_mgmt) && sm->key_mgmt != WPA_KEY_MGMT_OSEN)
{
/* Send EAPOL-Start to trigger full EAP authentication. */
@@ -278,9 +315,10 @@
const u8 *wpa_ie, size_t wpa_ie_len,
struct wpa_ptk *ptk)
{
- size_t rlen;
+ size_t mic_len, hdrlen, rlen;
struct wpa_eapol_key *reply;
- u8 *rbuf;
+ struct wpa_eapol_key_192 *reply192;
+ u8 *rbuf, *key_mic;
u8 *rsn_ie_buf = NULL;
if (wpa_ie == NULL) {
@@ -322,13 +360,16 @@
wpa_hexdump(MSG_DEBUG, "WPA: WPA IE for msg 2/4", wpa_ie, wpa_ie_len);
+ mic_len = wpa_mic_len(sm->key_mgmt);
+ hdrlen = mic_len == 24 ? sizeof(*reply192) : sizeof(*reply);
rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY,
- NULL, sizeof(*reply) + wpa_ie_len,
+ NULL, hdrlen + wpa_ie_len,
&rlen, (void *) &reply);
if (rbuf == NULL) {
os_free(rsn_ie_buf);
return -1;
}
+ reply192 = (struct wpa_eapol_key_192 *) reply;
reply->type = (sm->proto == WPA_PROTO_RSN ||
sm->proto == WPA_PROTO_OSEN) ?
@@ -344,35 +385,38 @@
wpa_hexdump(MSG_DEBUG, "WPA: Replay Counter", reply->replay_counter,
WPA_REPLAY_COUNTER_LEN);
- WPA_PUT_BE16(reply->key_data_length, wpa_ie_len);
- os_memcpy(reply + 1, wpa_ie, wpa_ie_len);
+ key_mic = reply192->key_mic; /* same offset for reply and reply192 */
+ if (mic_len == 24) {
+ WPA_PUT_BE16(reply192->key_data_length, wpa_ie_len);
+ os_memcpy(reply192 + 1, wpa_ie, wpa_ie_len);
+ } else {
+ WPA_PUT_BE16(reply->key_data_length, wpa_ie_len);
+ os_memcpy(reply + 1, wpa_ie, wpa_ie_len);
+ }
os_free(rsn_ie_buf);
os_memcpy(reply->key_nonce, nonce, WPA_NONCE_LEN);
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/4");
- wpa_eapol_key_send(sm, ptk->kck, ver, dst, ETH_P_EAPOL,
- rbuf, rlen, reply->key_mic);
+ wpa_eapol_key_send(sm, ptk->kck, ptk->kck_len, ver, dst, ETH_P_EAPOL,
+ rbuf, rlen, key_mic);
return 0;
}
static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,
- const struct wpa_eapol_key *key,
- struct wpa_ptk *ptk)
+ const struct wpa_eapol_key *key, struct wpa_ptk *ptk)
{
- size_t ptk_len = wpa_cipher_key_len(sm->pairwise_cipher) + 32;
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->key_mgmt))
- return wpa_derive_ptk_ft(sm, src_addr, key, ptk, ptk_len);
+ return wpa_derive_ptk_ft(sm, src_addr, key, ptk);
#endif /* CONFIG_IEEE80211R */
- wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion",
- sm->own_addr, sm->bssid, sm->snonce, key->key_nonce,
- (u8 *) ptk, ptk_len,
- wpa_key_mgmt_sha256(sm->key_mgmt));
- return 0;
+ return wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion",
+ sm->own_addr, sm->bssid, sm->snonce,
+ key->key_nonce, ptk, sm->key_mgmt,
+ sm->pairwise_cipher);
}
@@ -439,9 +483,9 @@
if (sm->pairwise_cipher == WPA_CIPHER_TKIP) {
u8 buf[8];
/* Supplicant: swap tx/rx Mic keys */
- os_memcpy(buf, ptk->u.auth.tx_mic_key, 8);
- os_memcpy(ptk->u.auth.tx_mic_key, ptk->u.auth.rx_mic_key, 8);
- os_memcpy(ptk->u.auth.rx_mic_key, buf, 8);
+ os_memcpy(buf, &ptk->tk[16], 8);
+ os_memcpy(&ptk->tk[16], &ptk->tk[24], 8);
+ os_memcpy(&ptk->tk[24], buf, 8);
os_memset(buf, 0, sizeof(buf));
}
sm->tptk_set = 1;
@@ -578,7 +622,7 @@
}
if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, key_rsc, rsclen,
- (u8 *) sm->ptk.tk1, keylen) < 0) {
+ sm->ptk.tk, keylen) < 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Failed to set PTK to the "
"driver (alg=%d keylen=%d bssid=" MACSTR ")",
@@ -586,6 +630,9 @@
return -1;
}
+ /* TK is not needed anymore in supplicant */
+ os_memset(sm->ptk.tk, 0, WPA_TK_MAX_LEN);
+
if (sm->wpa_ptk_rekey) {
eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
eloop_register_timeout(sm->wpa_ptk_rekey, 0, wpa_sm_rekey_ptk,
@@ -1035,14 +1082,18 @@
u16 ver, u16 key_info,
struct wpa_ptk *ptk)
{
- size_t rlen;
+ size_t mic_len, hdrlen, rlen;
struct wpa_eapol_key *reply;
- u8 *rbuf;
+ struct wpa_eapol_key_192 *reply192;
+ u8 *rbuf, *key_mic;
+ mic_len = wpa_mic_len(sm->key_mgmt);
+ hdrlen = mic_len == 24 ? sizeof(*reply192) : sizeof(*reply);
rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
- sizeof(*reply), &rlen, (void *) &reply);
+ hdrlen, &rlen, (void *) &reply);
if (rbuf == NULL)
return -1;
+ reply192 = (struct wpa_eapol_key_192 *) reply;
reply->type = (sm->proto == WPA_PROTO_RSN ||
sm->proto == WPA_PROTO_OSEN) ?
@@ -1057,11 +1108,15 @@
os_memcpy(reply->replay_counter, key->replay_counter,
WPA_REPLAY_COUNTER_LEN);
- WPA_PUT_BE16(reply->key_data_length, 0);
+ key_mic = reply192->key_mic; /* same offset for reply and reply192 */
+ if (mic_len == 24)
+ WPA_PUT_BE16(reply192->key_data_length, 0);
+ else
+ WPA_PUT_BE16(reply->key_data_length, 0);
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 4/4");
- wpa_eapol_key_send(sm, ptk->kck, ver, dst, ETH_P_EAPOL,
- rbuf, rlen, reply->key_mic);
+ wpa_eapol_key_send(sm, ptk->kck, ptk->kck_len, ver, dst, ETH_P_EAPOL,
+ rbuf, rlen, key_mic);
return 0;
}
@@ -1178,6 +1233,17 @@
if (ie.gtk)
wpa_sm_set_rekey_offload(sm);
+ if (sm->proto == WPA_PROTO_RSN && wpa_key_mgmt_suite_b(sm->key_mgmt)) {
+ struct rsn_pmksa_cache_entry *sa;
+
+ sa = pmksa_cache_add(sm->pmksa, sm->pmk, sm->pmk_len,
+ sm->ptk.kck, sm->ptk.kck_len,
+ sm->bssid, sm->own_addr,
+ sm->network_ctx, sm->key_mgmt);
+ if (!sm->cur_pmksa)
+ sm->cur_pmksa = sa;
+ }
+
return;
failed:
@@ -1242,8 +1308,9 @@
u16 ver, struct wpa_gtk_data *gd)
{
size_t maxkeylen;
+ u16 gtk_len;
- gd->gtk_len = WPA_GET_BE16(key->key_length);
+ gtk_len = WPA_GET_BE16(key->key_length);
maxkeylen = key_data_len;
if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
if (maxkeylen < 8) {
@@ -1255,14 +1322,16 @@
maxkeylen -= 8;
}
- if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
- gd->gtk_len, maxkeylen,
+ if (gtk_len > maxkeylen ||
+ wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
+ gtk_len, maxkeylen,
&gd->key_rsc_len, &gd->alg))
return -1;
+ gd->gtk_len = gtk_len;
gd->keyidx = (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >>
WPA_KEY_INFO_KEY_INDEX_SHIFT;
- if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) {
+ if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 && sm->ptk.kek_len == 16) {
u8 ek[32];
if (key_data_len > sizeof(gd->gtk)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
@@ -1271,7 +1340,7 @@
return -1;
}
os_memcpy(ek, key->key_iv, 16);
- os_memcpy(ek + 16, sm->ptk.kek, 16);
+ os_memcpy(ek + 16, sm->ptk.kek, sm->ptk.kek_len);
os_memcpy(gd->gtk, key_data, key_data_len);
if (rc4_skip(ek, 32, 256, gd->gtk, key_data_len)) {
os_memset(ek, 0, sizeof(ek));
@@ -1295,8 +1364,8 @@
(unsigned long) maxkeylen);
return -1;
}
- if (aes_unwrap(sm->ptk.kek, 16, maxkeylen / 8, key_data,
- gd->gtk)) {
+ if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, maxkeylen / 8,
+ key_data, gd->gtk)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: AES unwrap failed - could not decrypt "
"GTK");
@@ -1317,14 +1386,18 @@
const struct wpa_eapol_key *key,
int ver, u16 key_info)
{
- size_t rlen;
+ size_t mic_len, hdrlen, rlen;
struct wpa_eapol_key *reply;
- u8 *rbuf;
+ struct wpa_eapol_key_192 *reply192;
+ u8 *rbuf, *key_mic;
+ mic_len = wpa_mic_len(sm->key_mgmt);
+ hdrlen = mic_len == 24 ? sizeof(*reply192) : sizeof(*reply);
rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
- sizeof(*reply), &rlen, (void *) &reply);
+ hdrlen, &rlen, (void *) &reply);
if (rbuf == NULL)
return -1;
+ reply192 = (struct wpa_eapol_key_192 *) reply;
reply->type = (sm->proto == WPA_PROTO_RSN ||
sm->proto == WPA_PROTO_OSEN) ?
@@ -1339,11 +1412,15 @@
os_memcpy(reply->replay_counter, key->replay_counter,
WPA_REPLAY_COUNTER_LEN);
- WPA_PUT_BE16(reply->key_data_length, 0);
+ key_mic = reply192->key_mic; /* same offset for reply and reply192 */
+ if (mic_len == 24)
+ WPA_PUT_BE16(reply192->key_data_length, 0);
+ else
+ WPA_PUT_BE16(reply->key_data_length, 0);
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/2");
- wpa_eapol_key_send(sm, sm->ptk.kck, ver, sm->bssid, ETH_P_EAPOL,
- rbuf, rlen, reply->key_mic);
+ wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, sm->bssid,
+ ETH_P_EAPOL, rbuf, rlen, key_mic);
return 0;
}
@@ -1385,6 +1462,7 @@
if (wpa_supplicant_install_gtk(sm, &gd, key->key_rsc) ||
wpa_supplicant_send_2_of_2(sm, key, ver, key_info))
goto failed;
+ os_memset(&gd, 0, sizeof(gd));
if (rekey) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Group rekeying "
@@ -1403,24 +1481,26 @@
return;
failed:
+ os_memset(&gd, 0, sizeof(gd));
wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
}
static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm,
- struct wpa_eapol_key *key,
+ struct wpa_eapol_key_192 *key,
u16 ver,
const u8 *buf, size_t len)
{
- u8 mic[16];
+ u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
int ok = 0;
+ size_t mic_len = wpa_mic_len(sm->key_mgmt);
- os_memcpy(mic, key->key_mic, 16);
+ os_memcpy(mic, key->key_mic, mic_len);
if (sm->tptk_set) {
- os_memset(key->key_mic, 0, 16);
- wpa_eapol_key_mic(sm->tptk.kck, ver, buf, len,
- key->key_mic);
- if (os_memcmp_const(mic, key->key_mic, 16) != 0) {
+ os_memset(key->key_mic, 0, mic_len);
+ wpa_eapol_key_mic(sm->tptk.kck, sm->tptk.kck_len, sm->key_mgmt,
+ ver, buf, len, key->key_mic);
+ if (os_memcmp_const(mic, key->key_mic, mic_len) != 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Invalid EAPOL-Key MIC "
"when using TPTK - ignoring TPTK");
@@ -1434,10 +1514,10 @@
}
if (!ok && sm->ptk_set) {
- os_memset(key->key_mic, 0, 16);
- wpa_eapol_key_mic(sm->ptk.kck, ver, buf, len,
- key->key_mic);
- if (os_memcmp_const(mic, key->key_mic, 16) != 0) {
+ os_memset(key->key_mic, 0, mic_len);
+ wpa_eapol_key_mic(sm->ptk.kck, sm->ptk.kck_len, sm->key_mgmt,
+ ver, buf, len, key->key_mic);
+ if (os_memcmp_const(mic, key->key_mic, mic_len) != 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Invalid EAPOL-Key MIC - "
"dropping packet");
@@ -1476,10 +1556,10 @@
/* Decrypt key data here so that this operation does not need
* to be implemented separately for each message type. */
- if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) {
+ if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 && sm->ptk.kek_len == 16) {
u8 ek[32];
os_memcpy(ek, key->key_iv, 16);
- os_memcpy(ek + 16, sm->ptk.kek, 16);
+ os_memcpy(ek + 16, sm->ptk.kek, sm->ptk.kek_len);
if (rc4_skip(ek, 32, 256, key_data, *key_data_len)) {
os_memset(ek, 0, sizeof(ek));
wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
@@ -1489,7 +1569,8 @@
os_memset(ek, 0, sizeof(ek));
} else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
ver == WPA_KEY_INFO_TYPE_AES_128_CMAC ||
- sm->key_mgmt == WPA_KEY_MGMT_OSEN) {
+ sm->key_mgmt == WPA_KEY_MGMT_OSEN ||
+ wpa_key_mgmt_suite_b(sm->key_mgmt)) {
u8 *buf;
if (*key_data_len < 8 || *key_data_len % 8) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
@@ -1504,7 +1585,7 @@
"WPA: No memory for AES-UNWRAP buffer");
return -1;
}
- if (aes_unwrap(sm->ptk.kek, 16, *key_data_len / 8,
+ if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, *key_data_len / 8,
key_data, buf)) {
os_free(buf);
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
@@ -1541,7 +1622,9 @@
static void wpa_eapol_key_dump(struct wpa_sm *sm,
- const struct wpa_eapol_key *key)
+ const struct wpa_eapol_key *key,
+ unsigned int key_data_len,
+ const u8 *mic, unsigned int mic_len)
{
#ifndef CONFIG_NO_STDOUT_DEBUG
u16 key_info = WPA_GET_BE16(key->key_info);
@@ -1563,15 +1646,14 @@
key_info & WPA_KEY_INFO_ENCR_KEY_DATA ? " Encr" : "");
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
" key_length=%u key_data_length=%u",
- WPA_GET_BE16(key->key_length),
- WPA_GET_BE16(key->key_data_length));
+ WPA_GET_BE16(key->key_length), key_data_len);
wpa_hexdump(MSG_DEBUG, " replay_counter",
key->replay_counter, WPA_REPLAY_COUNTER_LEN);
wpa_hexdump(MSG_DEBUG, " key_nonce", key->key_nonce, WPA_NONCE_LEN);
wpa_hexdump(MSG_DEBUG, " key_iv", key->key_iv, 16);
wpa_hexdump(MSG_DEBUG, " key_rsc", key->key_rsc, 8);
wpa_hexdump(MSG_DEBUG, " key_id (reserved)", key->key_id, 8);
- wpa_hexdump(MSG_DEBUG, " key_mic", key->key_mic, 16);
+ wpa_hexdump(MSG_DEBUG, " key_mic", mic, mic_len);
#endif /* CONFIG_NO_STDOUT_DEBUG */
}
@@ -1598,22 +1680,27 @@
size_t plen, data_len, key_data_len;
const struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
+ struct wpa_eapol_key_192 *key192;
u16 key_info, ver;
u8 *tmp = NULL;
int ret = -1;
struct wpa_peerkey *peerkey = NULL;
u8 *key_data;
+ size_t mic_len, keyhdrlen;
#ifdef CONFIG_IEEE80211R
sm->ft_completed = 0;
#endif /* CONFIG_IEEE80211R */
- if (len < sizeof(*hdr) + sizeof(*key)) {
+ mic_len = wpa_mic_len(sm->key_mgmt);
+ keyhdrlen = mic_len == 24 ? sizeof(*key192) : sizeof(*key);
+
+ if (len < sizeof(*hdr) + keyhdrlen) {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
"WPA: EAPOL frame too short to be a WPA "
"EAPOL-Key (len %lu, expecting at least %lu)",
(unsigned long) len,
- (unsigned long) sizeof(*hdr) + sizeof(*key));
+ (unsigned long) sizeof(*hdr) + keyhdrlen);
return 0;
}
@@ -1635,7 +1722,7 @@
goto out;
}
wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL-Key", buf, len);
- if (plen > len - sizeof(*hdr) || plen < sizeof(*key)) {
+ if (plen > len - sizeof(*hdr) || plen < keyhdrlen) {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
"WPA: EAPOL frame payload size %lu "
"invalid (frame size %lu)",
@@ -1658,7 +1745,12 @@
goto out;
os_memcpy(tmp, buf, data_len);
key = (struct wpa_eapol_key *) (tmp + sizeof(struct ieee802_1x_hdr));
- key_data = (u8 *) (key + 1);
+ key192 = (struct wpa_eapol_key_192 *)
+ (tmp + sizeof(struct ieee802_1x_hdr));
+ if (mic_len == 24)
+ key_data = (u8 *) (key192 + 1);
+ else
+ key_data = (u8 *) (key + 1);
if (key->type != EAPOL_KEY_TYPE_WPA && key->type != EAPOL_KEY_TYPE_RSN)
{
@@ -1668,14 +1760,18 @@
ret = 0;
goto out;
}
- wpa_eapol_key_dump(sm, key);
- key_data_len = WPA_GET_BE16(key->key_data_length);
- if (key_data_len > plen - sizeof(struct wpa_eapol_key)) {
+ if (mic_len == 24)
+ key_data_len = WPA_GET_BE16(key192->key_data_length);
+ else
+ key_data_len = WPA_GET_BE16(key->key_data_length);
+ wpa_eapol_key_dump(sm, key, key_data_len, key192->key_mic, mic_len);
+
+ if (key_data_len > plen - keyhdrlen) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Invalid EAPOL-Key "
"frame - key_data overflow (%u > %u)",
(unsigned int) key_data_len,
- (unsigned int) (plen - sizeof(struct wpa_eapol_key)));
+ (unsigned int) (plen - keyhdrlen));
goto out;
}
@@ -1687,6 +1783,7 @@
ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES &&
+ !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
sm->key_mgmt != WPA_KEY_MGMT_OSEN) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: Unsupported EAPOL-Key descriptor version %d",
@@ -1702,6 +1799,14 @@
goto out;
}
+ if (wpa_key_mgmt_suite_b(sm->key_mgmt) &&
+ ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "RSN: Unsupported EAPOL-Key descriptor version %d (expected AKM defined = 0)",
+ ver);
+ goto out;
+ }
+
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->key_mgmt)) {
/* IEEE 802.11r uses a new key_info type (AES-128-CMAC). */
@@ -1715,7 +1820,8 @@
#ifdef CONFIG_IEEE80211W
if (wpa_key_mgmt_sha256(sm->key_mgmt)) {
if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
- sm->key_mgmt != WPA_KEY_MGMT_OSEN) {
+ sm->key_mgmt != WPA_KEY_MGMT_OSEN &&
+ !wpa_key_mgmt_suite_b(sm->key_mgmt)) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: AP did not use the "
"negotiated AES-128-CMAC");
@@ -1724,6 +1830,7 @@
} else
#endif /* CONFIG_IEEE80211W */
if (sm->pairwise_cipher == WPA_CIPHER_CCMP &&
+ !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: CCMP is used, but EAPOL-Key "
@@ -1743,6 +1850,7 @@
} else
goto out;
} else if (sm->pairwise_cipher == WPA_CIPHER_GCMP &&
+ !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: GCMP is used, but EAPOL-Key "
@@ -1813,12 +1921,13 @@
}
if ((key_info & WPA_KEY_INFO_MIC) && !peerkey &&
- wpa_supplicant_verify_eapol_key_mic(sm, key, ver, tmp, data_len))
+ wpa_supplicant_verify_eapol_key_mic(sm, key192, ver, tmp, data_len))
goto out;
#ifdef CONFIG_PEERKEY
if ((key_info & WPA_KEY_INFO_MIC) && peerkey &&
- peerkey_verify_eapol_key_mic(sm, peerkey, key, ver, tmp, data_len))
+ peerkey_verify_eapol_key_mic(sm, peerkey, key192, ver, tmp,
+ data_len))
goto out;
#endif /* CONFIG_PEERKEY */
@@ -1870,7 +1979,7 @@
ret = 1;
out:
- os_free(tmp);
+ bin_clear_free(tmp, data_len);
return ret;
}
@@ -1906,6 +2015,10 @@
WPA_AUTH_KEY_MGMT_CCKM);
case WPA_KEY_MGMT_WPA_NONE:
return WPA_AUTH_KEY_MGMT_NONE;
+ case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
+ return RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
+ case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
+ return RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192;
default:
return 0;
}
@@ -1963,7 +2076,7 @@
sm->dot11RSNAConfigPMKLifetime,
sm->dot11RSNAConfigPMKReauthThreshold,
sm->dot11RSNAConfigSATimeout);
- if (ret < 0 || (size_t) ret >= buflen)
+ if (os_snprintf_error(buflen, ret))
return 0;
len = ret;
@@ -1990,7 +2103,7 @@
RSN_SUITE_ARG(wpa_cipher_to_suite(sm->proto,
sm->group_cipher)),
sm->dot11RSNA4WayHandshakeFailures);
- if (ret >= 0 && (size_t) ret < buflen)
+ if (!os_snprintf_error(buflen - len, ret))
len += ret;
return (int) len;
@@ -2088,6 +2201,7 @@
os_free(sm->assoc_wpa_ie);
os_free(sm->ap_wpa_ie);
os_free(sm->ap_rsn_ie);
+ wpa_sm_drop_sa(sm);
os_free(sm->ctx);
peerkey_deinit(sm);
#ifdef CONFIG_IEEE80211R
@@ -2176,6 +2290,9 @@
#ifdef CONFIG_TDLS
wpa_tdls_disassoc(sm);
#endif /* CONFIG_TDLS */
+
+ /* Keys are not needed in the WPA state machine anymore */
+ wpa_sm_drop_sa(sm);
}
@@ -2184,10 +2301,12 @@
* @sm: Pointer to WPA state machine data from wpa_sm_init()
* @pmk: The new PMK
* @pmk_len: The length of the new PMK in bytes
+ * @bssid: AA to add into PMKSA cache or %NULL to not cache the PMK
*
* Configure the PMK for WPA state machine.
*/
-void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len)
+void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
+ const u8 *bssid)
{
if (sm == NULL)
return;
@@ -2200,6 +2319,12 @@
sm->xxkey_len = pmk_len;
os_memcpy(sm->xxkey, pmk, pmk_len);
#endif /* CONFIG_IEEE80211R */
+
+ if (bssid) {
+ pmksa_cache_add(sm->pmksa, pmk, pmk_len, NULL, 0,
+ bssid, sm->own_addr,
+ sm->network_ctx, sm->key_mgmt);
+ }
}
@@ -2424,7 +2549,7 @@
wpa_cipher_txt(sm->pairwise_cipher),
wpa_cipher_txt(sm->group_cipher),
wpa_key_mgmt_txt(sm->key_mgmt, sm->proto));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -2437,7 +2562,7 @@
ret = os_snprintf(pos, end - pos, "pmf=%d\n",
(rsn.capabilities &
WPA_CAPABILITY_MFPR) ? 2 : 1);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -2640,7 +2765,6 @@
}
-#ifdef CONFIG_TESTING_OPTIONS
void wpa_sm_drop_sa(struct wpa_sm *sm)
{
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Clear old PMK and PTK");
@@ -2649,8 +2773,12 @@
os_memset(sm->pmk, 0, sizeof(sm->pmk));
os_memset(&sm->ptk, 0, sizeof(sm->ptk));
os_memset(&sm->tptk, 0, sizeof(sm->tptk));
+#ifdef CONFIG_IEEE80211R
+ os_memset(sm->xxkey, 0, sizeof(sm->xxkey));
+ os_memset(sm->pmk_r0, 0, sizeof(sm->pmk_r0));
+ os_memset(sm->pmk_r1, 0, sizeof(sm->pmk_r1));
+#endif /* CONFIG_IEEE80211R */
}
-#endif /* CONFIG_TESTING_OPTIONS */
int wpa_sm_has_ptk(struct wpa_sm *sm)
@@ -2783,3 +2911,33 @@
}
#endif /* CONFIG_P2P */
+
+
+void wpa_sm_set_rx_replay_ctr(struct wpa_sm *sm, const u8 *rx_replay_counter)
+{
+ if (rx_replay_counter == NULL)
+ return;
+
+ os_memcpy(sm->rx_replay_counter, rx_replay_counter,
+ WPA_REPLAY_COUNTER_LEN);
+ sm->rx_replay_counter_set = 1;
+ wpa_printf(MSG_DEBUG, "Updated key replay counter");
+}
+
+
+void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm,
+ const u8 *ptk_kck, size_t ptk_kck_len,
+ const u8 *ptk_kek, size_t ptk_kek_len)
+{
+ if (ptk_kck && ptk_kck_len <= WPA_KCK_MAX_LEN) {
+ os_memcpy(sm->ptk.kck, ptk_kck, ptk_kck_len);
+ sm->ptk.kck_len = ptk_kck_len;
+ wpa_printf(MSG_DEBUG, "Updated PTK KCK");
+ }
+ if (ptk_kek && ptk_kek_len <= WPA_KEK_MAX_LEN) {
+ os_memcpy(sm->ptk.kek, ptk_kek, ptk_kek_len);
+ sm->ptk.kek_len = ptk_kek_len;
+ wpa_printf(MSG_DEBUG, "Updated PTK KEK");
+ }
+ sm->ptk_set = 1;
+}
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 63032b0..e163b70 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -1,6 +1,6 @@
/*
* wpa_supplicant - WPA definitions
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -17,6 +17,7 @@
struct wpa_sm;
struct eapol_sm;
struct wpa_config_blob;
+struct hostapd_freq_params;
struct wpa_sm_ctx {
void *ctx; /* pointer to arbitrary upper level context */
@@ -51,7 +52,7 @@
int (*mark_authenticated)(void *ctx, const u8 *target_ap);
#ifdef CONFIG_TDLS
int (*tdls_get_capa)(void *ctx, int *tdls_supported,
- int *tdls_ext_setup);
+ int *tdls_ext_setup, int *tdls_chan_switch);
int (*send_tdls_mgmt)(void *ctx, const u8 *dst,
u8 action_code, u8 dialog_token,
u16 status_code, u32 peer_capab,
@@ -67,9 +68,15 @@
size_t supp_channels_len,
const u8 *supp_oper_classes,
size_t supp_oper_classes_len);
+ int (*tdls_enable_channel_switch)(
+ void *ctx, const u8 *addr, u8 oper_class,
+ const struct hostapd_freq_params *params);
+ int (*tdls_disable_channel_switch)(void *ctx, const u8 *addr);
#endif /* CONFIG_TDLS */
- void (*set_rekey_offload)(void *ctx, const u8 *kek, const u8 *kck,
+ void (*set_rekey_offload)(void *ctx, const u8 *kek, size_t kek_len,
+ const u8 *kck, size_t kck_len,
const u8 *replay_ctr);
+ int (*key_mgmt_set_pmk)(void *ctx, const u8 *pmk, size_t pmk_len);
};
@@ -105,7 +112,8 @@
void wpa_sm_deinit(struct wpa_sm *sm);
void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid);
void wpa_sm_notify_disassoc(struct wpa_sm *sm);
-void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len);
+void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
+ const u8 *bssid);
void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm);
void wpa_sm_set_fast_reauth(struct wpa_sm *sm, int fast_reauth);
void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx);
@@ -147,6 +155,11 @@
int wpa_sm_get_p2p_ip_addr(struct wpa_sm *sm, u8 *buf);
+void wpa_sm_set_rx_replay_ctr(struct wpa_sm *sm, const u8 *rx_replay_counter);
+void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm,
+ const u8 *ptk_kck, size_t ptk_kck_len,
+ const u8 *ptk_kek, size_t ptk_kek_len);
+
#else /* CONFIG_NO_WPA */
static inline struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx)
@@ -301,6 +314,16 @@
{
}
+static inline void wpa_sm_set_rx_replay_ctr(struct wpa_sm *sm,
+ const u8 *rx_replay_counter)
+{
+}
+
+static inline void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm, const u8 *ptk_kck,
+ const u8 *ptk_kek)
+{
+}
+
#endif /* CONFIG_NO_WPA */
#ifdef CONFIG_PEERKEY
@@ -388,6 +411,10 @@
void wpa_tdls_disable_unreachable_link(struct wpa_sm *sm, const u8 *addr);
const char * wpa_tdls_get_link_status(struct wpa_sm *sm, const u8 *addr);
int wpa_tdls_is_external_setup(struct wpa_sm *sm);
+int wpa_tdls_enable_chan_switch(struct wpa_sm *sm, const u8 *addr,
+ u8 oper_class,
+ struct hostapd_freq_params *freq_params);
+int wpa_tdls_disable_chan_switch(struct wpa_sm *sm, const u8 *addr);
int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf);
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index 3b3c9d0..06dea05 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - IEEE 802.11r - Fast BSS Transition
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -19,8 +19,7 @@
#ifdef CONFIG_IEEE80211R
int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
- const struct wpa_eapol_key *key,
- struct wpa_ptk *ptk, size_t ptk_len)
+ const struct wpa_eapol_key *key, struct wpa_ptk *ptk)
{
u8 ptk_name[WPA_PMK_NAME_LEN];
const u8 *anonce = key->key_nonce;
@@ -43,13 +42,9 @@
wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN);
wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
WPA_PMK_NAME_LEN);
- wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, anonce, sm->own_addr,
- sm->bssid, sm->pmk_r1_name,
- (u8 *) ptk, ptk_len, ptk_name);
- wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, ptk_len);
- wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
-
- return 0;
+ return wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, anonce, sm->own_addr,
+ sm->bssid, sm->pmk_r1_name, ptk, ptk_name,
+ sm->key_mgmt, sm->pairwise_cipher);
}
@@ -134,6 +129,7 @@
* @anonce: ANonce or %NULL if not yet available
* @pmk_name: PMKR0Name or PMKR1Name to be added into the RSN IE PMKID List
* @kck: 128-bit KCK for MIC or %NULL if no MIC is used
+ * @kck_len: KCK length in octets
* @target_ap: Target AP address
* @ric_ies: Optional IE(s), e.g., WMM TSPEC(s), for RIC-Request or %NULL
* @ric_ies_len: Length of ric_ies buffer in octets
@@ -144,7 +140,8 @@
*/
static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
const u8 *anonce, const u8 *pmk_name,
- const u8 *kck, const u8 *target_ap,
+ const u8 *kck, size_t kck_len,
+ const u8 *target_ap,
const u8 *ric_ies, size_t ric_ies_len,
const u8 *ap_mdie)
{
@@ -298,7 +295,7 @@
/* Information element count */
ftie->mic_control[1] = 3 + ieee802_11_ie_count(ric_ies,
ric_ies_len);
- if (wpa_ft_mic(kck, sm->own_addr, target_ap, 5,
+ if (wpa_ft_mic(kck, kck_len, sm->own_addr, target_ap, 5,
((u8 *) mdie) - 2, 2 + sizeof(*mdie),
ftie_pos, 2 + *ftie_len,
(u8 *) rsnie, 2 + rsnie->len, ric_ies,
@@ -333,7 +330,7 @@
keylen = wpa_cipher_key_len(sm->pairwise_cipher);
if (wpa_sm_set_key(sm, alg, bssid, 0, 1, null_rsc,
- sizeof(null_rsc), (u8 *) sm->ptk.tk1, keylen) < 0) {
+ sizeof(null_rsc), (u8 *) sm->ptk.tk, keylen) < 0) {
wpa_printf(MSG_WARNING, "FT: Failed to set PTK to the driver");
return -1;
}
@@ -360,7 +357,7 @@
}
ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name,
- NULL, sm->bssid, NULL, 0, mdie);
+ NULL, 0, sm->bssid, NULL, 0, mdie);
if (ft_ies) {
wpa_sm_update_ft_ies(sm, sm->mobility_domain,
ft_ies, ft_ies_len);
@@ -376,7 +373,7 @@
const u8 *ric_ies, size_t ric_ies_len)
{
u8 *ft_ies;
- size_t ft_ies_len, ptk_len;
+ size_t ft_ies_len;
struct wpa_ft_ies parse;
struct rsn_mdie *mdie;
struct rsn_ftie *ftie;
@@ -478,16 +475,14 @@
sm->pmk_r1_name, WPA_PMK_NAME_LEN);
bssid = target_ap;
- ptk_len = sm->pairwise_cipher != WPA_CIPHER_TKIP ? 48 : 64;
- wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, ftie->anonce, sm->own_addr,
- bssid, sm->pmk_r1_name,
- (u8 *) &sm->ptk, ptk_len, ptk_name);
- wpa_hexdump_key(MSG_DEBUG, "FT: PTK",
- (u8 *) &sm->ptk, ptk_len);
- wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
+ if (wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, ftie->anonce,
+ sm->own_addr, bssid, sm->pmk_r1_name, &sm->ptk,
+ ptk_name, sm->key_mgmt, sm->pairwise_cipher) < 0)
+ return -1;
ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, ftie->anonce,
- sm->pmk_r1_name, sm->ptk.kck, bssid,
+ sm->pmk_r1_name,
+ sm->ptk.kck, sm->ptk.kck_len, bssid,
ric_ies, ric_ies_len,
parse.mdie ? parse.mdie - 2 : NULL);
if (ft_ies) {
@@ -566,7 +561,8 @@
return -1;
}
gtk_len = gtk_elem_len - 19;
- if (aes_unwrap(sm->ptk.kek, 16, gtk_len / 8, gtk_elem + 11, gtk)) {
+ if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, gtk_len / 8, gtk_elem + 11,
+ gtk)) {
wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not "
"decrypt GTK");
return -1;
@@ -645,8 +641,8 @@
return -1;
}
- if (aes_unwrap(sm->ptk.kek, 16, WPA_IGTK_LEN / 8, igtk_elem + 9, igtk))
- {
+ if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, WPA_IGTK_LEN / 8,
+ igtk_elem + 9, igtk)) {
wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not "
"decrypt IGTK");
return -1;
@@ -677,7 +673,7 @@
struct rsn_mdie *mdie;
struct rsn_ftie *ftie;
unsigned int count;
- u8 mic[16];
+ u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);
@@ -770,7 +766,7 @@
return -1;
}
- if (wpa_ft_mic(sm->ptk.kck, sm->own_addr, src_addr, 6,
+ if (wpa_ft_mic(sm->ptk.kck, sm->ptk.kck_len, sm->own_addr, src_addr, 6,
parse.mdie - 2, parse.mdie_len + 2,
parse.ftie - 2, parse.ftie_len + 2,
parse.rsn - 2, parse.rsn_len + 2,
@@ -839,7 +835,7 @@
}
ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name,
- NULL, target_ap, NULL, 0, mdie);
+ NULL, 0, target_ap, NULL, 0, mdie);
if (ft_ies) {
sm->over_the_ds_in_progress = 1;
os_memcpy(sm->target_ap, target_ap, ETH_ALEN);
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 839b545..431bb20 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -1,6 +1,6 @@
/*
* Internal WPA/RSN supplicant state machine definitions
- * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -92,6 +92,7 @@
#ifdef CONFIG_TDLS
struct wpa_tdls_peer *tdls;
int tdls_prohibited;
+ int tdls_chan_switch_prohibited;
int tdls_disabled;
/* The driver supports TDLS */
@@ -102,6 +103,9 @@
* to it via tdls_mgmt.
*/
int tdls_external_setup;
+
+ /* The driver supports TDLS channel switching */
+ int tdls_chan_switch;
#endif /* CONFIG_TDLS */
#ifdef CONFIG_IEEE80211R
@@ -250,18 +254,20 @@
{
if (!sm->ctx->set_rekey_offload)
return;
- sm->ctx->set_rekey_offload(sm->ctx->ctx, sm->ptk.kek,
- sm->ptk.kck, sm->rx_replay_counter);
+ sm->ctx->set_rekey_offload(sm->ctx->ctx, sm->ptk.kek, sm->ptk.kek_len,
+ sm->ptk.kck, sm->ptk.kck_len,
+ sm->rx_replay_counter);
}
#ifdef CONFIG_TDLS
static inline int wpa_sm_tdls_get_capa(struct wpa_sm *sm,
int *tdls_supported,
- int *tdls_ext_setup)
+ int *tdls_ext_setup,
+ int *tdls_chan_switch)
{
if (sm->ctx->tdls_get_capa)
return sm->ctx->tdls_get_capa(sm->ctx->ctx, tdls_supported,
- tdls_ext_setup);
+ tdls_ext_setup, tdls_chan_switch);
return -1;
}
@@ -310,9 +316,39 @@
supp_oper_classes_len);
return -1;
}
+
+static inline int
+wpa_sm_tdls_enable_channel_switch(struct wpa_sm *sm, const u8 *addr,
+ u8 oper_class,
+ const struct hostapd_freq_params *freq_params)
+{
+ if (sm->ctx->tdls_enable_channel_switch)
+ return sm->ctx->tdls_enable_channel_switch(sm->ctx->ctx, addr,
+ oper_class,
+ freq_params);
+ return -1;
+}
+
+static inline int
+wpa_sm_tdls_disable_channel_switch(struct wpa_sm *sm, const u8 *addr)
+{
+ if (sm->ctx->tdls_disable_channel_switch)
+ return sm->ctx->tdls_disable_channel_switch(sm->ctx->ctx, addr);
+ return -1;
+}
#endif /* CONFIG_TDLS */
-void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck,
+static inline int wpa_sm_key_mgmt_set_pmk(struct wpa_sm *sm,
+ const u8 *pmk, size_t pmk_len)
+{
+ if (!sm->proactive_key_caching)
+ return 0;
+ if (!sm->ctx->key_mgmt_set_pmk)
+ return -1;
+ return sm->ctx->key_mgmt_set_pmk(sm->ctx->ctx, pmk, pmk_len);
+}
+
+void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, size_t kck_len,
int ver, const u8 *dest, u16 proto,
u8 *msg, size_t msg_len, u8 *key_mic);
int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
@@ -326,8 +362,7 @@
struct wpa_ptk *ptk);
int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
- const struct wpa_eapol_key *key,
- struct wpa_ptk *ptk, size_t ptk_len);
+ const struct wpa_eapol_key *key, struct wpa_ptk *ptk);
void wpa_tdls_assoc(struct wpa_sm *sm);
void wpa_tdls_disassoc(struct wpa_sm *sm);
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index 93e8cf6..cb334df 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -1,6 +1,6 @@
/*
* wpa_supplicant - WPA/RSN IE and KDE processing
- * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -173,6 +173,10 @@
} else if (key_mgmt == WPA_KEY_MGMT_FT_SAE) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
#endif /* CONFIG_SAE */
+ } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192);
+ } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B);
} else {
wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
key_mgmt);
diff --git a/src/tls/asn1.c b/src/tls/asn1.c
index 97462fa..cec1092 100644
--- a/src/tls/asn1.c
+++ b/src/tls/asn1.c
@@ -166,7 +166,7 @@
ret = os_snprintf(pos, buf + len - pos,
"%s%lu",
i == 0 ? "" : ".", oid->oid[i]);
- if (ret < 0 || ret >= buf + len - pos)
+ if (os_snprintf_error(buf + len - pos, ret))
break;
pos += ret;
}
diff --git a/src/tls/tlsv1_client.c b/src/tls/tlsv1_client.c
index 4a4f0b6..facdd65 100644
--- a/src/tls/tlsv1_client.c
+++ b/src/tls/tlsv1_client.c
@@ -570,8 +570,26 @@
case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
cipher = "DES-CBC3-SHA";
break;
- case TLS_DH_anon_WITH_AES_128_CBC_SHA256:
- cipher = "ADH-AES-128-SHA256";
+ case TLS_DHE_RSA_WITH_DES_CBC_SHA:
+ cipher = "DHE-RSA-DES-CBC-SHA";
+ break;
+ case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ cipher = "DHE-RSA-DES-CBC3-SHA";
+ break;
+ case TLS_DH_anon_WITH_RC4_128_MD5:
+ cipher = "ADH-RC4-MD5";
+ break;
+ case TLS_DH_anon_WITH_DES_CBC_SHA:
+ cipher = "ADH-DES-SHA";
+ break;
+ case TLS_DH_anon_WITH_3DES_EDE_CBC_SHA:
+ cipher = "ADH-DES-CBC3-SHA";
+ break;
+ case TLS_RSA_WITH_AES_128_CBC_SHA:
+ cipher = "AES-128-SHA";
+ break;
+ case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+ cipher = "DHE-RSA-AES-128-SHA";
break;
case TLS_DH_anon_WITH_AES_128_CBC_SHA:
cipher = "ADH-AES-128-SHA";
@@ -579,15 +597,30 @@
case TLS_RSA_WITH_AES_256_CBC_SHA:
cipher = "AES-256-SHA";
break;
- case TLS_RSA_WITH_AES_256_CBC_SHA256:
- cipher = "AES-256-SHA256";
+ case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+ cipher = "DHE-RSA-AES-256-SHA";
break;
- case TLS_RSA_WITH_AES_128_CBC_SHA:
- cipher = "AES-128-SHA";
+ case TLS_DH_anon_WITH_AES_256_CBC_SHA:
+ cipher = "ADH-AES-256-SHA";
break;
case TLS_RSA_WITH_AES_128_CBC_SHA256:
cipher = "AES-128-SHA256";
break;
+ case TLS_RSA_WITH_AES_256_CBC_SHA256:
+ cipher = "AES-256-SHA256";
+ break;
+ case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+ cipher = "DHE-RSA-AES-128-SHA256";
+ break;
+ case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+ cipher = "DHE-RSA-AES-256-SHA256";
+ break;
+ case TLS_DH_anon_WITH_AES_128_CBC_SHA256:
+ cipher = "ADH-AES-128-SHA256";
+ break;
+ case TLS_DH_anon_WITH_AES_256_CBC_SHA256:
+ cipher = "ADH-AES-256-SHA256";
+ break;
default:
return -1;
}
diff --git a/src/tls/tlsv1_client_read.c b/src/tls/tlsv1_client_read.c
index 4f08e0f..9ce9680 100644
--- a/src/tls/tlsv1_client_read.c
+++ b/src/tls/tlsv1_client_read.c
@@ -440,6 +440,7 @@
const u8 *pos, *end, *server_params, *server_params_end;
u8 alert;
unsigned int bits;
+ u16 val;
tlsv1_client_free_dh(conn);
@@ -449,13 +450,13 @@
if (end - pos < 3)
goto fail;
server_params = pos;
- conn->dh_p_len = WPA_GET_BE16(pos);
+ val = WPA_GET_BE16(pos);
pos += 2;
- if (conn->dh_p_len == 0 || end - pos < (int) conn->dh_p_len) {
- wpa_printf(MSG_DEBUG, "TLSv1: Invalid dh_p length %lu",
- (unsigned long) conn->dh_p_len);
+ if (val == 0 || val > (size_t) (end - pos)) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Invalid dh_p length %u", val);
goto fail;
}
+ conn->dh_p_len = val;
bits = count_bits(pos, conn->dh_p_len);
if (bits < 768) {
wpa_printf(MSG_INFO, "TLSv1: Reject under 768-bit DH prime (insecure; only %u bits)",
@@ -474,10 +475,11 @@
if (end - pos < 3)
goto fail;
- conn->dh_g_len = WPA_GET_BE16(pos);
+ val = WPA_GET_BE16(pos);
pos += 2;
- if (conn->dh_g_len == 0 || end - pos < (int) conn->dh_g_len)
+ if (val == 0 || val > (size_t) (end - pos))
goto fail;
+ conn->dh_g_len = val;
conn->dh_g = os_malloc(conn->dh_g_len);
if (conn->dh_g == NULL)
goto fail;
@@ -490,10 +492,11 @@
if (end - pos < 3)
goto fail;
- conn->dh_ys_len = WPA_GET_BE16(pos);
+ val = WPA_GET_BE16(pos);
pos += 2;
- if (conn->dh_ys_len == 0 || end - pos < (int) conn->dh_ys_len)
+ if (val == 0 || val > (size_t) (end - pos))
goto fail;
+ conn->dh_ys_len = val;
conn->dh_ys = os_malloc(conn->dh_ys_len);
if (conn->dh_ys == NULL)
goto fail;
diff --git a/src/tls/tlsv1_server.c b/src/tls/tlsv1_server.c
index 23d0b81..93ae488 100644
--- a/src/tls/tlsv1_server.c
+++ b/src/tls/tlsv1_server.c
@@ -516,14 +516,56 @@
case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
cipher = "DES-CBC3-SHA";
break;
+ case TLS_DHE_RSA_WITH_DES_CBC_SHA:
+ cipher = "DHE-RSA-DES-CBC-SHA";
+ break;
+ case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ cipher = "DHE-RSA-DES-CBC3-SHA";
+ break;
+ case TLS_DH_anon_WITH_RC4_128_MD5:
+ cipher = "ADH-RC4-MD5";
+ break;
+ case TLS_DH_anon_WITH_DES_CBC_SHA:
+ cipher = "ADH-DES-SHA";
+ break;
+ case TLS_DH_anon_WITH_3DES_EDE_CBC_SHA:
+ cipher = "ADH-DES-CBC3-SHA";
+ break;
+ case TLS_RSA_WITH_AES_128_CBC_SHA:
+ cipher = "AES-128-SHA";
+ break;
+ case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+ cipher = "DHE-RSA-AES-128-SHA";
+ break;
case TLS_DH_anon_WITH_AES_128_CBC_SHA:
cipher = "ADH-AES-128-SHA";
break;
case TLS_RSA_WITH_AES_256_CBC_SHA:
cipher = "AES-256-SHA";
break;
- case TLS_RSA_WITH_AES_128_CBC_SHA:
- cipher = "AES-128-SHA";
+ case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+ cipher = "DHE-RSA-AES-256-SHA";
+ break;
+ case TLS_DH_anon_WITH_AES_256_CBC_SHA:
+ cipher = "ADH-AES-256-SHA";
+ break;
+ case TLS_RSA_WITH_AES_128_CBC_SHA256:
+ cipher = "AES-128-SHA256";
+ break;
+ case TLS_RSA_WITH_AES_256_CBC_SHA256:
+ cipher = "AES-256-SHA256";
+ break;
+ case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+ cipher = "DHE-RSA-AES-128-SHA256";
+ break;
+ case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+ cipher = "DHE-RSA-AES-256-SHA256";
+ break;
+ case TLS_DH_anon_WITH_AES_128_CBC_SHA256:
+ cipher = "ADH-AES-128-SHA256";
+ break;
+ case TLS_DH_anon_WITH_AES_256_CBC_SHA256:
+ cipher = "ADH-AES-256-SHA256";
break;
default:
return -1;
diff --git a/src/tls/tlsv1_server_read.c b/src/tls/tlsv1_server_read.c
index 728e137..310966c 100644
--- a/src/tls/tlsv1_server_read.c
+++ b/src/tls/tlsv1_server_read.c
@@ -626,7 +626,7 @@
dh_yc_len = WPA_GET_BE16(pos);
dh_yc = pos + 2;
- if (dh_yc + dh_yc_len > end) {
+ if (dh_yc_len > end - dh_yc) {
tlsv1_server_log(conn, "Client public value overflow (length %d)",
dh_yc_len);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
diff --git a/src/tls/x509v3.c b/src/tls/x509v3.c
index e1e4df8..742af32 100644
--- a/src/tls/x509v3.c
+++ b/src/tls/x509v3.c
@@ -512,7 +512,7 @@
ret = os_snprintf(pos, end - pos, "%s=%s, ",
x509_name_attr_str(name->attr[i].type),
name->attr[i].value);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
goto done;
pos += ret;
}
@@ -527,7 +527,7 @@
if (name->email) {
ret = os_snprintf(pos, end - pos, "/emailAddress=%s",
name->email);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
goto done;
pos += ret;
}
diff --git a/src/utils/base64.c b/src/utils/base64.c
index af1307f..d44f290 100644
--- a/src/utils/base64.c
+++ b/src/utils/base64.c
@@ -48,9 +48,11 @@
pos = out;
line_len = 0;
while (end - in >= 3) {
- *pos++ = base64_table[in[0] >> 2];
- *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
- *pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)];
+ *pos++ = base64_table[(in[0] >> 2) & 0x3f];
+ *pos++ = base64_table[(((in[0] & 0x03) << 4) |
+ (in[1] >> 4)) & 0x3f];
+ *pos++ = base64_table[(((in[1] & 0x0f) << 2) |
+ (in[2] >> 6)) & 0x3f];
*pos++ = base64_table[in[2] & 0x3f];
in += 3;
line_len += 4;
@@ -61,14 +63,14 @@
}
if (end - in) {
- *pos++ = base64_table[in[0] >> 2];
+ *pos++ = base64_table[(in[0] >> 2) & 0x3f];
if (end - in == 1) {
- *pos++ = base64_table[(in[0] & 0x03) << 4];
+ *pos++ = base64_table[((in[0] & 0x03) << 4) & 0x3f];
*pos++ = '=';
} else {
- *pos++ = base64_table[((in[0] & 0x03) << 4) |
- (in[1] >> 4)];
- *pos++ = base64_table[(in[1] & 0x0f) << 2];
+ *pos++ = base64_table[(((in[0] & 0x03) << 4) |
+ (in[1] >> 4)) & 0x3f];
+ *pos++ = base64_table[((in[1] & 0x0f) << 2) & 0x3f];
}
*pos++ = '=';
line_len += 4;
diff --git a/src/utils/browser-android.c b/src/utils/browser-android.c
index d5ff5b5..9ce1a5c 100644
--- a/src/utils/browser-android.c
+++ b/src/utils/browser-android.c
@@ -64,24 +64,15 @@
int hs20_web_browser(const char *url)
{
- char cmd[2000];
- int ret;
struct http_server *http;
struct in_addr addr;
struct browser_data data;
+ pid_t pid;
wpa_printf(MSG_INFO, "Launching Android browser to %s", url);
os_memset(&data, 0, sizeof(data));
- ret = os_snprintf(cmd, sizeof(cmd),
- "start -a android.intent.action.VIEW -d %s "
- "-n com.android.browser/.BrowserActivity", url);
- if (ret < 0 || (size_t) ret >= sizeof(cmd)) {
- wpa_printf(MSG_ERROR, "Too long URL");
- return -1;
- }
-
if (eloop_init() < 0) {
wpa_printf(MSG_ERROR, "eloop_init failed");
return -1;
@@ -94,14 +85,34 @@
return -1;
}
- if (os_exec("/system/bin/am", cmd, 1) != 0) {
- wpa_printf(MSG_INFO, "Failed to launch Android browser");
- eloop_cancel_timeout(browser_timeout, NULL, NULL);
+ pid = fork();
+ if (pid < 0) {
+ wpa_printf(MSG_ERROR, "fork: %s", strerror(errno));
http_server_deinit(http);
eloop_destroy();
return -1;
}
+ if (pid == 0) {
+ /* run the external command in the child process */
+ char *argv[9];
+
+ argv[0] = "browser-android";
+ argv[1] = "start";
+ argv[2] = "-a";
+ argv[3] = "android.intent.action.VIEW";
+ argv[4] = "-d";
+ argv[5] = (void *) url;
+ argv[6] = "-n";
+ argv[7] = "com.android.browser/.BrowserActivity";
+ argv[8] = NULL;
+
+ execv("/system/bin/am", argv);
+ wpa_printf(MSG_ERROR, "execv: %s", strerror(errno));
+ exit(0);
+ return -1;
+ }
+
eloop_register_timeout(30, 0, browser_timeout, &data, NULL);
eloop_run();
eloop_cancel_timeout(browser_timeout, &data, NULL);
@@ -109,7 +120,7 @@
eloop_destroy();
wpa_printf(MSG_INFO, "Closing Android browser");
- if (os_exec("/system/bin/input", "keyevent 3", 1) != 0) {
+ if (system("/system/bin/input keyevent KEYCODE_HOME") != 0) {
wpa_printf(MSG_INFO, "Failed to inject keyevent");
}
diff --git a/src/utils/browser-system.c b/src/utils/browser-system.c
index a080e2c..aed3970 100644
--- a/src/utils/browser-system.c
+++ b/src/utils/browser-system.c
@@ -64,22 +64,15 @@
int hs20_web_browser(const char *url)
{
- char cmd[2000];
- int ret;
struct http_server *http;
struct in_addr addr;
struct browser_data data;
+ pid_t pid;
- wpa_printf(MSG_INFO, "Launching Android browser to %s", url);
+ wpa_printf(MSG_INFO, "Launching system browser to %s", url);
os_memset(&data, 0, sizeof(data));
- ret = os_snprintf(cmd, sizeof(cmd), "x-www-browser '%s' &", url);
- if (ret < 0 || (size_t) ret >= sizeof(cmd)) {
- wpa_printf(MSG_ERROR, "Too long URL");
- return -1;
- }
-
if (eloop_init() < 0) {
wpa_printf(MSG_ERROR, "eloop_init failed");
return -1;
@@ -92,14 +85,28 @@
return -1;
}
- if (os_exec("/usr/bin/x-www-browser", url, 0) != 0) {
- wpa_printf(MSG_INFO, "Failed to launch browser");
- eloop_cancel_timeout(browser_timeout, NULL, NULL);
+ pid = fork();
+ if (pid < 0) {
+ wpa_printf(MSG_ERROR, "fork: %s", strerror(errno));
http_server_deinit(http);
eloop_destroy();
return -1;
}
+ if (pid == 0) {
+ /* run the external command in the child process */
+ char *argv[3];
+
+ argv[0] = "browser-system";
+ argv[1] = (void *) url;
+ argv[2] = NULL;
+
+ execv("/usr/bin/x-www-browser", argv);
+ wpa_printf(MSG_ERROR, "execv: %s", strerror(errno));
+ exit(0);
+ return -1;
+ }
+
eloop_register_timeout(120, 0, browser_timeout, &data, NULL);
eloop_run();
eloop_cancel_timeout(browser_timeout, &data, NULL);
diff --git a/src/utils/browser-wpadebug.c b/src/utils/browser-wpadebug.c
index ce3054b..5fc40fa 100644
--- a/src/utils/browser-wpadebug.c
+++ b/src/utils/browser-wpadebug.c
@@ -65,26 +65,15 @@
int hs20_web_browser(const char *url)
{
- char cmd[2000];
- int ret;
struct http_server *http;
struct in_addr addr;
struct browser_data data;
+ pid_t pid;
wpa_printf(MSG_INFO, "Launching wpadebug browser to %s", url);
os_memset(&data, 0, sizeof(data));
- ret = os_snprintf(cmd, sizeof(cmd),
- "start -a android.action.MAIN "
- "-c android.intent.category.LAUNCHER "
- "-n w1.fi.wpadebug/.WpaWebViewActivity "
- "-e w1.fi.wpadebug.URL '%s'", url);
- if (ret < 0 || (size_t) ret >= sizeof(cmd)) {
- wpa_printf(MSG_ERROR, "Too long URL");
- return -1;
- }
-
if (eloop_init() < 0) {
wpa_printf(MSG_ERROR, "eloop_init failed");
return -1;
@@ -97,14 +86,37 @@
return -1;
}
- if (os_exec("/system/bin/am", cmd, 1) != 0) {
- wpa_printf(MSG_INFO, "Failed to launch wpadebug browser");
- eloop_cancel_timeout(browser_timeout, NULL, NULL);
+ pid = fork();
+ if (pid < 0) {
+ wpa_printf(MSG_ERROR, "fork: %s", strerror(errno));
http_server_deinit(http);
eloop_destroy();
return -1;
}
+ if (pid == 0) {
+ /* run the external command in the child process */
+ char *argv[12];
+
+ argv[0] = "browser-wpadebug";
+ argv[1] = "start";
+ argv[2] = "-a";
+ argv[3] = "android.action.MAIN";
+ argv[4] = "-c";
+ argv[5] = "android.intent.category.LAUNCHER";
+ argv[6] = "-n";
+ argv[7] = "w1.fi.wpadebug/.WpaWebViewActivity";
+ argv[8] = "-e";
+ argv[9] = "w1.fi.wpadebug.URL";
+ argv[10] = (void *) url;
+ argv[11] = NULL;
+
+ execv("/system/bin/am", argv);
+ wpa_printf(MSG_ERROR, "execv: %s", strerror(errno));
+ exit(0);
+ return -1;
+ }
+
eloop_register_timeout(300, 0, browser_timeout, &data, NULL);
eloop_run();
eloop_cancel_timeout(browser_timeout, &data, NULL);
diff --git a/src/utils/common.c b/src/utils/common.c
index 9902004..93f1722 100644
--- a/src/utils/common.c
+++ b/src/utils/common.c
@@ -36,6 +36,25 @@
}
+static const char * hwaddr_parse(const char *txt, u8 *addr)
+{
+ size_t i;
+
+ for (i = 0; i < ETH_ALEN; i++) {
+ int a;
+
+ a = hex2byte(txt);
+ if (a < 0)
+ return NULL;
+ txt += 2;
+ addr[i] = a;
+ if (i < ETH_ALEN - 1 && *txt++ != ':')
+ return NULL;
+ }
+ return txt;
+}
+
+
/**
* hwaddr_aton - Convert ASCII string to MAC address (colon-delimited format)
* @txt: MAC address as a string (e.g., "00:11:22:33:44:55")
@@ -44,25 +63,46 @@
*/
int hwaddr_aton(const char *txt, u8 *addr)
{
- int i;
+ return hwaddr_parse(txt, addr) ? 0 : -1;
+}
- for (i = 0; i < 6; i++) {
- int a, b;
- a = hex2num(*txt++);
- if (a < 0)
+/**
+ * hwaddr_masked_aton - Convert ASCII string with optional mask to MAC address (colon-delimited format)
+ * @txt: MAC address with optional mask as a string (e.g., "00:11:22:33:44:55/ff:ff:ff:ff:00:00")
+ * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
+ * @mask: Buffer for the MAC address mask (ETH_ALEN = 6 bytes)
+ * @maskable: Flag to indicate whether a mask is allowed
+ * Returns: 0 on success, -1 on failure (e.g., string not a MAC address)
+ */
+int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable)
+{
+ const char *r;
+
+ /* parse address part */
+ r = hwaddr_parse(txt, addr);
+ if (!r)
+ return -1;
+
+ /* check for optional mask */
+ if (*r == '\0' || isspace(*r)) {
+ /* no mask specified, assume default */
+ os_memset(mask, 0xff, ETH_ALEN);
+ } else if (maskable && *r == '/') {
+ /* mask specified and allowed */
+ r = hwaddr_parse(r + 1, mask);
+ /* parser error? */
+ if (!r)
return -1;
- b = hex2num(*txt++);
- if (b < 0)
- return -1;
- *addr++ = (a << 4) | b;
- if (i < 5 && *txt++ != ':')
- return -1;
+ } else {
+ /* mask specified but not allowed or trailing garbage */
+ return -1;
}
return 0;
}
+
/**
* hwaddr_compact_aton - Convert ASCII string to MAC address (no colon delimitors format)
* @txt: MAC address as a string (e.g., "001122334455")
@@ -144,6 +184,30 @@
}
+int hwaddr_mask_txt(char *buf, size_t len, const u8 *addr, const u8 *mask)
+{
+ size_t i;
+ int print_mask = 0;
+ int res;
+
+ for (i = 0; i < ETH_ALEN; i++) {
+ if (mask[i] != 0xff) {
+ print_mask = 1;
+ break;
+ }
+ }
+
+ if (print_mask)
+ res = os_snprintf(buf, len, MACSTR "/" MACSTR,
+ MAC2STR(addr), MAC2STR(mask));
+ else
+ res = os_snprintf(buf, len, MACSTR, MAC2STR(addr));
+ if (os_snprintf_error(len, res))
+ return -1;
+ return res;
+}
+
+
/**
* inc_byte_array - Increment arbitrary length byte array by one
* @counter: Pointer to byte array
@@ -183,6 +247,35 @@
os_memcpy(buf + 4, (u8 *) &tmp, 4);
}
+/**
+ * wpa_scnprintf - Simpler-to-use snprintf function
+ * @buf: Output buffer
+ * @size: Buffer size
+ * @fmt: format
+ *
+ * Simpler snprintf version that doesn't require further error checks - the
+ * return value only indicates how many bytes were actually written, excluding
+ * the NULL byte (i.e., 0 on error, size-1 if buffer is not big enough).
+ */
+int wpa_scnprintf(char *buf, size_t size, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ if (!size)
+ return 0;
+
+ va_start(ap, fmt);
+ ret = vsnprintf(buf, size, fmt, ap);
+ va_end(ap);
+
+ if (ret < 0)
+ return 0;
+ if ((size_t) ret >= size)
+ return size - 1;
+
+ return ret;
+}
static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data,
size_t len, int uppercase)
@@ -195,7 +288,7 @@
for (i = 0; i < len; i++) {
ret = os_snprintf(pos, end - pos, uppercase ? "%02X" : "%02x",
data[i]);
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
end[-1] = '\0';
return pos - buf;
}
@@ -578,21 +671,6 @@
}
-int find_first_bit(u32 value)
-{
- int pos = 0;
-
- while (value) {
- if (value & 0x1)
- return pos;
- value >>= 1;
- pos++;
- }
-
- return -1;
-}
-
-
size_t merge_byte_arrays(u8 *res, size_t res_len,
const u8 *src1, size_t src1_len,
const u8 *src2, size_t src2_len)
@@ -726,7 +804,7 @@
res = os_snprintf(pos, end - pos, "%s%u-%u",
i == 0 ? "" : ",",
range->min, range->max);
- if (res < 0 || res > end - pos) {
+ if (os_snprintf_error(end - pos, res)) {
os_free(buf);
return NULL;
}
@@ -866,3 +944,35 @@
addr[0] |= 0x02; /* locally administered */
return 0;
}
+
+
+/**
+ * str_token - Get next token from a string
+ * @buf: String to tokenize. Note that the string might be modified.
+ * @delim: String of delimiters
+ * @context: Pointer to save our context. Should be initialized with
+ * NULL on the first call, and passed for any further call.
+ * Returns: The next token, NULL if there are no more valid tokens.
+ */
+char * str_token(char *str, const char *delim, char **context)
+{
+ char *end, *pos = str;
+
+ if (*context)
+ pos = *context;
+
+ while (*pos && os_strchr(delim, *pos))
+ pos++;
+ if (!*pos)
+ return NULL;
+
+ end = pos + 1;
+ while (*end && !os_strchr(delim, *end))
+ end++;
+
+ if (*end)
+ *end++ = '\0';
+
+ *context = end;
+ return pos;
+}
diff --git a/src/utils/common.h b/src/utils/common.h
index 14d9ad1..82a51e5 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -164,6 +164,7 @@
#define be_to_host16(n) wpa_swap_16(n)
#define host_to_be16(n) wpa_swap_16(n)
#define le_to_host32(n) (n)
+#define host_to_le32(n) (n)
#define be_to_host32(n) wpa_swap_32(n)
#define host_to_be32(n) wpa_swap_32(n)
@@ -329,6 +330,9 @@
#ifndef ETH_ALEN
#define ETH_ALEN 6
#endif
+#ifndef ETH_HLEN
+#define ETH_HLEN 14
+#endif
#ifndef IFNAMSIZ
#define IFNAMSIZ 16
#endif
@@ -468,16 +472,20 @@
#endif /* __must_check */
int hwaddr_aton(const char *txt, u8 *addr);
+int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable);
int hwaddr_compact_aton(const char *txt, u8 *addr);
int hwaddr_aton2(const char *txt, u8 *addr);
int hex2byte(const char *hex);
int hexstr2bin(const char *hex, u8 *buf, size_t len);
void inc_byte_array(u8 *counter, size_t len);
void wpa_get_ntp_timestamp(u8 *buf);
+int wpa_scnprintf(char *buf, size_t size, const char *fmt, ...);
int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len);
int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data,
size_t len);
+int hwaddr_mask_txt(char *buf, size_t len, const u8 *addr, const u8 *mask);
+
#ifdef CONFIG_NATIVE_WINDOWS
void wpa_unicode2ascii_inplace(TCHAR *str);
TCHAR * wpa_strdup_tchar(const char *str);
@@ -493,7 +501,6 @@
char * wpa_config_parse_string(const char *value, size_t *len);
int is_hex(const u8 *data, size_t len);
-int find_first_bit(u32 value);
size_t merge_byte_arrays(u8 *res, size_t res_len,
const u8 *src1, size_t src1_len,
const u8 *src2, size_t src2_len);
@@ -534,13 +541,14 @@
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
-
void str_clear_free(char *str);
void bin_clear_free(void *bin, size_t len);
int random_mac_addr(u8 *addr);
int random_mac_addr_keep_oui(u8 *addr);
+char * str_token(char *str, const char *delim, char **context);
+
/*
* gcc 4.4 ends up generating strict-aliasing warnings about some very common
diff --git a/src/utils/eloop.c b/src/utils/eloop.c
index 0da6de4..4a565eb 100644
--- a/src/utils/eloop.c
+++ b/src/utils/eloop.c
@@ -242,8 +242,10 @@
eloop_trace_sock_remove_ref(table);
tmp = os_realloc_array(table->table, table->count + 1,
sizeof(struct eloop_sock));
- if (tmp == NULL)
+ if (tmp == NULL) {
+ eloop_trace_sock_add_ref(table);
return -1;
+ }
tmp[table->count].sock = sock;
tmp[table->count].eloop_data = eloop_data;
diff --git a/src/utils/os.h b/src/utils/os.h
index b9247d8..77250d6 100644
--- a/src/utils/os.h
+++ b/src/utils/os.h
@@ -549,6 +549,12 @@
#endif /* OS_NO_C_LIB_DEFINES */
+static inline int os_snprintf_error(size_t size, int res)
+{
+ return res < 0 || (unsigned int) res >= size;
+}
+
+
static inline void * os_realloc_array(void *ptr, size_t nmemb, size_t size)
{
if (size && nmemb > (~(size_t) 0) / size)
diff --git a/src/utils/os_internal.c b/src/utils/os_internal.c
index 90b6688..77733ad 100644
--- a/src/utils/os_internal.c
+++ b/src/utils/os_internal.c
@@ -17,9 +17,11 @@
*/
#include "includes.h"
+#include <time.h>
+#include <sys/wait.h>
#undef OS_REJECT_C_LIB_FUNCTIONS
-#include "os.h"
+#include "common.h"
void os_sleep(os_time_t sec, os_time_t usec)
{
@@ -96,7 +98,7 @@
int os_daemonize(const char *pid_file)
{
if (daemon(0, 0)) {
- perror("daemon");
+ wpa_printf(MSG_ERROR, "daemon: %s", strerror(errno));
return -1;
}
@@ -167,8 +169,8 @@
}
}
- cwd_len = strlen(cwd);
- rel_len = strlen(rel_path);
+ cwd_len = os_strlen(cwd);
+ rel_len = os_strlen(rel_path);
ret_len = cwd_len + 1 + rel_len + 1;
ret = os_malloc(ret_len);
if (ret) {
@@ -506,3 +508,57 @@
str[size - 1] = '\0';
return ret;
}
+
+
+int os_exec(const char *program, const char *arg, int wait_completion)
+{
+ pid_t pid;
+ int pid_status;
+
+ pid = fork();
+ if (pid < 0) {
+ wpa_printf(MSG_ERROR, "fork: %s", strerror(errno));
+ return -1;
+ }
+
+ if (pid == 0) {
+ /* run the external command in the child process */
+ const int MAX_ARG = 30;
+ char *_program, *_arg, *pos;
+ char *argv[MAX_ARG + 1];
+ int i;
+
+ _program = os_strdup(program);
+ _arg = os_strdup(arg);
+
+ argv[0] = _program;
+
+ i = 1;
+ pos = _arg;
+ while (i < MAX_ARG && pos && *pos) {
+ while (*pos == ' ')
+ pos++;
+ if (*pos == '\0')
+ break;
+ argv[i++] = pos;
+ pos = os_strchr(pos, ' ');
+ if (pos)
+ *pos++ = '\0';
+ }
+ argv[i] = NULL;
+
+ execv(program, argv);
+ wpa_printf(MSG_ERROR, "execv: %s", strerror(errno));
+ os_free(_program);
+ os_free(_arg);
+ exit(0);
+ return -1;
+ }
+
+ if (wait_completion) {
+ /* wait for the child process to complete in the parent */
+ waitpid(pid, &pid_status, 0);
+ }
+
+ return 0;
+}
diff --git a/src/utils/os_none.c b/src/utils/os_none.c
index 2649111..83fe025 100644
--- a/src/utils/os_none.c
+++ b/src/utils/os_none.c
@@ -234,3 +234,9 @@
return 0;
}
#endif /* OS_NO_C_LIB_DEFINES */
+
+
+int os_exec(const char *program, const char *arg, int wait_completion)
+{
+ return -1;
+}
diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c
index 523a4d0..86fbd0a 100644
--- a/src/utils/os_unix.c
+++ b/src/utils/os_unix.c
@@ -467,9 +467,105 @@
#ifdef WPA_TRACE
+#if defined(WPA_TRACE_BFD) && defined(CONFIG_TESTING_OPTIONS)
+char wpa_trace_fail_func[256] = { 0 };
+unsigned int wpa_trace_fail_after;
+
+static int testing_fail_alloc(void)
+{
+ const char *func[WPA_TRACE_LEN];
+ size_t i, res, len;
+ char *pos, *next;
+ int match;
+
+ if (!wpa_trace_fail_after)
+ return 0;
+
+ res = wpa_trace_calling_func(func, WPA_TRACE_LEN);
+ i = 0;
+ if (i < res && os_strcmp(func[i], __func__) == 0)
+ i++;
+ if (i < res && os_strcmp(func[i], "os_malloc") == 0)
+ i++;
+ if (i < res && os_strcmp(func[i], "os_zalloc") == 0)
+ i++;
+ if (i < res && os_strcmp(func[i], "os_calloc") == 0)
+ i++;
+ if (i < res && os_strcmp(func[i], "os_realloc") == 0)
+ i++;
+ if (i < res && os_strcmp(func[i], "os_realloc_array") == 0)
+ i++;
+ if (i < res && os_strcmp(func[i], "os_strdup") == 0)
+ i++;
+
+ pos = wpa_trace_fail_func;
+
+ match = 0;
+ while (i < res) {
+ int allow_skip = 1;
+ int maybe = 0;
+
+ if (*pos == '=') {
+ allow_skip = 0;
+ pos++;
+ } else if (*pos == '?') {
+ maybe = 1;
+ pos++;
+ }
+ next = os_strchr(pos, ';');
+ if (next)
+ len = next - pos;
+ else
+ len = os_strlen(pos);
+ if (os_memcmp(pos, func[i], len) != 0) {
+ if (maybe && next) {
+ pos = next + 1;
+ continue;
+ }
+ if (allow_skip) {
+ i++;
+ continue;
+ }
+ return 0;
+ }
+ if (!next) {
+ match = 1;
+ break;
+ }
+ pos = next + 1;
+ i++;
+ }
+ if (!match)
+ return 0;
+
+ wpa_trace_fail_after--;
+ if (wpa_trace_fail_after == 0) {
+ wpa_printf(MSG_INFO, "TESTING: fail allocation at %s",
+ wpa_trace_fail_func);
+ for (i = 0; i < res; i++)
+ wpa_printf(MSG_INFO, "backtrace[%d] = %s",
+ (int) i, func[i]);
+ return 1;
+ }
+
+ return 0;
+}
+
+#else
+
+static inline int testing_fail_alloc(void)
+{
+ return 0;
+}
+#endif
+
void * os_malloc(size_t size)
{
struct os_alloc_trace *a;
+
+ if (testing_fail_alloc())
+ return NULL;
+
a = malloc(sizeof(*a) + size);
if (a == NULL)
return NULL;
diff --git a/src/utils/os_win32.c b/src/utils/os_win32.c
index 57ee132..296ea13 100644
--- a/src/utils/os_win32.c
+++ b/src/utils/os_win32.c
@@ -12,6 +12,7 @@
#include <wincrypt.h>
#include "os.h"
+#include "common.h"
void os_sleep(os_time_t sec, os_time_t usec)
{
diff --git a/src/utils/pcsc_funcs.c b/src/utils/pcsc_funcs.c
index d955dc4..6f5ea93 100644
--- a/src/utils/pcsc_funcs.c
+++ b/src/utils/pcsc_funcs.c
@@ -281,77 +281,82 @@
wpa_hexdump(MSG_DEBUG, "SCARD: file header FSP template",
pos, end - pos);
- while (pos + 1 < end) {
+ while (end - pos >= 2) {
+ unsigned char type, len;
+
+ type = pos[0];
+ len = pos[1];
wpa_printf(MSG_MSGDUMP, "SCARD: file header TLV 0x%02x len=%d",
- pos[0], pos[1]);
- if (pos + 2 + pos[1] > end)
+ type, len);
+ pos += 2;
+
+ if (len > (unsigned int) (end - pos))
break;
- switch (pos[0]) {
+ switch (type) {
case USIM_TLV_FILE_DESC:
wpa_hexdump(MSG_MSGDUMP, "SCARD: File Descriptor TLV",
- pos + 2, pos[1]);
+ pos, len);
break;
case USIM_TLV_FILE_ID:
wpa_hexdump(MSG_MSGDUMP, "SCARD: File Identifier TLV",
- pos + 2, pos[1]);
+ pos, len);
break;
case USIM_TLV_DF_NAME:
wpa_hexdump(MSG_MSGDUMP, "SCARD: DF name (AID) TLV",
- pos + 2, pos[1]);
+ pos, len);
break;
case USIM_TLV_PROPR_INFO:
wpa_hexdump(MSG_MSGDUMP, "SCARD: Proprietary "
- "information TLV", pos + 2, pos[1]);
+ "information TLV", pos, len);
break;
case USIM_TLV_LIFE_CYCLE_STATUS:
wpa_hexdump(MSG_MSGDUMP, "SCARD: Life Cycle Status "
- "Integer TLV", pos + 2, pos[1]);
+ "Integer TLV", pos, len);
break;
case USIM_TLV_FILE_SIZE:
wpa_hexdump(MSG_MSGDUMP, "SCARD: File size TLV",
- pos + 2, pos[1]);
- if ((pos[1] == 1 || pos[1] == 2) && file_len) {
- if (pos[1] == 1)
- *file_len = (int) pos[2];
+ pos, len);
+ if ((len == 1 || len == 2) && file_len) {
+ if (len == 1)
+ *file_len = (int) pos[0];
else
- *file_len = ((int) pos[2] << 8) |
- (int) pos[3];
+ *file_len = WPA_GET_BE16(pos);
wpa_printf(MSG_DEBUG, "SCARD: file_size=%d",
*file_len);
}
break;
case USIM_TLV_TOTAL_FILE_SIZE:
wpa_hexdump(MSG_MSGDUMP, "SCARD: Total file size TLV",
- pos + 2, pos[1]);
+ pos, len);
break;
case USIM_TLV_PIN_STATUS_TEMPLATE:
wpa_hexdump(MSG_MSGDUMP, "SCARD: PIN Status Template "
- "DO TLV", pos + 2, pos[1]);
- if (pos[1] >= 2 && pos[2] == USIM_PS_DO_TAG &&
- pos[3] >= 1 && ps_do) {
+ "DO TLV", pos, len);
+ if (len >= 2 && pos[0] == USIM_PS_DO_TAG &&
+ pos[1] >= 1 && ps_do) {
wpa_printf(MSG_DEBUG, "SCARD: PS_DO=0x%02x",
- pos[4]);
- *ps_do = (int) pos[4];
+ pos[2]);
+ *ps_do = (int) pos[2];
}
break;
case USIM_TLV_SHORT_FILE_ID:
wpa_hexdump(MSG_MSGDUMP, "SCARD: Short File "
- "Identifier (SFI) TLV", pos + 2, pos[1]);
+ "Identifier (SFI) TLV", pos, len);
break;
case USIM_TLV_SECURITY_ATTR_8B:
case USIM_TLV_SECURITY_ATTR_8C:
case USIM_TLV_SECURITY_ATTR_AB:
wpa_hexdump(MSG_MSGDUMP, "SCARD: Security attribute "
- "TLV", pos + 2, pos[1]);
+ "TLV", pos, len);
break;
default:
wpa_hexdump(MSG_MSGDUMP, "SCARD: Unrecognized TLV",
- pos, 2 + pos[1]);
+ pos, len);
break;
}
- pos += 2 + pos[1];
+ pos += len;
if (pos == end)
return 0;
@@ -397,10 +402,12 @@
unsigned char rid[5];
unsigned char appl_code[2]; /* 0x1002 for 3G USIM */
} *efdir;
- unsigned char buf[127];
+ unsigned char buf[127], *aid_pos;
size_t blen;
+ unsigned int aid_len = 0;
efdir = (struct efdir *) buf;
+ aid_pos = &buf[4];
blen = sizeof(buf);
if (scard_select_file(scard, SCARD_FILE_EF_DIR, buf, &blen)) {
wpa_printf(MSG_DEBUG, "SCARD: Failed to read EF_DIR");
@@ -449,14 +456,15 @@
continue;
}
- if (efdir->aid_len < 1 || efdir->aid_len > 16) {
- wpa_printf(MSG_DEBUG, "SCARD: Invalid AID length %d",
- efdir->aid_len);
+ aid_len = efdir->aid_len;
+ if (aid_len < 1 || aid_len > 16) {
+ wpa_printf(MSG_DEBUG, "SCARD: Invalid AID length %u",
+ aid_len);
continue;
}
wpa_hexdump(MSG_DEBUG, "SCARD: AID from EF_DIR record",
- efdir->rid, efdir->aid_len);
+ aid_pos, aid_len);
if (efdir->appl_code[0] == 0x10 &&
efdir->appl_code[1] == 0x02) {
@@ -472,14 +480,14 @@
return -1;
}
- if (efdir->aid_len > maxlen) {
+ if (aid_len > maxlen) {
wpa_printf(MSG_DEBUG, "SCARD: Too long AID");
return -1;
}
- os_memcpy(aid, efdir->rid, efdir->aid_len);
+ os_memcpy(aid, aid_pos, aid_len);
- return efdir->aid_len;
+ return aid_len;
}
@@ -1096,7 +1104,7 @@
}
if (scard->sim_type == SCARD_GSM_SIM) {
- blen = (buf[2] << 8) | buf[3];
+ blen = WPA_GET_BE16(&buf[2]);
} else {
int file_size;
if (scard_parse_fsp_templ(buf, blen, NULL, &file_size))
@@ -1170,7 +1178,7 @@
}
if (scard->sim_type == SCARD_GSM_SIM) {
- file_size = (buf[2] << 8) | buf[3];
+ file_size = WPA_GET_BE16(&buf[2]);
} else {
if (scard_parse_fsp_templ(buf, blen, NULL, &file_size))
return -3;
diff --git a/src/utils/radiotap.c b/src/utils/radiotap.c
index 197a4af..f8f815a 100644
--- a/src/utils/radiotap.c
+++ b/src/utils/radiotap.c
@@ -109,6 +109,7 @@
iterator->_arg_index = 0;
iterator->_bitmap_shifter = get_unaligned_le32(&radiotap_header->it_present);
iterator->_arg = (uint8_t *)radiotap_header + sizeof(*radiotap_header);
+ iterator->_next_ns_data = NULL;
iterator->_reset_on_ext = 0;
iterator->_next_bitmap = &radiotap_header->it_present;
iterator->_next_bitmap++;
@@ -154,6 +155,8 @@
}
iterator->this_arg = iterator->_arg;
+ iterator->this_arg_index = 0;
+ iterator->this_arg_size = 0;
/* we are all initialized happily */
diff --git a/src/utils/trace.c b/src/utils/trace.c
index 6044f5f..8484d27 100644
--- a/src/utils/trace.c
+++ b/src/utils/trace.c
@@ -33,7 +33,7 @@
os_snprintf(exe, sizeof(exe) - 1, "/proc/%u/exe", getpid());
len = readlink(exe, fname, sizeof(fname) - 1);
if (len < 0 || len >= (int) sizeof(fname)) {
- perror("readlink");
+ wpa_printf(MSG_ERROR, "readlink: %s", strerror(errno));
return;
}
fname[len] = '\0';
@@ -160,7 +160,7 @@
if (abfd == NULL)
return;
- data.pc = (bfd_vma) pc;
+ data.pc = (bfd_hostptr_t) pc;
data.found = FALSE;
bfd_map_over_sections(abfd, find_addr_sect, &data);
@@ -201,7 +201,7 @@
if (abfd == NULL)
return NULL;
- data.pc = (bfd_vma) pc;
+ data.pc = (bfd_hostptr_t) pc;
data.found = FALSE;
bfd_map_over_sections(abfd, find_addr_sect, &data);
@@ -243,6 +243,53 @@
wpa_trace_bfd_addr(pc);
}
+
+size_t wpa_trace_calling_func(const char *buf[], size_t len)
+{
+ bfd *abfd;
+ void *btrace_res[WPA_TRACE_LEN];
+ int i, btrace_num;
+ size_t pos = 0;
+
+ if (len == 0)
+ return 0;
+ if (len > WPA_TRACE_LEN)
+ len = WPA_TRACE_LEN;
+
+ wpa_trace_bfd_init();
+ abfd = cached_abfd;
+ if (!abfd)
+ return 0;
+
+ btrace_num = backtrace(btrace_res, len);
+ if (btrace_num < 1)
+ return 0;
+
+ for (i = 0; i < btrace_num; i++) {
+ struct bfd_data data;
+
+ data.pc = (bfd_hostptr_t) btrace_res[i];
+ data.found = FALSE;
+ bfd_map_over_sections(abfd, find_addr_sect, &data);
+
+ while (data.found) {
+ if (data.function &&
+ (pos > 0 ||
+ os_strcmp(data.function, __func__) != 0)) {
+ buf[pos++] = data.function;
+ if (pos == len)
+ return pos;
+ }
+
+ data.found = bfd_find_inliner_info(abfd, &data.filename,
+ &data.function,
+ &data.line);
+ }
+ }
+
+ return pos;
+}
+
#else /* WPA_TRACE_BFD */
#define wpa_trace_bfd_init() do { } while (0)
diff --git a/src/utils/trace.h b/src/utils/trace.h
index 38f43fb..43ed86c 100644
--- a/src/utils/trace.h
+++ b/src/utils/trace.h
@@ -40,6 +40,7 @@
dl_list_del(&(ptr)->wpa_trace_ref_##name.list); \
} while (0)
void wpa_trace_check_ref(const void *addr);
+size_t wpa_trace_calling_func(const char *buf[], size_t len);
#else /* WPA_TRACE */
diff --git a/src/utils/uuid.c b/src/utils/uuid.c
index 2aa4bcb..0f224f9 100644
--- a/src/utils/uuid.c
+++ b/src/utils/uuid.c
@@ -55,7 +55,7 @@
bin[4], bin[5], bin[6], bin[7],
bin[8], bin[9], bin[10], bin[11],
bin[12], bin[13], bin[14], bin[15]);
- if (len < 0 || (size_t) len >= max_len)
+ if (os_snprintf_error(max_len, len))
return -1;
return 0;
}
diff --git a/src/utils/wpa_debug.c b/src/utils/wpa_debug.c
index 68cbace..0d11905 100644
--- a/src/utils/wpa_debug.c
+++ b/src/utils/wpa_debug.c
@@ -555,6 +555,8 @@
#ifndef _WIN32
setvbuf(out_file, NULL, _IOLBF, 0);
#endif /* _WIN32 */
+#else /* CONFIG_DEBUG_FILE */
+ (void)path;
#endif /* CONFIG_DEBUG_FILE */
return 0;
}
@@ -572,6 +574,14 @@
#endif /* CONFIG_DEBUG_FILE */
}
+
+void wpa_debug_setup_stdout(void)
+{
+#ifndef _WIN32
+ setvbuf(stdout, NULL, _IOLBF, 0);
+#endif /* _WIN32 */
+}
+
#endif /* CONFIG_NO_STDOUT_DEBUG */
@@ -617,7 +627,7 @@
if (ifname) {
int res = os_snprintf(prefix, sizeof(prefix), "%s: ",
ifname);
- if (res < 0 || res >= (int) sizeof(prefix))
+ if (os_snprintf_error(sizeof(prefix), res))
prefix[0] = '\0';
}
}
diff --git a/src/utils/wpa_debug.h b/src/utils/wpa_debug.h
index 391f197..400bea9 100644
--- a/src/utils/wpa_debug.h
+++ b/src/utils/wpa_debug.h
@@ -34,6 +34,7 @@
#define wpa_hexdump_ascii_key(l,t,b,le) do { } while (0)
#define wpa_debug_open_file(p) do { } while (0)
#define wpa_debug_close_file() do { } while (0)
+#define wpa_debug_setup_stdout() do { } while (0)
#define wpa_dbg(args...) do { } while (0)
static inline int wpa_debug_reopen_file(void)
@@ -46,6 +47,7 @@
int wpa_debug_open_file(const char *path);
int wpa_debug_reopen_file(void);
void wpa_debug_close_file(void);
+void wpa_debug_setup_stdout(void);
/**
* wpa_debug_printf_timestamp - Print timestamp for debug output
diff --git a/src/utils/wpabuf.c b/src/utils/wpabuf.c
index b257b36..7aafa0a 100644
--- a/src/utils/wpabuf.c
+++ b/src/utils/wpabuf.c
@@ -205,6 +205,15 @@
}
+void wpabuf_clear_free(struct wpabuf *buf)
+{
+ if (buf) {
+ os_memset(wpabuf_mhead(buf), 0, wpabuf_len(buf));
+ wpabuf_free(buf);
+ }
+}
+
+
void * wpabuf_put(struct wpabuf *buf, size_t len)
{
void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf);
diff --git a/src/utils/wpabuf.h b/src/utils/wpabuf.h
index dbce925..c3ef1ba 100644
--- a/src/utils/wpabuf.h
+++ b/src/utils/wpabuf.h
@@ -32,6 +32,7 @@
struct wpabuf * wpabuf_alloc_copy(const void *data, size_t len);
struct wpabuf * wpabuf_dup(const struct wpabuf *src);
void wpabuf_free(struct wpabuf *buf);
+void wpabuf_clear_free(struct wpabuf *buf);
void * wpabuf_put(struct wpabuf *buf, size_t len);
struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b);
struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len);
diff --git a/src/wps/wps.c b/src/wps/wps.c
index b0f6887..2c68be8 100644
--- a/src/wps/wps.c
+++ b/src/wps/wps.c
@@ -560,7 +560,7 @@
"wps_state=configured\n");
else
ret = 0;
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -568,7 +568,7 @@
if (attr.ap_setup_locked && *attr.ap_setup_locked) {
ret = os_snprintf(pos, end - pos,
"wps_ap_setup_locked=1\n");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -576,7 +576,7 @@
if (attr.selected_registrar && *attr.selected_registrar) {
ret = os_snprintf(pos, end - pos,
"wps_selected_registrar=1\n");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -585,7 +585,7 @@
ret = os_snprintf(pos, end - pos,
"wps_device_password_id=%u\n",
WPA_GET_BE16(attr.dev_password_id));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -595,7 +595,7 @@
"wps_selected_registrar_config_methods="
"0x%04x\n",
WPA_GET_BE16(attr.sel_reg_config_methods));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -607,7 +607,7 @@
wps_dev_type_bin2str(attr.primary_dev_type,
devtype,
sizeof(devtype)));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -626,7 +626,7 @@
str[i] = '\0';
ret = os_snprintf(pos, end - pos, "wps_device_name=%s\n", str);
os_free(str);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -635,7 +635,7 @@
ret = os_snprintf(pos, end - pos,
"wps_config_methods=0x%04x\n",
WPA_GET_BE16(attr.config_methods));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
diff --git a/src/wps/wps.h b/src/wps/wps.h
index 192d283..0a7f65d 100644
--- a/src/wps/wps.h
+++ b/src/wps/wps.h
@@ -819,6 +819,7 @@
int wps_registrar_add_nfc_password_token(struct wps_registrar *reg,
const u8 *oob_dev_pw,
size_t oob_dev_pw_len);
+void wps_registrar_flush(struct wps_registrar *reg);
int wps_build_credential_wrap(struct wpabuf *msg,
const struct wps_credential *cred);
diff --git a/src/wps/wps_common.c b/src/wps/wps_common.c
index a282348..222d485 100644
--- a/src/wps/wps_common.c
+++ b/src/wps/wps_common.c
@@ -489,7 +489,7 @@
ret = os_snprintf(buf, buf_len, "%u-%08X-%u",
WPA_GET_BE16(dev_type), WPA_GET_BE32(&dev_type[2]),
WPA_GET_BE16(&dev_type[6]));
- if (ret < 0 || (unsigned int) ret >= buf_len)
+ if (os_snprintf_error(buf_len, ret))
return NULL;
return buf;
diff --git a/src/wps/wps_defs.h b/src/wps/wps_defs.h
index f483e2e..da005a4 100644
--- a/src/wps/wps_defs.h
+++ b/src/wps/wps_defs.h
@@ -279,30 +279,71 @@
WPS_DEV_DISPLAY = 7,
WPS_DEV_MULTIMEDIA = 8,
WPS_DEV_GAMING = 9,
- WPS_DEV_PHONE = 10
+ WPS_DEV_PHONE = 10,
+ WPS_DEV_AUDIO = 11,
};
enum wps_dev_subcateg {
WPS_DEV_COMPUTER_PC = 1,
WPS_DEV_COMPUTER_SERVER = 2,
WPS_DEV_COMPUTER_MEDIA_CENTER = 3,
+ WPS_DEV_COMPUTER_ULTRA_MOBILE = 4,
+ WPS_DEV_COMPUTER_NOTEBOOK = 5,
+ WPS_DEV_COMPUTER_DESKTOP = 6,
+ WPS_DEV_COMPUTER_MID = 7,
+ WPS_DEV_COMPUTER_NETBOOK = 8,
+ WPS_DEV_COMPUTER_TABLET = 9,
+ WPS_DEV_INPUT_KEYBOARD = 1,
+ WPS_DEV_INPUT_MOUSE = 2,
+ WPS_DEV_INPUT_JOYSTICK = 3,
+ WPS_DEV_INPUT_TRACKBALL = 4,
+ WPS_DEV_INPUT_GAMING = 5,
+ WPS_DEV_INPUT_REMOTE = 6,
+ WPS_DEV_INPUT_TOUCHSCREEN = 7,
+ WPS_DEV_INPUT_BIOMETRIC_READER = 8,
+ WPS_DEV_INPUT_BARCODE_READER = 9,
WPS_DEV_PRINTER_PRINTER = 1,
WPS_DEV_PRINTER_SCANNER = 2,
+ WPS_DEV_PRINTER_FAX = 3,
+ WPS_DEV_PRINTER_COPIER = 4,
+ WPS_DEV_PRINTER_ALL_IN_ONE = 5,
WPS_DEV_CAMERA_DIGITAL_STILL_CAMERA = 1,
+ WPS_DEV_CAMERA_VIDEO = 2,
+ WPS_DEV_CAMERA_WEB = 3,
+ WPS_DEV_CAMERA_SECURITY = 4,
WPS_DEV_STORAGE_NAS = 1,
WPS_DEV_NETWORK_INFRA_AP = 1,
WPS_DEV_NETWORK_INFRA_ROUTER = 2,
WPS_DEV_NETWORK_INFRA_SWITCH = 3,
+ WPS_DEV_NETWORK_INFRA_GATEWAY = 4,
+ WPS_DEV_NETWORK_INFRA_BRIDGE = 5,
WPS_DEV_DISPLAY_TV = 1,
WPS_DEV_DISPLAY_PICTURE_FRAME = 2,
WPS_DEV_DISPLAY_PROJECTOR = 3,
+ WPS_DEV_DISPLAY_MONITOR = 4,
WPS_DEV_MULTIMEDIA_DAR = 1,
WPS_DEV_MULTIMEDIA_PVR = 2,
WPS_DEV_MULTIMEDIA_MCX = 3,
+ WPS_DEV_MULTIMEDIA_SET_TOP_BOX = 4,
+ WPS_DEV_MULTIMEDIA_MEDIA_SERVER = 5,
+ WPS_DEV_MULTIMEDIA_PORTABLE_VIDEO_PLAYER = 6,
WPS_DEV_GAMING_XBOX = 1,
WPS_DEV_GAMING_XBOX360 = 2,
WPS_DEV_GAMING_PLAYSTATION = 3,
- WPS_DEV_PHONE_WINDOWS_MOBILE = 1
+ WPS_DEV_GAMING_GAME_CONSOLE = 4,
+ WPS_DEV_GAMING_PORTABLE_DEVICE = 5,
+ WPS_DEV_PHONE_WINDOWS_MOBILE = 1,
+ WPS_DEV_PHONE_SINGLE_MODE = 2,
+ WPS_DEV_PHONE_DUAL_MODE = 3,
+ WPS_DEV_PHONE_SP_SINGLE_MODE = 4,
+ WPS_DEV_PHONE_SP_DUAL_MODE = 5,
+ WPS_DEV_AUDIO_TUNER_RECV = 1,
+ WPS_DEV_AUDIO_SPEAKERS = 2,
+ WPS_DEV_AUDIO_PMP = 3,
+ WPS_DEV_AUDIO_HEADSET = 4,
+ WPS_DEV_AUDIO_HEADPHONES = 5,
+ WPS_DEV_AUDIO_MICROPHONE = 6,
+ WPS_DEV_AUDIO_HOME_THEATRE = 7,
};
diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c
index 9f5a90c..89957b1 100644
--- a/src/wps/wps_enrollee.c
+++ b/src/wps/wps_enrollee.c
@@ -247,22 +247,48 @@
static int wps_build_cred_auth_type(struct wps_data *wps, struct wpabuf *msg)
{
- wpa_printf(MSG_DEBUG, "WPS: * Authentication Type (0x%x)",
- wps->wps->ap_auth_type);
+ u16 auth_type = wps->wps->ap_auth_type;
+
+ /*
+ * Work around issues with Windows 7 WPS implementation not liking
+ * multiple Authentication Type bits in M7 AP Settings attribute by
+ * showing only the most secure option from current configuration.
+ */
+ if (auth_type & WPS_AUTH_WPA2PSK)
+ auth_type = WPS_AUTH_WPA2PSK;
+ else if (auth_type & WPS_AUTH_WPAPSK)
+ auth_type = WPS_AUTH_WPAPSK;
+ else if (auth_type & WPS_AUTH_OPEN)
+ auth_type = WPS_AUTH_OPEN;
+
+ wpa_printf(MSG_DEBUG, "WPS: * Authentication Type (0x%x)", auth_type);
wpabuf_put_be16(msg, ATTR_AUTH_TYPE);
wpabuf_put_be16(msg, 2);
- wpabuf_put_be16(msg, wps->wps->ap_auth_type);
+ wpabuf_put_be16(msg, auth_type);
return 0;
}
static int wps_build_cred_encr_type(struct wps_data *wps, struct wpabuf *msg)
{
- wpa_printf(MSG_DEBUG, "WPS: * Encryption Type (0x%x)",
- wps->wps->ap_encr_type);
+ u16 encr_type = wps->wps->ap_encr_type;
+
+ /*
+ * Work around issues with Windows 7 WPS implementation not liking
+ * multiple Encryption Type bits in M7 AP Settings attribute by
+ * showing only the most secure option from current configuration.
+ */
+ if (wps->wps->ap_auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK)) {
+ if (encr_type & WPS_ENCR_AES)
+ encr_type = WPS_ENCR_AES;
+ else if (encr_type & WPS_ENCR_TKIP)
+ encr_type = WPS_ENCR_TKIP;
+ }
+
+ wpa_printf(MSG_DEBUG, "WPS: * Encryption Type (0x%x)", encr_type);
wpabuf_put_be16(msg, ATTR_ENCR_TYPE);
wpabuf_put_be16(msg, 2);
- wpabuf_put_be16(msg, wps->wps->ap_encr_type);
+ wpabuf_put_be16(msg, encr_type);
return 0;
}
diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c
index b90cc25..8ee1ea9 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -676,6 +676,22 @@
}
+void wps_registrar_flush(struct wps_registrar *reg)
+{
+ if (reg == NULL)
+ return;
+ wps_free_pins(®->pins);
+ wps_free_nfc_pw_tokens(®->nfc_pw_tokens, 0);
+ wps_free_pbc_sessions(reg->pbc_sessions);
+ reg->pbc_sessions = NULL;
+ wps_free_devices(reg->devices);
+ reg->devices = NULL;
+#ifdef WPS_WORKAROUNDS
+ reg->pbc_ignore_start.sec = 0;
+#endif /* WPS_WORKAROUNDS */
+}
+
+
/**
* wps_registrar_deinit - Deinitialize WPS Registrar data
* @reg: Registrar data from wps_registrar_init()
@@ -686,11 +702,8 @@
return;
eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
- wps_free_pins(®->pins);
- wps_free_nfc_pw_tokens(®->nfc_pw_tokens, 0);
- wps_free_pbc_sessions(reg->pbc_sessions);
+ wps_registrar_flush(reg);
wpabuf_free(reg->extra_cred);
- wps_free_devices(reg->devices);
os_free(reg);
}
@@ -3495,7 +3508,7 @@
d->dev.model_name ? d->dev.model_name : "",
d->dev.model_number ? d->dev.model_number : "",
d->dev.serial_number ? d->dev.serial_number : "");
- if (ret < 0 || (size_t) ret >= buflen - len)
+ if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
diff --git a/src/wps/wps_upnp.c b/src/wps/wps_upnp.c
index ae94a9f..933d734 100644
--- a/src/wps/wps_upnp.c
+++ b/src/wps/wps_upnp.c
@@ -251,13 +251,16 @@
* use for constructing UUIDs for subscriptions. Presumably any method from
* rfc4122 is good enough; I've chosen random number method.
*/
-static void uuid_make(u8 uuid[UUID_LEN])
+static int uuid_make(u8 uuid[UUID_LEN])
{
- os_get_random(uuid, UUID_LEN);
+ if (os_get_random(uuid, UUID_LEN) < 0)
+ return -1;
/* Replace certain bits as specified in rfc4122 or X.667 */
uuid[6] &= 0x0f; uuid[6] |= (4 << 4); /* version 4 == random gen */
uuid[8] &= 0x3f; uuid[8] |= 0x80;
+
+ return 0;
}
@@ -700,10 +703,12 @@
if (dl_list_len(&sm->subscriptions) >= MAX_SUBSCRIPTIONS) {
s = dl_list_first(&sm->subscriptions, struct subscription,
list);
- wpa_printf(MSG_INFO, "WPS UPnP: Too many subscriptions, "
- "trashing oldest");
- dl_list_del(&s->list);
- subscription_destroy(s);
+ if (s) {
+ wpa_printf(MSG_INFO,
+ "WPS UPnP: Too many subscriptions, trashing oldest");
+ dl_list_del(&s->list);
+ subscription_destroy(s);
+ }
}
s = os_zalloc(sizeof(*s));
@@ -714,7 +719,10 @@
s->sm = sm;
s->timeout_time = expire;
- uuid_make(s->uuid);
+ if (uuid_make(s->uuid) < 0) {
+ subscription_destroy(s);
+ return NULL;
+ }
subscr_addr_list_create(s, callback_urls);
if (dl_list_empty(&s->addr_list)) {
wpa_printf(MSG_DEBUG, "WPS UPnP: No valid callback URLs in "
diff --git a/src/wps/wps_upnp_ssdp.c b/src/wps/wps_upnp_ssdp.c
index 098571c..26a740d 100644
--- a/src/wps/wps_upnp_ssdp.c
+++ b/src/wps/wps_upnp_ssdp.c
@@ -317,7 +317,8 @@
* (see notes above)
*/
next_timeout_msec = 0;
- os_get_random((void *) &r, sizeof(r));
+ if (os_get_random((void *) &r, sizeof(r)) < 0)
+ r = 32768;
next_timeout_sec = UPNP_CACHE_SEC / 4 +
(((UPNP_CACHE_SEC / 4) * r) >> 16);
sm->advertise_count++;
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index b5c9660..ed78bf9 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -10,8 +10,6 @@
ifneq ($(BOARD_WPA_SUPPLICANT_DRIVER),)
CONFIG_DRIVER_$(BOARD_WPA_SUPPLICANT_DRIVER) := y
-else
- CONFIG_DRIVER_TEST := y
endif
include $(LOCAL_PATH)/android.config
@@ -84,6 +82,7 @@
OBJS += src/utils/common.c
OBJS += src/utils/wpa_debug.c
OBJS += src/utils/wpabuf.c
+OBJS += wmm_ac.c
OBJS_p = wpa_passphrase.c
OBJS_p += src/utils/common.c
OBJS_p += src/utils/wpa_debug.c
@@ -183,6 +182,17 @@
L_CFLAGS += -DCONFIG_NO_SCAN_PROCESSING
endif
+ifdef CONFIG_SUITEB
+L_CFLAGS += -DCONFIG_SUITEB
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
+ifdef CONFIG_SUITEB192
+L_CFLAGS += -DCONFIG_SUITEB192
+NEED_SHA384=y
+endif
+
ifdef CONFIG_IEEE80211W
L_CFLAGS += -DCONFIG_IEEE80211W
NEED_SHA256=y
@@ -192,11 +202,24 @@
ifdef CONFIG_IEEE80211R
L_CFLAGS += -DCONFIG_IEEE80211R
OBJS += src/rsn_supp/wpa_ft.c
-NEED_80211_COMMON=y
NEED_SHA256=y
NEED_AES_OMAC1=y
endif
+ifdef CONFIG_MESH
+NEED_80211_COMMON=y
+NEED_SHA256=y
+NEED_AES_SIV=y
+NEED_AES_OMAC1=y
+NEED_AES_CTR=y
+CONFIG_SAE=y
+CONFIG_AP=y
+L_CFLAGS += -DCONFIG_MESH
+OBJS += mesh.c
+OBJS += mesh_mpm.c
+OBJS += mesh_rsn.c
+endif
+
ifdef CONFIG_SAE
L_CFLAGS += -DCONFIG_SAE
OBJS += src/common/sae.c
@@ -262,7 +285,6 @@
L_CFLAGS += -DCONFIG_P2P
NEED_GAS=y
NEED_OFFCHANNEL=y
-NEED_80211_COMMON=y
CONFIG_WPS=y
CONFIG_AP=y
ifdef CONFIG_P2P_STRICT
@@ -328,6 +350,12 @@
LIBS += -lpcap
endif
+ifdef CONFIG_ERP
+L_CFLAGS += -DCONFIG_ERP
+NEED_SHA256=y
+NEED_HMAC_SHA256_KDF=y
+endif
+
ifdef CONFIG_EAP_TLS
# EAP-TLS
ifeq ($(CONFIG_EAP_TLS), dyn)
@@ -634,7 +662,6 @@
NEED_DH_GROUPS=y
NEED_SHA256=y
NEED_BASE64=y
-NEED_80211_COMMON=y
NEED_AES_CBC=y
NEED_MODEXP=y
@@ -743,7 +770,6 @@
endif
ifdef CONFIG_AP
-NEED_80211_COMMON=y
NEED_EAP_COMMON=y
NEED_RSN_AUTHENTICATOR=y
L_CFLAGS += -DCONFIG_AP
@@ -767,6 +793,7 @@
OBJS += src/ap/drv_callbacks.c
OBJS += src/ap/ap_drv_ops.c
OBJS += src/ap/beacon.c
+OBJS += src/ap/bss_load.c
OBJS += src/ap/eap_user_db.c
ifdef CONFIG_IEEE80211N
OBJS += src/ap/ieee802_11_ht.c
@@ -982,23 +1009,6 @@
CONFIG_INTERNAL_DH_GROUP5=y
endif
-ifeq ($(CONFIG_TLS), nss)
-ifdef TLS_FUNCS
-OBJS += src/crypto/tls_nss.c
-LIBS += -lssl3
-endif
-OBJS += src/crypto/crypto_nss.c
-OBJS_p += src/crypto/crypto_nss.c
-ifdef NEED_FIPS186_2_PRF
-OBJS += src/crypto/fips_prf_internal.c
-OBJS += src/crypto/sha1-internal.c
-endif
-LIBS += -lnss3
-LIBS_p += -lnss3
-CONFIG_INTERNAL_MD4=y
-CONFIG_INTERNAL_DH_GROUP5=y
-endif
-
ifeq ($(CONFIG_TLS), internal)
ifndef CONFIG_CRYPTO
CONFIG_CRYPTO=internal
@@ -1148,6 +1158,9 @@
AESOBJS += src/crypto/aes-internal-enc.c
endif
endif
+ifdef NEED_AES_SIV
+AESOBJS += src/crypto/aes-siv.c
+endif
ifdef NEED_AES
OBJS += $(AESOBJS)
endif
@@ -1223,8 +1236,14 @@
ifdef NEED_TLS_PRF_SHA256
SHA256OBJS += src/crypto/sha256-tlsprf.c
endif
+ifdef NEED_HMAC_SHA256_KDF
+SHA256OBJS += src/crypto/sha256-kdf.c
+endif
OBJS += $(SHA256OBJS)
endif
+ifdef NEED_SHA384
+L_CFLAGS += -DCONFIG_SHA384
+endif
ifdef NEED_DH_GROUPS
OBJS += src/crypto/dh_groups.c
@@ -1367,14 +1386,12 @@
endif
ifdef NEED_SME
-NEED_80211_COMMON=y
OBJS += sme.c
L_CFLAGS += -DCONFIG_SME
endif
-ifdef NEED_80211_COMMON
OBJS += src/common/ieee802_11_common.c
-endif
+OBJS += src/common/hw_features_common.c
ifdef NEED_EAP_COMMON
OBJS += src/eap_common/eap_common.c
@@ -1499,26 +1516,6 @@
ifdef CONFIG_DRIVER_NL80211
OBJS_priv += src/common/ieee802_11_common.c
endif
-ifdef CONFIG_DRIVER_TEST
-OBJS_priv += $(SHA1OBJS)
-OBJS_priv += $(MD5OBJS)
-ifeq ($(CONFIG_TLS), openssl)
-OBJS_priv += src/crypto/crypto_openssl.c
-endif
-ifeq ($(CONFIG_TLS), gnutls)
-OBJS_priv += src/crypto/crypto_gnutls.c
-endif
-ifeq ($(CONFIG_TLS), nss)
-OBJS_priv += src/crypto/crypto_nss.c
-endif
-ifeq ($(CONFIG_TLS), internal)
-ifeq ($(CONFIG_CRYPTO), libtomcrypt)
-OBJS_priv += src/crypto/crypto_libtomcrypt.c
-else
-OBJS_priv += src/crypto/crypto_internal.c
-endif
-endif
-endif # CONFIG_DRIVER_TEST
OBJS += src/l2_packet/l2_packet_privsep.c
OBJS += src/drivers/driver_privsep.c
EXTRA_progs += wpa_priv
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 8f7c23f..21486c4 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -80,6 +80,7 @@
OBJS_c = wpa_cli.o ../src/common/wpa_ctrl.o
OBJS_c += ../src/utils/wpa_debug.o
OBJS_c += ../src/utils/common.o
+OBJS += wmm_ac.o
ifndef CONFIG_OS
ifdef CONFIG_NATIVE_WINDOWS
@@ -185,6 +186,17 @@
CFLAGS += -DCONFIG_NO_SCAN_PROCESSING
endif
+ifdef CONFIG_SUITEB
+CFLAGS += -DCONFIG_SUITEB
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
+ifdef CONFIG_SUITEB192
+CFLAGS += -DCONFIG_SUITEB192
+NEED_SHA384=y
+endif
+
ifdef CONFIG_IEEE80211W
CFLAGS += -DCONFIG_IEEE80211W
NEED_SHA256=y
@@ -194,11 +206,24 @@
ifdef CONFIG_IEEE80211R
CFLAGS += -DCONFIG_IEEE80211R
OBJS += ../src/rsn_supp/wpa_ft.o
-NEED_80211_COMMON=y
NEED_SHA256=y
NEED_AES_OMAC1=y
endif
+ifdef CONFIG_MESH
+NEED_80211_COMMON=y
+NEED_SHA256=y
+NEED_AES_SIV=y
+NEED_AES_OMAC1=y
+NEED_AES_CTR=y
+CONFIG_SAE=y
+CONFIG_AP=y
+CFLAGS += -DCONFIG_MESH
+OBJS += mesh.o
+OBJS += mesh_mpm.o
+OBJS += mesh_rsn.o
+endif
+
ifdef CONFIG_SAE
CFLAGS += -DCONFIG_SAE
OBJS += ../src/common/sae.o
@@ -264,7 +289,6 @@
CFLAGS += -DCONFIG_P2P
NEED_GAS=y
NEED_OFFCHANNEL=y
-NEED_80211_COMMON=y
CONFIG_WPS=y
CONFIG_AP=y
ifdef CONFIG_P2P_STRICT
@@ -329,6 +353,12 @@
LIBS += -lpcap
endif
+ifdef CONFIG_ERP
+CFLAGS += -DCONFIG_ERP
+NEED_SHA256=y
+NEED_HMAC_SHA256_KDF=y
+endif
+
ifdef CONFIG_EAP_TLS
# EAP-TLS
ifeq ($(CONFIG_EAP_TLS), dyn)
@@ -635,7 +665,6 @@
NEED_DH_GROUPS=y
NEED_SHA256=y
NEED_BASE64=y
-NEED_80211_COMMON=y
NEED_AES_CBC=y
NEED_MODEXP=y
@@ -757,7 +786,6 @@
endif
ifdef CONFIG_AP
-NEED_80211_COMMON=y
NEED_EAP_COMMON=y
NEED_RSN_AUTHENTICATOR=y
CFLAGS += -DCONFIG_AP
@@ -781,6 +809,7 @@
OBJS += ../src/ap/drv_callbacks.o
OBJS += ../src/ap/ap_drv_ops.o
OBJS += ../src/ap/beacon.o
+OBJS += ../src/ap/bss_load.o
OBJS += ../src/ap/eap_user_db.o
ifdef CONFIG_IEEE80211N
OBJS += ../src/ap/ieee802_11_ht.o
@@ -996,23 +1025,6 @@
CONFIG_INTERNAL_DH_GROUP5=y
endif
-ifeq ($(CONFIG_TLS), nss)
-ifdef TLS_FUNCS
-OBJS += ../src/crypto/tls_nss.o
-LIBS += -lssl3
-endif
-OBJS += ../src/crypto/crypto_nss.o
-OBJS_p += ../src/crypto/crypto_nss.o
-ifdef NEED_FIPS186_2_PRF
-OBJS += ../src/crypto/fips_prf_internal.o
-SHA1OBJS += ../src/crypto/sha1-internal.o
-endif
-LIBS += -lnss3
-LIBS_p += -lnss3
-CONFIG_INTERNAL_MD4=y
-CONFIG_INTERNAL_DH_GROUP5=y
-endif
-
ifeq ($(CONFIG_TLS), internal)
ifndef CONFIG_CRYPTO
CONFIG_CRYPTO=internal
@@ -1149,6 +1161,9 @@
AESOBJS += ../src/crypto/aes-omac1.o
endif
endif
+ifdef NEED_AES_SIV
+AESOBJS += ../src/crypto/aes-siv.o
+endif
ifdef NEED_AES_WRAP
NEED_AES_ENC=y
AESOBJS += ../src/crypto/aes-wrap.o
@@ -1235,8 +1250,14 @@
ifdef NEED_TLS_PRF_SHA256
SHA256OBJS += ../src/crypto/sha256-tlsprf.o
endif
+ifdef NEED_HMAC_SHA256_KDF
+OBJS += ../src/crypto/sha256-kdf.o
+endif
OBJS += $(SHA256OBJS)
endif
+ifdef NEED_SHA384
+CFLAGS += -DCONFIG_SHA384
+endif
ifdef NEED_DH_GROUPS
OBJS += ../src/crypto/dh_groups.o
@@ -1386,14 +1407,12 @@
endif
ifdef NEED_SME
-NEED_80211_COMMON=y
OBJS += sme.o
CFLAGS += -DCONFIG_SME
endif
-ifdef NEED_80211_COMMON
OBJS += ../src/common/ieee802_11_common.o
-endif
+OBJS += ../src/common/hw_features_common.o
ifdef NEED_EAP_COMMON
OBJS += ../src/eap_common/eap_common.o
@@ -1496,6 +1515,7 @@
OBJS += wpas_module_tests.o
OBJS += ../src/utils/utils_module_tests.o
OBJS += ../src/common/common_module_tests.o
+OBJS += ../src/crypto/crypto_module_tests.o
ifdef CONFIG_WPS
OBJS += ../src/wps/wps_module_tests.o
endif
@@ -1539,26 +1559,6 @@
ifdef CONFIG_DRIVER_NL80211
OBJS_priv += ../src/common/ieee802_11_common.o
endif
-ifdef CONFIG_DRIVER_TEST
-OBJS_priv += $(SHA1OBJS)
-OBJS_priv += $(MD5OBJS)
-ifeq ($(CONFIG_TLS), openssl)
-OBJS_priv += ../src/crypto/crypto_openssl.o
-endif
-ifeq ($(CONFIG_TLS), gnutls)
-OBJS_priv += ../src/crypto/crypto_gnutls.o
-endif
-ifeq ($(CONFIG_TLS), nss)
-OBJS_priv += ../src/crypto/crypto_nss.o
-endif
-ifeq ($(CONFIG_TLS), internal)
-ifeq ($(CONFIG_CRYPTO), libtomcrypt)
-OBJS_priv += ../src/crypto/crypto_libtomcrypt.o
-else
-OBJS_priv += ../src/crypto/crypto_internal.o
-endif
-endif
-endif # CONFIG_DRIVER_TEST
OBJS += ../src/l2_packet/l2_packet_privsep.o
OBJS += ../src/drivers/driver_privsep.o
EXTRA_progs += wpa_priv
@@ -1588,6 +1588,10 @@
Q=
E=true
endif
+ifeq ($(QUIET), 1)
+Q=@
+E=true
+endif
dynamic_eap_methods: $(EAPDYN)
@@ -1680,10 +1684,12 @@
endif
%.service: %.service.in
- sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@
+ $(Q)sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@
+ @$(E) " sed" $<
%@.service: %.service.arg.in
- sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@
+ $(Q)sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@
+ @$(E) " sed" $<
wpa_supplicant.exe: wpa_supplicant
mv -f $< $@
diff --git a/wpa_supplicant/README b/wpa_supplicant/README
index 653848e..f9c65d2 100644
--- a/wpa_supplicant/README
+++ b/wpa_supplicant/README
@@ -1,7 +1,7 @@
WPA Supplicant
==============
-Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
This program is licensed under the BSD license (the one with
diff --git a/wpa_supplicant/README-HS20 b/wpa_supplicant/README-HS20
index 58c2475..161dc06 100644
--- a/wpa_supplicant/README-HS20
+++ b/wpa_supplicant/README-HS20
@@ -172,7 +172,7 @@
# If set, this FQDN is used as a suffix match requirement for the AAA
# server certificate in SubjectAltName dNSName element(s). If a
# matching dNSName is found, this constraint is met. If no dNSName
-# values are present, this constraint is matched against SubjetName CN
+# values are present, this constraint is matched against SubjectName CN
# using same suffix match comparison. Suffix match here means that the
# host/domain name is compared one label at a time starting from the
# top-level domain and all the labels in @domain_suffix_match shall be
diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config
index 3ed734d..8d27bb2 100644
--- a/wpa_supplicant/android.config
+++ b/wpa_supplicant/android.config
@@ -55,9 +55,6 @@
# wpa_supplicant.
# CONFIG_USE_NDISUIO=y
-# Driver interface for development testing
-#CONFIG_DRIVER_TEST=y
-
# Driver interface for wired Ethernet drivers
#CONFIG_DRIVER_WIRED=y
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 7c93498..65532e3 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -75,24 +75,10 @@
#endif /* CONFIG_IEEE80211N */
-static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid,
- struct hostapd_config *conf)
+void wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ struct hostapd_config *conf)
{
- struct hostapd_bss_config *bss = conf->bss[0];
-
- conf->driver = wpa_s->driver;
-
- os_strlcpy(bss->iface, wpa_s->ifname, sizeof(bss->iface));
-
- conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency,
- &conf->channel);
- if (conf->hw_mode == NUM_HOSTAPD_MODES) {
- wpa_printf(MSG_ERROR, "Unsupported AP mode frequency: %d MHz",
- ssid->frequency);
- return -1;
- }
-
/* TODO: enable HT40 if driver supports it;
* drop to 11b if driver does not support 11g */
@@ -146,6 +132,7 @@
HT_CAP_INFO_SHORT_GI20MHZ |
HT_CAP_INFO_SHORT_GI40MHZ |
HT_CAP_INFO_RX_STBC_MASK |
+ HT_CAP_INFO_TX_STBC |
HT_CAP_INFO_MAX_AMSDU_SIZE);
if (mode->vht_capab && ssid->vht) {
@@ -155,6 +142,28 @@
}
}
#endif /* CONFIG_IEEE80211N */
+}
+
+
+static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ struct hostapd_config *conf)
+{
+ struct hostapd_bss_config *bss = conf->bss[0];
+
+ conf->driver = wpa_s->driver;
+
+ os_strlcpy(bss->iface, wpa_s->ifname, sizeof(bss->iface));
+
+ conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency,
+ &conf->channel);
+ if (conf->hw_mode == NUM_HOSTAPD_MODES) {
+ wpa_printf(MSG_ERROR, "Unsupported AP mode frequency: %d MHz",
+ ssid->frequency);
+ return -1;
+ }
+
+ wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf);
#ifdef CONFIG_P2P
if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G &&
@@ -217,7 +226,7 @@
bss->wpa_key_mgmt = ssid->key_mgmt;
bss->wpa_pairwise = ssid->pairwise_cipher;
if (ssid->psk_set) {
- os_free(bss->ssid.wpa_psk);
+ bin_clear_free(bss->ssid.wpa_psk, sizeof(*bss->ssid.wpa_psk));
bss->ssid.wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk));
if (bss->ssid.wpa_psk == NULL)
return -1;
@@ -317,7 +326,8 @@
bss->ssid.security_policy != SECURITY_PLAINTEXT)
goto no_wps;
if (bss->ssid.security_policy == SECURITY_WPA_PSK &&
- (!(bss->rsn_pairwise & WPA_CIPHER_CCMP) || !(bss->wpa & 2)))
+ (!(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) ||
+ !(bss->wpa & 2)))
goto no_wps; /* WPS2 does not allow WPA/TKIP-only
* configuration */
bss->eap_server = 1;
@@ -555,6 +565,7 @@
return -1;
hapd_iface->owner = wpa_s;
hapd_iface->drv_flags = wpa_s->drv_flags;
+ hapd_iface->smps_modes = wpa_s->drv_smps_modes;
hapd_iface->probe_resp_offloads = wpa_s->probe_resp_offloads;
hapd_iface->extended_capa = wpa_s->extended_capa;
hapd_iface->extended_capa_mask = wpa_s->extended_capa_mask;
@@ -629,6 +640,10 @@
#endif /* CONFIG_P2P */
hapd_iface->bss[i]->setup_complete_cb = wpas_ap_configured_cb;
hapd_iface->bss[i]->setup_complete_cb_ctx = wpa_s;
+#ifdef CONFIG_TESTING_OPTIONS
+ hapd_iface->bss[i]->ext_eapol_frame_io =
+ wpa_s->ext_eapol_frame_io;
+#endif /* CONFIG_TESTING_OPTIONS */
}
os_memcpy(hapd_iface->bss[0]->own_addr, wpa_s->own_addr, ETH_ALEN);
@@ -798,9 +813,14 @@
if (pin == NULL) {
unsigned int rpin = wps_generate_pin();
ret_len = os_snprintf(buf, buflen, "%08d", rpin);
+ if (os_snprintf_error(buflen, ret_len))
+ return -1;
pin = buf;
- } else
+ } else if (buf) {
ret_len = os_snprintf(buf, buflen, "%s", pin);
+ if (os_snprintf_error(buflen, ret_len))
+ return -1;
+ }
ret = hostapd_wps_add_pin(wpa_s->ap_iface->bss[0], bssid, "any", pin,
timeout);
@@ -890,7 +910,7 @@
return -1;
hapd = wpa_s->ap_iface->bss[0];
ret = os_snprintf(pin_txt, sizeof(pin_txt), "%s", pin);
- if (ret < 0 || ret >= (int) sizeof(pin_txt))
+ if (os_snprintf_error(sizeof(pin_txt), ret))
return -1;
os_free(hapd->conf->ap_pin);
hapd->conf->ap_pin = os_strdup(pin_txt);
@@ -975,30 +995,45 @@
int ap_ctrl_iface_sta_first(struct wpa_supplicant *wpa_s,
char *buf, size_t buflen)
{
- if (wpa_s->ap_iface == NULL)
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface)
+ hapd = wpa_s->ap_iface->bss[0];
+ else if (wpa_s->ifmsh)
+ hapd = wpa_s->ifmsh->bss[0];
+ else
return -1;
- return hostapd_ctrl_iface_sta_first(wpa_s->ap_iface->bss[0],
- buf, buflen);
+ return hostapd_ctrl_iface_sta_first(hapd, buf, buflen);
}
int ap_ctrl_iface_sta(struct wpa_supplicant *wpa_s, const char *txtaddr,
char *buf, size_t buflen)
{
- if (wpa_s->ap_iface == NULL)
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface)
+ hapd = wpa_s->ap_iface->bss[0];
+ else if (wpa_s->ifmsh)
+ hapd = wpa_s->ifmsh->bss[0];
+ else
return -1;
- return hostapd_ctrl_iface_sta(wpa_s->ap_iface->bss[0], txtaddr,
- buf, buflen);
+ return hostapd_ctrl_iface_sta(hapd, txtaddr, buf, buflen);
}
int ap_ctrl_iface_sta_next(struct wpa_supplicant *wpa_s, const char *txtaddr,
char *buf, size_t buflen)
{
- if (wpa_s->ap_iface == NULL)
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface)
+ hapd = wpa_s->ap_iface->bss[0];
+ else if (wpa_s->ifmsh)
+ hapd = wpa_s->ifmsh->bss[0];
+ else
return -1;
- return hostapd_ctrl_iface_sta_next(wpa_s->ap_iface->bss[0], txtaddr,
- buf, buflen);
+ return hostapd_ctrl_iface_sta_next(hapd, txtaddr, buf, buflen);
}
@@ -1044,7 +1079,7 @@
wpa_cipher_txt(conf->wpa_group),
wpa_key_mgmt_txt(conf->wpa_key_mgmt,
conf->wpa));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
return pos - buf;
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index 8aa5ffa..4d80c7a 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -75,4 +75,9 @@
int wpas_ap_wps_add_nfc_pw(struct wpa_supplicant *wpa_s, u16 pw_id,
const struct wpabuf *pw, const u8 *pubkey_hash);
+struct hostapd_config;
+void wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ struct hostapd_config *conf);
+
#endif /* AP_H */
diff --git a/wpa_supplicant/bgscan_learn.c b/wpa_supplicant/bgscan_learn.c
index 6a92b73..a320cc4 100644
--- a/wpa_supplicant/bgscan_learn.c
+++ b/wpa_supplicant/bgscan_learn.c
@@ -294,7 +294,7 @@
int ret;
ret = os_snprintf(pos, msg + sizeof(msg) - pos, " %d",
freqs[i]);
- if (ret < 0 || ret >= msg + sizeof(msg) - pos)
+ if (os_snprintf_error(msg + sizeof(msg) - pos, ret))
break;
pos += ret;
}
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 1de51e5..1798439 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -306,8 +306,9 @@
static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
{
return bss == wpa_s->current_bss ||
- os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 ||
- os_memcmp(bss->bssid, wpa_s->pending_bssid, ETH_ALEN) == 0;
+ (!is_zero_ether_addr(bss->bssid) &&
+ (os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 ||
+ os_memcmp(bss->bssid, wpa_s->pending_bssid, ETH_ALEN) == 0));
}
@@ -620,7 +621,7 @@
struct wpa_scan_res *res,
struct os_reltime *fetch_time)
{
- const u8 *ssid, *p2p;
+ const u8 *ssid, *p2p, *mesh;
struct wpa_bss *bss;
if (wpa_s->conf->ignore_old_scan_res) {
@@ -670,6 +671,11 @@
/* TODO: add option for ignoring BSSes we are not interested in
* (to save memory) */
+
+ mesh = wpa_scan_get_ie(res, WLAN_EID_MESH_ID);
+ if (mesh && mesh[1] <= 32)
+ ssid = mesh;
+
bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]);
if (bss == NULL)
bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res, fetch_time);
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index b7f259b..1ffc2dc 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / Configuration parser and common functions
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -225,7 +225,7 @@
if (value == NULL)
return NULL;
res = os_snprintf(value, 20, "%d", *src);
- if (res < 0 || res >= 20) {
+ if (os_snprintf_error(20, res)) {
os_free(value);
return NULL;
}
@@ -235,6 +235,99 @@
#endif /* NO_CONFIG_WRITE */
+static int wpa_config_parse_addr_list(const struct parse_data *data,
+ int line, const char *value,
+ u8 **list, size_t *num, char *name,
+ u8 abort_on_error, u8 masked)
+{
+ const char *pos;
+ u8 *buf, *n, addr[2 * ETH_ALEN];
+ size_t count;
+
+ buf = NULL;
+ count = 0;
+
+ pos = value;
+ while (pos && *pos) {
+ while (*pos == ' ')
+ pos++;
+
+ if (hwaddr_masked_aton(pos, addr, &addr[ETH_ALEN], masked)) {
+ if (abort_on_error || count == 0) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid %s address '%s'",
+ line, name, value);
+ os_free(buf);
+ return -1;
+ }
+ /* continue anyway since this could have been from a
+ * truncated configuration file line */
+ wpa_printf(MSG_INFO,
+ "Line %d: Ignore likely truncated %s address '%s'",
+ line, name, pos);
+ } else {
+ n = os_realloc_array(buf, count + 1, 2 * ETH_ALEN);
+ if (n == NULL) {
+ os_free(buf);
+ return -1;
+ }
+ buf = n;
+ os_memmove(buf + 2 * ETH_ALEN, buf,
+ count * 2 * ETH_ALEN);
+ os_memcpy(buf, addr, 2 * ETH_ALEN);
+ count++;
+ wpa_printf(MSG_MSGDUMP,
+ "%s: addr=" MACSTR " mask=" MACSTR,
+ name, MAC2STR(addr),
+ MAC2STR(&addr[ETH_ALEN]));
+ }
+
+ pos = os_strchr(pos, ' ');
+ }
+
+ os_free(*list);
+ *list = buf;
+ *num = count;
+
+ return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_addr_list(const struct parse_data *data,
+ const u8 *list, size_t num, char *name)
+{
+ char *value, *end, *pos;
+ int res;
+ size_t i;
+
+ if (list == NULL || num == 0)
+ return NULL;
+
+ value = os_malloc(2 * 20 * num);
+ if (value == NULL)
+ return NULL;
+ pos = value;
+ end = value + 2 * 20 * num;
+
+ for (i = num; i > 0; i--) {
+ const u8 *a = list + (i - 1) * 2 * ETH_ALEN;
+ const u8 *m = a + ETH_ALEN;
+
+ if (i < num)
+ *pos++ = ' ';
+ res = hwaddr_mask_txt(pos, end - pos, a, m);
+ if (res < 0) {
+ os_free(value);
+ return NULL;
+ }
+ pos += res;
+ }
+
+ return value;
+}
+#endif /* NO_CONFIG_WRITE */
+
static int wpa_config_parse_bssid(const struct parse_data *data,
struct wpa_ssid *ssid, int line,
const char *value)
@@ -270,7 +363,7 @@
if (value == NULL)
return NULL;
res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->bssid));
- if (res < 0 || res >= 20) {
+ if (os_snprintf_error(20, res)) {
os_free(value);
return NULL;
}
@@ -280,6 +373,50 @@
#endif /* NO_CONFIG_WRITE */
+static int wpa_config_parse_bssid_blacklist(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ return wpa_config_parse_addr_list(data, line, value,
+ &ssid->bssid_blacklist,
+ &ssid->num_bssid_blacklist,
+ "bssid_blacklist", 1, 1);
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_bssid_blacklist(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ return wpa_config_write_addr_list(data, ssid->bssid_blacklist,
+ ssid->num_bssid_blacklist,
+ "bssid_blacklist");
+}
+#endif /* NO_CONFIG_WRITE */
+
+
+static int wpa_config_parse_bssid_whitelist(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ return wpa_config_parse_addr_list(data, line, value,
+ &ssid->bssid_whitelist,
+ &ssid->num_bssid_whitelist,
+ "bssid_whitelist", 1, 1);
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_bssid_whitelist(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ return wpa_config_write_addr_list(data, ssid->bssid_whitelist,
+ ssid->num_bssid_whitelist,
+ "bssid_whitelist");
+}
+#endif /* NO_CONFIG_WRITE */
+
+
static int wpa_config_parse_psk(const struct parse_data *data,
struct wpa_ssid *ssid, int line,
const char *value)
@@ -358,9 +495,15 @@
if (ssid->ext_psk) {
size_t len = 4 + os_strlen(ssid->ext_psk) + 1;
char *buf = os_malloc(len);
+ int res;
+
if (buf == NULL)
return NULL;
- os_snprintf(buf, len, "ext:%s", ssid->ext_psk);
+ res = os_snprintf(buf, len, "ext:%s", ssid->ext_psk);
+ if (os_snprintf_error(len, res)) {
+ os_free(buf);
+ buf = NULL;
+ }
return buf;
}
#endif /* CONFIG_EXT_PASSWORD */
@@ -446,7 +589,7 @@
if (ssid->proto & WPA_PROTO_WPA) {
ret = os_snprintf(pos, end - pos, "%sWPA",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return buf;
pos += ret;
}
@@ -454,7 +597,7 @@
if (ssid->proto & WPA_PROTO_RSN) {
ret = os_snprintf(pos, end - pos, "%sRSN",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return buf;
pos += ret;
}
@@ -462,7 +605,7 @@
if (ssid->proto & WPA_PROTO_OSEN) {
ret = os_snprintf(pos, end - pos, "%sOSEN",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return buf;
pos += ret;
}
@@ -535,6 +678,14 @@
else if (os_strcmp(start, "OSEN") == 0)
val |= WPA_KEY_MGMT_OSEN;
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_SUITEB
+ else if (os_strcmp(start, "WPA-EAP-SUITE-B") == 0)
+ val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B;
+#endif /* CONFIG_SUITEB */
+#ifdef CONFIG_SUITEB192
+ else if (os_strcmp(start, "WPA-EAP-SUITE-B-192") == 0)
+ val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
+#endif /* CONFIG_SUITEB192 */
else {
wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
line, start);
@@ -574,7 +725,7 @@
if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
ret = os_snprintf(pos, end - pos, "%sWPA-PSK",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
end[-1] = '\0';
return buf;
}
@@ -584,7 +735,7 @@
if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
ret = os_snprintf(pos, end - pos, "%sWPA-EAP",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
end[-1] = '\0';
return buf;
}
@@ -594,7 +745,7 @@
if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
ret = os_snprintf(pos, end - pos, "%sIEEE8021X",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
end[-1] = '\0';
return buf;
}
@@ -604,7 +755,7 @@
if (ssid->key_mgmt & WPA_KEY_MGMT_NONE) {
ret = os_snprintf(pos, end - pos, "%sNONE",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
end[-1] = '\0';
return buf;
}
@@ -614,7 +765,7 @@
if (ssid->key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
ret = os_snprintf(pos, end - pos, "%sWPA-NONE",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
end[-1] = '\0';
return buf;
}
@@ -625,7 +776,7 @@
if (ssid->key_mgmt & WPA_KEY_MGMT_FT_PSK) {
ret = os_snprintf(pos, end - pos, "%sFT-PSK",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
end[-1] = '\0';
return buf;
}
@@ -635,7 +786,7 @@
if (ssid->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
ret = os_snprintf(pos, end - pos, "%sFT-EAP",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
end[-1] = '\0';
return buf;
}
@@ -647,7 +798,7 @@
if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
ret = os_snprintf(pos, end - pos, "%sWPA-PSK-SHA256",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
end[-1] = '\0';
return buf;
}
@@ -657,7 +808,7 @@
if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
ret = os_snprintf(pos, end - pos, "%sWPA-EAP-SHA256",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
end[-1] = '\0';
return buf;
}
@@ -669,7 +820,7 @@
if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
ret = os_snprintf(pos, end - pos, "%sWPS",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
end[-1] = '\0';
return buf;
}
@@ -677,6 +828,64 @@
}
#endif /* CONFIG_WPS */
+#ifdef CONFIG_SAE
+ if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
+ ret = os_snprintf(pos, end - pos, "%sSAE",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret)) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
+ }
+
+ if (ssid->key_mgmt & WPA_KEY_MGMT_FT_SAE) {
+ ret = os_snprintf(pos, end - pos, "%sFT-SAE",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret)) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
+ }
+#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_HS20
+ if (ssid->key_mgmt & WPA_KEY_MGMT_OSEN) {
+ ret = os_snprintf(pos, end - pos, "%sOSEN",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret)) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
+ }
+#endif /* CONFIG_HS20 */
+
+#ifdef CONFIG_SUITEB
+ if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
+ ret = os_snprintf(pos, end - pos, "%sWPA-EAP-SUITE-B",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret)) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
+ }
+#endif /* CONFIG_SUITEB */
+
+#ifdef CONFIG_SUITEB192
+ if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
+ ret = os_snprintf(pos, end - pos, "%sWPA-EAP-SUITE-B-192",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret)) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
+ }
+#endif /* CONFIG_SUITEB192 */
+
if (pos == buf) {
os_free(buf);
buf = NULL;
@@ -846,7 +1055,7 @@
if (ssid->auth_alg & WPA_AUTH_ALG_OPEN) {
ret = os_snprintf(pos, end - pos, "%sOPEN",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
end[-1] = '\0';
return buf;
}
@@ -856,7 +1065,7 @@
if (ssid->auth_alg & WPA_AUTH_ALG_SHARED) {
ret = os_snprintf(pos, end - pos, "%sSHARED",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
end[-1] = '\0';
return buf;
}
@@ -866,7 +1075,7 @@
if (ssid->auth_alg & WPA_AUTH_ALG_LEAP) {
ret = os_snprintf(pos, end - pos, "%sLEAP",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
end[-1] = '\0';
return buf;
}
@@ -987,7 +1196,7 @@
for (i = 0; freqs[i]; i++) {
ret = os_snprintf(pos, end - pos, "%s%u",
i == 0 ? "" : " ", freqs[i]);
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
end[-1] = '\0';
return buf;
}
@@ -1110,7 +1319,7 @@
if (name) {
ret = os_snprintf(pos, end - pos, "%s%s",
pos == buf ? "" : " ", name);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
break;
pos += ret;
}
@@ -1264,7 +1473,7 @@
os_memcpy(key, buf, *len);
str_clear_free(buf);
res = os_snprintf(title, sizeof(title), "wep_key%d", idx);
- if (res >= 0 && (size_t) res < sizeof(title))
+ if (!os_snprintf_error(sizeof(title), res))
wpa_hexdump_key(MSG_MSGDUMP, title, key, *len);
return 0;
}
@@ -1387,7 +1596,7 @@
if (value == NULL)
return NULL;
res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->go_p2p_dev_addr));
- if (res < 0 || res >= 20) {
+ if (os_snprintf_error(20, res)) {
os_free(value);
return NULL;
}
@@ -1401,53 +1610,10 @@
struct wpa_ssid *ssid, int line,
const char *value)
{
- const char *pos;
- u8 *buf, *n, addr[ETH_ALEN];
- size_t count;
-
- buf = NULL;
- count = 0;
-
- pos = value;
- while (pos && *pos) {
- while (*pos == ' ')
- pos++;
-
- if (hwaddr_aton(pos, addr)) {
- if (count == 0) {
- wpa_printf(MSG_ERROR, "Line %d: Invalid "
- "p2p_client_list address '%s'.",
- line, value);
- os_free(buf);
- return -1;
- }
- /* continue anyway since this could have been from a
- * truncated configuration file line */
- wpa_printf(MSG_INFO, "Line %d: Ignore likely "
- "truncated p2p_client_list address '%s'",
- line, pos);
- } else {
- n = os_realloc_array(buf, count + 1, ETH_ALEN);
- if (n == NULL) {
- os_free(buf);
- return -1;
- }
- buf = n;
- os_memmove(buf + ETH_ALEN, buf, count * ETH_ALEN);
- os_memcpy(buf, addr, ETH_ALEN);
- count++;
- wpa_hexdump(MSG_MSGDUMP, "p2p_client_list",
- addr, ETH_ALEN);
- }
-
- pos = os_strchr(pos, ' ');
- }
-
- os_free(ssid->p2p_client_list);
- ssid->p2p_client_list = buf;
- ssid->num_p2p_clients = count;
-
- return 0;
+ return wpa_config_parse_addr_list(data, line, value,
+ &ssid->p2p_client_list,
+ &ssid->num_p2p_clients,
+ "p2p_client_list", 0, 0);
}
@@ -1455,34 +1621,9 @@
static char * wpa_config_write_p2p_client_list(const struct parse_data *data,
struct wpa_ssid *ssid)
{
- char *value, *end, *pos;
- int res;
- size_t i;
-
- if (ssid->p2p_client_list == NULL || ssid->num_p2p_clients == 0)
- return NULL;
-
- value = os_malloc(20 * ssid->num_p2p_clients);
- if (value == NULL)
- return NULL;
- pos = value;
- end = value + 20 * ssid->num_p2p_clients;
-
- for (i = ssid->num_p2p_clients; i > 0; i--) {
- res = os_snprintf(pos, end - pos, MACSTR " ",
- MAC2STR(ssid->p2p_client_list +
- (i - 1) * ETH_ALEN));
- if (res < 0 || res >= end - pos) {
- os_free(value);
- return NULL;
- }
- pos += res;
- }
-
- if (pos > value)
- pos[-1] = '\0';
-
- return value;
+ return wpa_config_write_addr_list(data, ssid->p2p_client_list,
+ ssid->num_p2p_clients,
+ "p2p_client_list");
}
#endif /* NO_CONFIG_WRITE */
@@ -1542,6 +1683,45 @@
#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_MESH
+
+static int wpa_config_parse_mesh_basic_rates(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ int *rates = wpa_config_parse_int_array(value);
+
+ if (rates == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid mesh_basic_rates '%s'",
+ line, value);
+ return -1;
+ }
+ if (rates[0] == 0) {
+ os_free(rates);
+ rates = NULL;
+ }
+
+ os_free(ssid->mesh_basic_rates);
+ ssid->mesh_basic_rates = rates;
+
+ return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+
+static char * wpa_config_write_mesh_basic_rates(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ return wpa_config_write_freqs(data, ssid->mesh_basic_rates);
+}
+
+#endif /* NO_CONFIG_WRITE */
+
+#endif /* CONFIG_MESH */
+
+
/* Helper macros for network block parser */
#ifdef OFFSET
@@ -1633,6 +1813,8 @@
{ STR_RANGE(ssid, 0, MAX_SSID_LEN) },
{ INT_RANGE(scan_ssid, 0, 1) },
{ FUNC(bssid) },
+ { FUNC(bssid_blacklist) },
+ { FUNC(bssid_whitelist) },
{ FUNC_KEY(psk) },
{ FUNC(proto) },
{ FUNC(key_mgmt) },
@@ -1656,6 +1838,7 @@
{ STRe(subject_match) },
{ STRe(altsubject_match) },
{ STRe(domain_suffix_match) },
+ { STRe(domain_match) },
{ STRe(ca_cert2) },
{ STRe(ca_path2) },
{ STRe(client_cert2) },
@@ -1665,6 +1848,7 @@
{ STRe(subject_match2) },
{ STRe(altsubject_match2) },
{ STRe(domain_suffix_match2) },
+ { STRe(domain_match2) },
{ STRe(phase1) },
{ STRe(phase2) },
{ STRe(pcsc) },
@@ -1682,6 +1866,8 @@
{ INTe(engine2) },
{ INT(eapol_flags) },
{ INTe(sim_num) },
+ { STRe(openssl_ciphers) },
+ { INTe(erp) },
#endif /* IEEE8021X_EAPOL */
{ FUNC_KEY(wep_key0) },
{ FUNC_KEY(wep_key1) },
@@ -1695,7 +1881,12 @@
{ INTe(fragment_size) },
{ INTe(ocsp) },
#endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_MESH
+ { INT_RANGE(mode, 0, 5) },
+ { INT_RANGE(no_auto_peer, 0, 1) },
+#else /* CONFIG_MESH */
{ INT_RANGE(mode, 0, 4) },
+#endif /* CONFIG_MESH */
{ INT_RANGE(proactive_key_caching, 0, 1) },
{ INT_RANGE(disabled, 0, 2) },
{ STR(id_str) },
@@ -1705,6 +1896,13 @@
{ INT_RANGE(peerkey, 0, 1) },
{ INT_RANGE(mixed_cell, 0, 1) },
{ INT_RANGE(frequency, 0, 65000) },
+#ifdef CONFIG_MESH
+ { FUNC(mesh_basic_rates) },
+ { INT(dot11MeshMaxRetries) },
+ { INT(dot11MeshRetryTimeout) },
+ { INT(dot11MeshConfirmTimeout) },
+ { INT(dot11MeshHoldingTimeout) },
+#endif /* CONFIG_MESH */
{ INT(wpa_ptk_rekey) },
{ STR(bgscan) },
{ INT_RANGE(ignore_broadcast_ssid, 0, 2) },
@@ -1876,6 +2074,7 @@
os_free(eap->subject_match);
os_free(eap->altsubject_match);
os_free(eap->domain_suffix_match);
+ os_free(eap->domain_match);
os_free(eap->ca_cert2);
os_free(eap->ca_path2);
os_free(eap->client_cert2);
@@ -1885,6 +2084,7 @@
os_free(eap->subject_match2);
os_free(eap->altsubject_match2);
os_free(eap->domain_suffix_match2);
+ os_free(eap->domain_match2);
os_free(eap->phase1);
os_free(eap->phase2);
os_free(eap->pcsc);
@@ -1903,6 +2103,7 @@
os_free(eap->pac_file);
bin_clear_free(eap->new_password, eap->new_password_len);
str_clear_free(eap->external_sim_resp);
+ os_free(eap->openssl_ciphers);
}
#endif /* IEEE8021X_EAPOL */
@@ -1919,7 +2120,6 @@
struct psk_list_entry *psk;
os_free(ssid->ssid);
- os_memset(ssid->psk, 0, sizeof(ssid->psk));
str_clear_free(ssid->passphrase);
os_free(ssid->ext_psk);
#ifdef IEEE8021X_EAPOL
@@ -1930,15 +2130,20 @@
os_free(ssid->freq_list);
os_free(ssid->bgscan);
os_free(ssid->p2p_client_list);
+ os_free(ssid->bssid_blacklist);
+ os_free(ssid->bssid_whitelist);
#ifdef CONFIG_HT_OVERRIDES
os_free(ssid->ht_mcs);
#endif /* CONFIG_HT_OVERRIDES */
+#ifdef CONFIG_MESH
+ os_free(ssid->mesh_basic_rates);
+#endif /* CONFIG_MESH */
while ((psk = dl_list_first(&ssid->psk_list, struct psk_list_entry,
list))) {
dl_list_del(&psk->list);
- os_free(psk);
+ bin_clear_free(psk, sizeof(*psk));
}
- os_free(ssid);
+ bin_clear_free(ssid, sizeof(*ssid));
}
@@ -2000,6 +2205,7 @@
{
struct wpa_ssid *ssid, *prev = NULL;
struct wpa_cred *cred, *cprev;
+ int i;
ssid = config->ssid;
while (ssid) {
@@ -2018,11 +2224,14 @@
wpa_config_flush_blobs(config);
wpabuf_free(config->wps_vendor_ext_m1);
+ for (i = 0; i < MAX_WPS_VENDOR_EXT; i++)
+ wpabuf_free(config->wps_vendor_ext[i]);
os_free(config->ctrl_interface);
os_free(config->ctrl_interface_group);
os_free(config->opensc_engine_path);
os_free(config->pkcs11_engine_path);
os_free(config->pkcs11_module_path);
+ os_free(config->openssl_ciphers);
os_free(config->pcsc_reader);
str_clear_free(config->pcsc_pin);
os_free(config->driver_param);
@@ -2045,6 +2254,7 @@
os_free(config->sae_groups);
wpabuf_free(config->ap_vendor_elements);
os_free(config->osu_dir);
+ os_free(config->bgscan);
os_free(config->wowlan_triggers);
os_free(config);
}
@@ -2181,6 +2391,12 @@
ssid->eap.fragment_size = DEFAULT_FRAGMENT_SIZE;
ssid->eap.sim_num = DEFAULT_USER_SELECTED_SIM;
#endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_MESH
+ ssid->dot11MeshMaxRetries = DEFAULT_MESH_MAX_RETRIES;
+ ssid->dot11MeshRetryTimeout = DEFAULT_MESH_RETRY_TIMEOUT;
+ ssid->dot11MeshConfirmTimeout = DEFAULT_MESH_CONFIRM_TIMEOUT;
+ ssid->dot11MeshHoldingTimeout = DEFAULT_MESH_HOLDING_TIMEOUT;
+#endif /* CONFIG_MESH */
#ifdef CONFIG_HT_OVERRIDES
ssid->disable_ht = DEFAULT_DISABLE_HT;
ssid->disable_ht40 = DEFAULT_DISABLE_HT40;
@@ -2831,12 +3047,18 @@
static char * alloc_int_str(int val)
{
+ const unsigned int bufsize = 20;
char *buf;
+ int res;
- buf = os_malloc(20);
+ buf = os_malloc(bufsize);
if (buf == NULL)
return NULL;
- os_snprintf(buf, 20, "%d", val);
+ res = os_snprintf(buf, bufsize, "%d", val);
+ if (os_snprintf_error(bufsize, res)) {
+ os_free(buf);
+ buf = NULL;
+ }
return buf;
}
@@ -2907,7 +3129,7 @@
ret = os_snprintf(pos, end - pos, "%s%u",
i > 0 ? "\n" : "",
cred->req_conn_capab_proto[i]);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return buf;
pos += ret;
@@ -2919,7 +3141,7 @@
"%s%d",
j > 0 ? "," : ":",
ports[j]);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return buf;
pos += ret;
}
@@ -2988,7 +3210,7 @@
for (i = 0; i < cred->num_domain; i++) {
ret = os_snprintf(pos, end - pos, "%s%s",
i > 0 ? "\n" : "", cred->domain[i]);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return buf;
pos += ret;
}
@@ -3053,7 +3275,7 @@
ret = os_snprintf(pos, end - pos, "%s%s",
i > 0 ? "\n" : "",
wpa_ssid_txt(e->ssid, e->ssid_len));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return buf;
pos += ret;
}
@@ -3083,7 +3305,7 @@
i > 0 ? "\n" : "",
p->fqdn, p->exact_match, p->priority,
p->country);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return buf;
pos += ret;
}
@@ -3273,6 +3495,9 @@
return NULL;
config->eapol_version = DEFAULT_EAPOL_VERSION;
config->ap_scan = DEFAULT_AP_SCAN;
+ config->user_mpm = DEFAULT_USER_MPM;
+ config->max_peer_links = DEFAULT_MAX_PEER_LINKS;
+ config->mesh_max_inactivity = DEFAULT_MESH_MAX_INACTIVITY;
config->fast_reauth = DEFAULT_FAST_REAUTH;
config->p2p_go_intent = DEFAULT_P2P_GO_INTENT;
config->p2p_intra_bss = DEFAULT_P2P_INTRA_BSS;
@@ -3290,6 +3515,8 @@
config->wmm_ac_params[3] = ac_vo;
config->p2p_search_delay = DEFAULT_P2P_SEARCH_DELAY;
config->rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME;
+ config->key_mgmt_offload = DEFAULT_KEY_MGMT_OFFLOAD;
+ config->cert_in_cb = DEFAULT_CERT_IN_CB;
if (ctrl_interface)
config->ctrl_interface = os_strdup(ctrl_interface);
@@ -3818,11 +4045,17 @@
#endif /* CONFIG_MACSEC */
{ INT(ap_scan), 0 },
{ FUNC(bgscan), 0 },
+#ifdef CONFIG_MESH
+ { INT(user_mpm), 0 },
+ { INT_RANGE(max_peer_links, 0, 255), 0 },
+ { INT(mesh_max_inactivity), 0 },
+#endif /* CONFIG_MESH */
{ INT(disable_scan_offload), 0 },
{ INT(fast_reauth), 0 },
{ STR(opensc_engine_path), 0 },
{ STR(pkcs11_engine_path), 0 },
{ STR(pkcs11_module_path), 0 },
+ { STR(openssl_ciphers), 0 },
{ STR(pcsc_reader), 0 },
{ STR(pcsc_pin), 0 },
{ INT(external_sim), 0 },
@@ -3915,6 +4148,8 @@
{ INT(mac_addr), 0 },
{ INT(rand_addr_lifetime), 0 },
{ INT(preassoc_mac_addr), 0 },
+ { INT(key_mgmt_offload), 0},
+ { INT(passive_scan), 0 },
};
#undef FUNC
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 3fd4192..6adf1eb 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -15,6 +15,9 @@
#else /* CONFIG_NO_SCAN_PROCESSING */
#define DEFAULT_AP_SCAN 1
#endif /* CONFIG_NO_SCAN_PROCESSING */
+#define DEFAULT_USER_MPM 1
+#define DEFAULT_MAX_PEER_LINKS 99
+#define DEFAULT_MESH_MAX_INACTIVITY 300
#define DEFAULT_FAST_REAUTH 1
#define DEFAULT_P2P_GO_INTENT 7
#define DEFAULT_P2P_INTRA_BSS 1
@@ -28,6 +31,8 @@
#define DEFAULT_SCAN_CUR_FREQ 0
#define DEFAULT_P2P_SEARCH_DELAY 500
#define DEFAULT_RAND_ADDR_LIFETIME 60
+#define DEFAULT_KEY_MGMT_OFFLOAD 1
+#define DEFAULT_CERT_IN_CB 1
#include "config_ssid.h"
#include "wps/wps.h"
@@ -163,7 +168,7 @@
* If set, this FQDN is used as a suffix match requirement for the AAA
* server certificate in SubjectAltName dNSName element(s). If a
* matching dNSName is found, this constraint is met. If no dNSName
- * values are present, this constraint is matched against SubjetName CN
+ * values are present, this constraint is matched against SubjectName CN
* using same suffix match comparison. Suffix match here means that the
* host/domain name is compared one label at a time starting from the
* top-level domain and all the labels in @domain_suffix_match shall be
@@ -517,6 +522,15 @@
char *pkcs11_module_path;
/**
+ * openssl_ciphers - OpenSSL cipher string
+ *
+ * This is an OpenSSL specific configuration option for configuring the
+ * default ciphers. If not set, "DEFAULT:!EXP:!LOW" is used as the
+ * default.
+ */
+ char *openssl_ciphers;
+
+ /**
* pcsc_reader - PC/SC reader name prefix
*
* If not %NULL, PC/SC reader with a name that matches this prefix is
@@ -1079,6 +1093,62 @@
* 2 = like 1, but maintain OUI (with local admin bit set)
*/
int preassoc_mac_addr;
+
+ /**
+ * key_mgmt_offload - Use key management offload
+ *
+ * Key management offload should be used if the device supports it.
+ * Key management offload is the capability of a device operating as
+ * a station to do the exchange necessary to establish temporal keys
+ * during initial RSN connection, after roaming, or during a PTK
+ * rekeying operation.
+ */
+ int key_mgmt_offload;
+
+ /**
+ * user_mpm - MPM residency
+ *
+ * 0: MPM lives in driver.
+ * 1: wpa_supplicant handles peering and station allocation.
+ *
+ * If AMPE or SAE is enabled, the MPM is always in userspace.
+ */
+ int user_mpm;
+
+ /**
+ * max_peer_links - Maximum number of peer links
+ *
+ * Maximum number of mesh peering currently maintained by the STA.
+ */
+ int max_peer_links;
+
+ /**
+ * cert_in_cb - Whether to include a peer certificate dump in events
+ *
+ * This controls whether peer certificates for authentication server and
+ * its certificate chain are included in EAP peer certificate events.
+ */
+ int cert_in_cb;
+
+ /**
+ * mesh_max_inactivity - Timeout in seconds to detect STA inactivity
+ *
+ * This timeout value is used in mesh STA to clean up inactive stations.
+ * By default: 300 seconds.
+ */
+ int mesh_max_inactivity;
+
+ /**
+ * passive_scan - Whether to force passive scan for network connection
+ *
+ * This parameter can be used to force only passive scanning to be used
+ * for network connection cases. It should be noted that this will slow
+ * down scan operations and reduce likelihood of finding the AP. In
+ * addition, some use cases will override this due to functional
+ * requirements, e.g., for finding an AP that uses hidden SSID
+ * (scan_ssid=1) or P2P device discovery.
+ */
+ int passive_scan;
};
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index ef909a1..b15207d 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -146,6 +146,15 @@
ssid->group_cipher &= ~WPA_CIPHER_CCMP;
}
+ if (ssid->mode == WPAS_MODE_MESH &&
+ (ssid->key_mgmt != WPA_KEY_MGMT_NONE &&
+ ssid->key_mgmt != WPA_KEY_MGMT_SAE)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: key_mgmt for mesh network should be open or SAE",
+ line);
+ errors++;
+ }
+
return errors;
}
@@ -602,7 +611,7 @@
int res;
res = os_snprintf(field, sizeof(field), "wep_key%d", idx);
- if (res < 0 || (size_t) res >= sizeof(field))
+ if (os_snprintf_error(sizeof(field), res))
return;
value = wpa_config_get(ssid, field);
if (value) {
@@ -685,6 +694,7 @@
STR(subject_match);
STR(altsubject_match);
STR(domain_suffix_match);
+ STR(domain_match);
STR(ca_cert2);
STR(ca_path2);
STR(client_cert2);
@@ -694,6 +704,7 @@
STR(subject_match2);
STR(altsubject_match2);
STR(domain_suffix_match2);
+ STR(domain_match2);
STR(phase1);
STR(phase2);
STR(pcsc);
@@ -710,6 +721,7 @@
INTe(engine);
INTe(engine2);
INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS);
+ INTe(erp);
#endif /* IEEE8021X_EAPOL */
for (i = 0; i < 4; i++)
write_wep_key(f, i, ssid);
@@ -746,6 +758,13 @@
INT(update_identifier);
#endif /* CONFIG_HS20 */
write_int(f, "mac_addr", ssid->mac_addr, -1);
+#ifdef CONFIG_MESH
+ STR(mesh_basic_rates);
+ INT_DEF(dot11MeshMaxRetries, DEFAULT_MESH_MAX_RETRIES);
+ INT_DEF(dot11MeshRetryTimeout, DEFAULT_MESH_RETRY_TIMEOUT);
+ INT_DEF(dot11MeshConfirmTimeout, DEFAULT_MESH_CONFIRM_TIMEOUT);
+ INT_DEF(dot11MeshHoldingTimeout, DEFAULT_MESH_HOLDING_TIMEOUT);
+#endif /* CONFIG_MESH */
#undef STR
#undef INT
@@ -941,6 +960,8 @@
if (config->pkcs11_module_path)
fprintf(f, "pkcs11_module_path=%s\n",
config->pkcs11_module_path);
+ if (config->openssl_ciphers)
+ fprintf(f, "openssl_ciphers=%s\n", config->openssl_ciphers);
if (config->pcsc_reader)
fprintf(f, "pcsc_reader=%s\n", config->pcsc_reader);
if (config->pcsc_pin)
@@ -1193,6 +1214,25 @@
if (config->preassoc_mac_addr)
fprintf(f, "preassoc_mac_addr=%d\n", config->preassoc_mac_addr);
+
+ if (config->key_mgmt_offload != DEFAULT_KEY_MGMT_OFFLOAD)
+ fprintf(f, "key_mgmt_offload=%u\n", config->key_mgmt_offload);
+
+ if (config->user_mpm != DEFAULT_USER_MPM)
+ fprintf(f, "user_mpm=%d\n", config->user_mpm);
+
+ if (config->max_peer_links != DEFAULT_MAX_PEER_LINKS)
+ fprintf(f, "max_peer_links=%d\n", config->max_peer_links);
+
+ if (config->cert_in_cb != DEFAULT_CERT_IN_CB)
+ fprintf(f, "cert_in_cb=%d\n", config->cert_in_cb);
+
+ if (config->mesh_max_inactivity != DEFAULT_MESH_MAX_INACTIVITY)
+ fprintf(f, "mesh_max_inactivity=%d\n",
+ config->mesh_max_inactivity);
+
+ if (config->passive_scan)
+ fprintf(f, "cert_in_cb=%d\n", config->passive_scan);
}
#endif /* CONFIG_NO_CONFIG_WRITE */
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index f50b2d4..f744895 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -27,6 +27,10 @@
#define DEFAULT_FRAGMENT_SIZE 1398
#define DEFAULT_BG_SCAN_PERIOD -1
+#define DEFAULT_MESH_MAX_RETRIES 2
+#define DEFAULT_MESH_RETRY_TIMEOUT 40
+#define DEFAULT_MESH_CONFIRM_TIMEOUT 40
+#define DEFAULT_MESH_HOLDING_TIMEOUT 40
#define DEFAULT_DISABLE_HT 0
#define DEFAULT_DISABLE_HT40 0
#define DEFAULT_DISABLE_SGI 0
@@ -128,6 +132,18 @@
u8 bssid[ETH_ALEN];
/**
+ * bssid_blacklist - List of inacceptable BSSIDs
+ */
+ u8 *bssid_blacklist;
+ size_t num_bssid_blacklist;
+
+ /**
+ * bssid_blacklist - List of acceptable BSSIDs
+ */
+ u8 *bssid_whitelist;
+ size_t num_bssid_whitelist;
+
+ /**
* bssid_set - Whether BSSID is configured for this network
*/
int bssid_set;
@@ -317,6 +333,8 @@
* 4 = P2P Group Formation (used internally; not in configuration
* files)
*
+ * 5 = Mesh
+ *
* Note: IBSS can only be used with key_mgmt NONE (plaintext and static
* WEP) and WPA-PSK (with proto=RSN). In addition, key_mgmt=WPA-NONE
* (fixed group key TKIP/CCMP) is available for backwards compatibility,
@@ -331,6 +349,7 @@
WPAS_MODE_AP = 2,
WPAS_MODE_P2P_GO = 3,
WPAS_MODE_P2P_GROUP_FORMATION = 4,
+ WPAS_MODE_MESH = 5,
} mode;
/**
@@ -400,6 +419,20 @@
*/
int frequency;
+ /**
+ * mesh_basic_rates - BSS Basic rate set for mesh network
+ *
+ */
+ int *mesh_basic_rates;
+
+ /**
+ * Mesh network plink parameters
+ */
+ int dot11MeshMaxRetries;
+ int dot11MeshRetryTimeout; /* msec */
+ int dot11MeshConfirmTimeout; /* msec */
+ int dot11MeshHoldingTimeout; /* msec */
+
int ht40;
int vht;
@@ -666,6 +699,14 @@
* followed).
*/
int mac_addr;
+
+ /**
+ * no_auto_peer - Do not automatically peer with compatible mesh peers
+ *
+ * When unset, the reception of a beacon from a another mesh peer in
+ * this MBSS will trigger a peering attempt.
+ */
+ int no_auto_peer;
};
#endif /* CONFIG_SSID_H */
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index a4c26e4..caa480c 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -1,12 +1,16 @@
/*
* WPA Supplicant / Control interface (shared code for all backends)
- * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, 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"
+#ifdef CONFIG_TESTING_OPTIONS
+#include <net/ethernet.h>
+#include <netinet/ip.h>
+#endif /* CONFIG_TESTING_OPTIONS */
#include "utils/common.h"
#include "utils/eloop.h"
@@ -15,6 +19,8 @@
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
+#include "crypto/tls.h"
+#include "ap/hostapd.h"
#include "eap_peer/eap.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "rsn_supp/wpa.h"
@@ -42,6 +48,7 @@
#include "wnm_sta.h"
#include "offchannel.h"
#include "drivers/driver.h"
+#include "mesh.h"
static int wpa_supplicant_global_iface_list(struct wpa_global *global,
char *buf, int len);
@@ -420,11 +427,32 @@
#ifdef CONFIG_TESTING_OPTIONS
} else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) {
wpa_s->ext_mgmt_frame_handling = !!atoi(value);
+ } else if (os_strcasecmp(cmd, "ext_eapol_frame_io") == 0) {
+ wpa_s->ext_eapol_frame_io = !!atoi(value);
+#ifdef CONFIG_AP
+ if (wpa_s->ap_iface) {
+ wpa_s->ap_iface->bss[0]->ext_eapol_frame_io =
+ wpa_s->ext_eapol_frame_io;
+ }
+#endif /* CONFIG_AP */
+ } else if (os_strcasecmp(cmd, "extra_roc_dur") == 0) {
+ wpa_s->extra_roc_dur = atoi(value);
+ } else if (os_strcasecmp(cmd, "test_failure") == 0) {
+ wpa_s->test_failure = atoi(value);
#endif /* CONFIG_TESTING_OPTIONS */
#ifndef CONFIG_NO_CONFIG_BLOBS
} else if (os_strcmp(cmd, "blob") == 0) {
ret = wpas_ctrl_set_blob(wpa_s, value);
#endif /* CONFIG_NO_CONFIG_BLOBS */
+ } else if (os_strcasecmp(cmd, "setband") == 0) {
+ if (os_strcmp(value, "AUTO") == 0)
+ wpa_s->setband = WPA_SETBAND_AUTO;
+ else if (os_strcmp(value, "5G") == 0)
+ wpa_s->setband = WPA_SETBAND_5G;
+ else if (os_strcmp(value, "2G") == 0)
+ wpa_s->setband = WPA_SETBAND_2G;
+ else
+ ret = -1;
} else {
value[-1] = '=';
ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
@@ -459,9 +487,6 @@
else
enabled = wpa_s->global->wifi_display;
res = os_snprintf(buf, buflen, "%d", enabled);
- if (res < 0 || (unsigned int) res >= buflen)
- return -1;
- return res;
#endif /* CONFIG_WIFI_DISPLAY */
#ifdef CONFIG_TESTING_GET_GTK
} else if (os_strcmp(cmd, "gtk") == 0) {
@@ -471,9 +496,11 @@
wpa_s->last_gtk_len);
return res;
#endif /* CONFIG_TESTING_GET_GTK */
+ } else if (os_strcmp(cmd, "tls_library") == 0) {
+ res = tls_get_library_version(buf, buflen);
}
- if (res < 0 || (unsigned int) res >= buflen)
+ if (os_snprintf_error(buflen, res))
return -1;
return res;
}
@@ -626,14 +653,162 @@
(wpa_s->drv_flags &
WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP ?
"EXTERNAL" : "INTERNAL") : "UNSUPPORTED");
- if (ret < 0 || (size_t) ret > buflen)
+ if (os_snprintf_error(buflen, ret))
return -1;
return ret;
}
+
+static int wpa_supplicant_ctrl_iface_tdls_chan_switch(
+ struct wpa_supplicant *wpa_s, char *cmd)
+{
+ u8 peer[ETH_ALEN];
+ struct hostapd_freq_params freq_params;
+ u8 oper_class;
+ char *pos, *end;
+
+ if (!wpa_tdls_is_external_setup(wpa_s->wpa)) {
+ wpa_printf(MSG_INFO,
+ "tdls_chanswitch: Only supported with external setup");
+ return -1;
+ }
+
+ os_memset(&freq_params, 0, sizeof(freq_params));
+
+ pos = os_strchr(cmd, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ oper_class = strtol(pos, &end, 10);
+ if (pos == end) {
+ wpa_printf(MSG_INFO,
+ "tdls_chanswitch: Invalid op class provided");
+ return -1;
+ }
+
+ pos = end;
+ freq_params.freq = atoi(pos);
+ if (freq_params.freq == 0) {
+ wpa_printf(MSG_INFO, "tdls_chanswitch: Invalid freq provided");
+ return -1;
+ }
+
+#define SET_FREQ_SETTING(str) \
+ do { \
+ const char *pos2 = os_strstr(pos, " " #str "="); \
+ if (pos2) { \
+ pos2 += sizeof(" " #str "=") - 1; \
+ freq_params.str = atoi(pos2); \
+ } \
+ } while (0)
+
+ SET_FREQ_SETTING(center_freq1);
+ SET_FREQ_SETTING(center_freq2);
+ SET_FREQ_SETTING(bandwidth);
+ SET_FREQ_SETTING(sec_channel_offset);
+#undef SET_FREQ_SETTING
+
+ freq_params.ht_enabled = !!os_strstr(pos, " ht");
+ freq_params.vht_enabled = !!os_strstr(pos, " vht");
+
+ if (hwaddr_aton(cmd, peer)) {
+ wpa_printf(MSG_DEBUG,
+ "CTRL_IFACE TDLS_CHAN_SWITCH: Invalid address '%s'",
+ cmd);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_CHAN_SWITCH " MACSTR
+ " OP CLASS %d FREQ %d CENTER1 %d CENTER2 %d BW %d SEC_OFFSET %d%s%s",
+ MAC2STR(peer), oper_class, freq_params.freq,
+ freq_params.center_freq1, freq_params.center_freq2,
+ freq_params.bandwidth, freq_params.sec_channel_offset,
+ freq_params.ht_enabled ? " HT" : "",
+ freq_params.vht_enabled ? " VHT" : "");
+
+ return wpa_tdls_enable_chan_switch(wpa_s->wpa, peer, oper_class,
+ &freq_params);
+}
+
+
+static int wpa_supplicant_ctrl_iface_tdls_cancel_chan_switch(
+ struct wpa_supplicant *wpa_s, char *cmd)
+{
+ u8 peer[ETH_ALEN];
+
+ if (!wpa_tdls_is_external_setup(wpa_s->wpa)) {
+ wpa_printf(MSG_INFO,
+ "tdls_chanswitch: Only supported with external setup");
+ return -1;
+ }
+
+ if (hwaddr_aton(cmd, peer)) {
+ wpa_printf(MSG_DEBUG,
+ "CTRL_IFACE TDLS_CANCEL_CHAN_SWITCH: Invalid address '%s'",
+ cmd);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_CANCEL_CHAN_SWITCH " MACSTR,
+ MAC2STR(peer));
+
+ return wpa_tdls_disable_chan_switch(wpa_s->wpa, peer);
+}
+
#endif /* CONFIG_TDLS */
+static int wmm_ac_ctrl_addts(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ char *token, *context = NULL;
+ struct wmm_ac_ts_setup_params params = {
+ .tsid = 0xff,
+ .direction = 0xff,
+ };
+
+ while ((token = str_token(cmd, " ", &context))) {
+ if (sscanf(token, "tsid=%i", ¶ms.tsid) == 1 ||
+ sscanf(token, "up=%i", ¶ms.user_priority) == 1 ||
+ sscanf(token, "nominal_msdu_size=%i",
+ ¶ms.nominal_msdu_size) == 1 ||
+ sscanf(token, "mean_data_rate=%i",
+ ¶ms.mean_data_rate) == 1 ||
+ sscanf(token, "min_phy_rate=%i",
+ ¶ms.minimum_phy_rate) == 1 ||
+ sscanf(token, "sba=%i",
+ ¶ms.surplus_bandwidth_allowance) == 1)
+ continue;
+
+ if (os_strcasecmp(token, "downlink") == 0) {
+ params.direction = WMM_TSPEC_DIRECTION_DOWNLINK;
+ } else if (os_strcasecmp(token, "uplink") == 0) {
+ params.direction = WMM_TSPEC_DIRECTION_UPLINK;
+ } else if (os_strcasecmp(token, "bidi") == 0) {
+ params.direction = WMM_TSPEC_DIRECTION_BI_DIRECTIONAL;
+ } else if (os_strcasecmp(token, "fixed_nominal_msdu") == 0) {
+ params.fixed_nominal_msdu = 1;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "CTRL: Invalid WMM_AC_ADDTS parameter: '%s'",
+ token);
+ return -1;
+ }
+
+ }
+
+ return wpas_wmm_ac_addts(wpa_s, ¶ms);
+}
+
+
+static int wmm_ac_ctrl_delts(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ u8 tsid = atoi(cmd);
+
+ return wpas_wmm_ac_delts(wpa_s, tsid);
+}
+
+
#ifdef CONFIG_IEEE80211R
static int wpa_supplicant_ctrl_iface_ft_ds(
struct wpa_supplicant *wpa_s, char *addr)
@@ -747,7 +922,7 @@
if (ret < 0)
return -1;
ret = os_snprintf(buf, buflen, "%s", pin);
- if (ret < 0 || (size_t) ret >= buflen)
+ if (os_snprintf_error(buflen, ret))
return -1;
return ret;
}
@@ -759,7 +934,7 @@
done:
/* Return the generated PIN */
ret = os_snprintf(buf, buflen, "%08d", ret);
- if (ret < 0 || (size_t) ret >= buflen)
+ if (os_snprintf_error(buflen, ret))
return -1;
return ret;
}
@@ -796,14 +971,14 @@
if (!wps_pin_valid(pin_val)) {
wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
- if (ret < 0 || (size_t) ret >= buflen)
+ if (os_snprintf_error(buflen, ret))
return -1;
return ret;
}
}
ret = os_snprintf(buf, buflen, "%s", pin);
- if (ret < 0 || (size_t) ret >= buflen)
+ if (os_snprintf_error(buflen, ret))
return -1;
return ret;
@@ -1537,12 +1712,12 @@
struct wpa_ssid *ssid = wpa_s->current_ssid;
ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
MAC2STR(wpa_s->bssid));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
ret = os_snprintf(pos, end - pos, "freq=%u\n",
wpa_s->assoc_freq);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
if (ssid) {
@@ -1560,7 +1735,7 @@
ret = os_snprintf(pos, end - pos, "ssid=%s\nid=%d\n",
wpa_ssid_txt(_ssid, ssid_len),
ssid->id);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -1571,7 +1746,7 @@
ret = os_snprintf(pos, end - pos,
"passphrase=%s\n",
ssid->passphrase);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -1579,7 +1754,7 @@
ret = os_snprintf(pos, end - pos,
"id_str=%s\n",
ssid->id_str);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -1610,7 +1785,7 @@
ret = 0;
break;
}
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -1632,21 +1807,21 @@
wpa_s->sme.sae.state == SAE_ACCEPTED) {
ret = os_snprintf(pos, end - pos, "sae_group=%d\n",
wpa_s->sme.sae.group);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
#endif /* CONFIG_SAE */
ret = os_snprintf(pos, end - pos, "wpa_state=%s\n",
wpa_supplicant_state_txt(wpa_s->wpa_state));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
if (wpa_s->l2 &&
l2_packet_get_ip_addr(wpa_s->l2, tmp, sizeof(tmp)) >= 0) {
ret = os_snprintf(pos, end - pos, "ip_address=%s\n", tmp);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -1655,7 +1830,7 @@
if (wpa_s->global->p2p) {
ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR
"\n", MAC2STR(wpa_s->global->p2p_dev_addr));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -1663,7 +1838,7 @@
ret = os_snprintf(pos, end - pos, "address=" MACSTR "\n",
MAC2STR(wpa_s->own_addr));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -1679,7 +1854,7 @@
release = rel_num + 1;
}
ret = os_snprintf(pos, end - pos, "hs20=%d\n", release);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -1698,7 +1873,7 @@
ret = os_snprintf(pos, end - pos,
"provisioning_sp=%s\n",
cred->provisioning_sp);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -1721,7 +1896,7 @@
}
ret = os_snprintf(pos, end - pos, "home_sp=%s\n",
cred->domain[i]);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -1741,7 +1916,7 @@
type = "unknown";
ret = os_snprintf(pos, end - pos, "sp_type=%s\n", type);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -1767,7 +1942,7 @@
char uuid_str[100];
uuid_bin2str(wpa_s->wps->uuid, uuid_str, sizeof(uuid_str));
ret = os_snprintf(pos, end - pos, "uuid=%s\n", uuid_str);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -1855,7 +2030,7 @@
while (e) {
ret = os_snprintf(pos, end - pos, MACSTR "\n",
MAC2STR(e->bssid));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
e = e->next;
@@ -1937,10 +2112,6 @@
char *pos, *end, *stamp;
int ret;
- if (cmd == NULL) {
- return -1;
- }
-
/* cmd: "LOG_LEVEL [<level>]" */
if (*cmd == '\0') {
pos = buf;
@@ -1949,7 +2120,7 @@
"Timestamp: %d\n",
debug_level_str(wpa_debug_level),
wpa_debug_timestamp);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
ret = 0;
return ret;
@@ -1992,7 +2163,7 @@
end = buf + buflen;
ret = os_snprintf(pos, end - pos,
"network id / ssid / bssid / flags\n");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -2013,7 +2184,7 @@
ret = os_snprintf(pos, end - pos, "%d\t%s",
ssid->id,
wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return prev - buf;
pos += ret;
if (ssid->bssid_set) {
@@ -2022,7 +2193,7 @@
} else {
ret = os_snprintf(pos, end - pos, "\tany");
}
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return prev - buf;
pos += ret;
ret = os_snprintf(pos, end - pos, "\t%s%s%s%s",
@@ -2033,11 +2204,11 @@
"[TEMP-DISABLED]" : "",
ssid->disabled == 2 ? "[P2P-PERSISTENT]" :
"");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return prev - buf;
pos += ret;
ret = os_snprintf(pos, end - pos, "\n");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return prev - buf;
pos += ret;
@@ -2052,7 +2223,7 @@
{
int ret;
ret = os_snprintf(pos, end - pos, "-");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos;
pos += ret;
ret = wpa_write_ciphers(pos, end, cipher, "+");
@@ -2071,13 +2242,13 @@
int ret;
ret = os_snprintf(pos, end - pos, "[%s-", proto);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos;
pos += ret;
if (wpa_parse_wpa_ie(ie, ie_len, &data) < 0) {
ret = os_snprintf(pos, end - pos, "?]");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos;
pos += ret;
return pos;
@@ -2087,21 +2258,28 @@
if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
ret = os_snprintf(pos, end - pos, "%sEAP",
pos == start ? "" : "+");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos;
pos += ret;
}
if (data.key_mgmt & WPA_KEY_MGMT_PSK) {
ret = os_snprintf(pos, end - pos, "%sPSK",
pos == start ? "" : "+");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos;
pos += ret;
}
if (data.key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
ret = os_snprintf(pos, end - pos, "%sNone",
pos == start ? "" : "+");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
+ return pos;
+ pos += ret;
+ }
+ if (data.key_mgmt & WPA_KEY_MGMT_SAE) {
+ ret = os_snprintf(pos, end - pos, "%sSAE",
+ pos == start ? "" : "+");
+ if (os_snprintf_error(end - pos, ret))
return pos;
pos += ret;
}
@@ -2109,14 +2287,21 @@
if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
ret = os_snprintf(pos, end - pos, "%sFT/EAP",
pos == start ? "" : "+");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos;
pos += ret;
}
if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK) {
ret = os_snprintf(pos, end - pos, "%sFT/PSK",
pos == start ? "" : "+");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
+ return pos;
+ pos += ret;
+ }
+ if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE) {
+ ret = os_snprintf(pos, end - pos, "%sFT/SAE",
+ pos == start ? "" : "+");
+ if (os_snprintf_error(end - pos, ret))
return pos;
pos += ret;
}
@@ -2125,30 +2310,50 @@
if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
ret = os_snprintf(pos, end - pos, "%sEAP-SHA256",
pos == start ? "" : "+");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos;
pos += ret;
}
if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
ret = os_snprintf(pos, end - pos, "%sPSK-SHA256",
pos == start ? "" : "+");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos;
pos += ret;
}
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SUITEB
+ if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
+ ret = os_snprintf(pos, end - pos, "%sEAP-SUITE-B",
+ pos == start ? "" : "+");
+ if (os_snprintf_error(end - pos, ret))
+ return pos;
+ pos += ret;
+ }
+#endif /* CONFIG_SUITEB */
+
+#ifdef CONFIG_SUITEB192
+ if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
+ ret = os_snprintf(pos, end - pos, "%sEAP-SUITE-B-192",
+ pos == start ? "" : "+");
+ if (os_snprintf_error(end - pos, ret))
+ return pos;
+ pos += ret;
+ }
+#endif /* CONFIG_SUITEB192 */
+
pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher);
if (data.capabilities & WPA_CAPABILITY_PREAUTH) {
ret = os_snprintf(pos, end - pos, "-preauth");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos;
pos += ret;
}
ret = os_snprintf(pos, end - pos, "]");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos;
pos += ret;
@@ -2176,7 +2381,7 @@
txt = "[WPS]";
ret = os_snprintf(pos, end - pos, "%s", txt);
- if (ret >= 0 && ret < end - pos)
+ if (!os_snprintf_error(end - pos, ret))
pos += ret;
wpabuf_free(wps_ie);
return pos;
@@ -2205,8 +2410,9 @@
{
char *pos, *end;
int ret;
- const u8 *ie, *ie2, *p2p;
+ const u8 *ie, *ie2, *p2p, *mesh;
+ mesh = wpa_bss_get_ie(bss, WLAN_EID_MESH_ID);
p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
if (!p2p)
p2p = wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE);
@@ -2220,26 +2426,34 @@
ret = os_snprintf(pos, end - pos, MACSTR "\t%d\t%d\t",
MAC2STR(bss->bssid), bss->freq, bss->level);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
if (ie)
pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]);
ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
- if (ie2)
- pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]);
+ if (ie2) {
+ pos = wpa_supplicant_ie_txt(pos, end, mesh ? "RSN" : "WPA2",
+ ie2, 2 + ie2[1]);
+ }
pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
ret = os_snprintf(pos, end - pos, "[WEP]");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+ if (mesh) {
+ ret = os_snprintf(pos, end - pos, "[MESH]");
+ if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
}
if (bss_is_dmg(bss)) {
const char *s;
ret = os_snprintf(pos, end - pos, "[DMG]");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
switch (bss->caps & IEEE80211_CAP_DMG_MASK) {
@@ -2257,33 +2471,33 @@
break;
}
ret = os_snprintf(pos, end - pos, "%s", s);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
} else {
if (bss->caps & IEEE80211_CAP_IBSS) {
ret = os_snprintf(pos, end - pos, "[IBSS]");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
}
if (bss->caps & IEEE80211_CAP_ESS) {
ret = os_snprintf(pos, end - pos, "[ESS]");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
}
}
if (p2p) {
ret = os_snprintf(pos, end - pos, "[P2P]");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
}
#ifdef CONFIG_HS20
if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE) && ie2) {
ret = os_snprintf(pos, end - pos, "[HS20]");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
}
@@ -2291,12 +2505,12 @@
ret = os_snprintf(pos, end - pos, "\t%s",
wpa_ssid_txt(bss->ssid, bss->ssid_len));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
ret = os_snprintf(pos, end - pos, "\n");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
@@ -2315,7 +2529,7 @@
end = buf + buflen;
ret = os_snprintf(pos, end - pos, "bssid / frequency / signal level / "
"flags / ssid\n");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -2331,6 +2545,116 @@
}
+#ifdef CONFIG_MESH
+
+static int wpa_supplicant_ctrl_iface_mesh_interface_add(
+ struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
+{
+ char *pos, ifname[IFNAMSIZ + 1];
+
+ ifname[0] = '\0';
+
+ pos = os_strstr(cmd, "ifname=");
+ if (pos) {
+ pos += 7;
+ os_strlcpy(ifname, pos, sizeof(ifname));
+ }
+
+ if (wpas_mesh_add_interface(wpa_s, ifname, sizeof(ifname)) < 0)
+ return -1;
+
+ os_strlcpy(reply, ifname, max_len);
+ return os_strlen(ifname);
+}
+
+
+static int wpa_supplicant_ctrl_iface_mesh_group_add(
+ struct wpa_supplicant *wpa_s, char *cmd)
+{
+ int id;
+ struct wpa_ssid *ssid;
+
+ id = atoi(cmd);
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: MESH_GROUP_ADD id=%d", id);
+
+ ssid = wpa_config_get_network(wpa_s->conf, id);
+ if (ssid == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "CTRL_IFACE: Could not find network id=%d", id);
+ return -1;
+ }
+ if (ssid->mode != WPAS_MODE_MESH) {
+ wpa_printf(MSG_DEBUG,
+ "CTRL_IFACE: Cannot use MESH_GROUP_ADD on a non mesh network");
+ return -1;
+ }
+ if (ssid->key_mgmt != WPA_KEY_MGMT_NONE &&
+ ssid->key_mgmt != WPA_KEY_MGMT_SAE) {
+ wpa_printf(MSG_ERROR,
+ "CTRL_IFACE: key_mgmt for mesh network should be open or SAE");
+ return -1;
+ }
+
+ /*
+ * TODO: If necessary write our own group_add function,
+ * for now we can reuse select_network
+ */
+ wpa_supplicant_select_network(wpa_s, ssid);
+
+ return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_mesh_group_remove(
+ struct wpa_supplicant *wpa_s, char *cmd)
+{
+ struct wpa_supplicant *orig;
+ struct wpa_global *global;
+ int found = 0;
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: MESH_GROUP_REMOVE ifname=%s", cmd);
+
+ global = wpa_s->global;
+ orig = wpa_s;
+
+ for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ if (os_strcmp(wpa_s->ifname, cmd) == 0) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ wpa_printf(MSG_ERROR,
+ "CTRL_IFACE: MESH_GROUP_REMOVE ifname=%s not found",
+ cmd);
+ return -1;
+ }
+ if (wpa_s->mesh_if_created && wpa_s == orig) {
+ wpa_printf(MSG_ERROR,
+ "CTRL_IFACE: MESH_GROUP_REMOVE can't remove itself");
+ return -1;
+ }
+
+ wpa_s->reassociate = 0;
+ wpa_s->disconnected = 1;
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpa_supplicant_cancel_scan(wpa_s);
+
+ /*
+ * TODO: If necessary write our own group_remove function,
+ * for now we can reuse deauthenticate
+ */
+ wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+
+ if (wpa_s->mesh_if_created)
+ wpa_supplicant_remove_iface(global, wpa_s, 0);
+
+ return 0;
+}
+
+#endif /* CONFIG_MESH */
+
+
static int wpa_supplicant_ctrl_iface_select_network(
struct wpa_supplicant *wpa_s, char *cmd)
{
@@ -2463,7 +2787,7 @@
wpa_config_set_network_defaults(ssid);
ret = os_snprintf(buf, buflen, "%d\n", ssid->id);
- if (ret < 0 || (size_t) ret >= buflen)
+ if (os_snprintf_error(buflen, ret))
return -1;
return ret;
}
@@ -2586,6 +2910,8 @@
wpa_config_update_psk(ssid);
else if (os_strcmp(name, "priority") == 0)
wpa_config_update_prio_list(wpa_s->conf);
+ else if (os_strcmp(name, "no_auto_peer") == 0)
+ ssid->no_auto_peer = atoi(value);
return 0;
}
@@ -2712,7 +3038,7 @@
ssid_d = wpa_config_get_network(wpa_s->conf, id_d);
if (ssid_d == NULL) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
- "network id=%d", id_s);
+ "network id=%d", id_d);
return -1;
}
@@ -2743,7 +3069,7 @@
end = buf + buflen;
ret = os_snprintf(pos, end - pos,
"cred id / realm / username / domain / imsi\n");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -2754,7 +3080,7 @@
cred->username ? cred->username : "",
cred->domain ? cred->domain[0] : "",
cred->imsi ? cred->imsi : "");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -2780,7 +3106,7 @@
wpa_msg(wpa_s, MSG_INFO, CRED_ADDED "%d", cred->id);
ret = os_snprintf(buf, buflen, "%d\n", cred->id);
- if (ret < 0 || (size_t) ret >= buflen)
+ if (os_snprintf_error(buflen, ret))
return -1;
return ret;
}
@@ -2810,9 +3136,13 @@
ssid = wpa_s->conf->ssid;
while (ssid) {
if (ssid->parent_cred == cred) {
+ int res;
+
wpa_printf(MSG_DEBUG, "Remove network id %d since it "
"used the removed credential", ssid->id);
- os_snprintf(str, sizeof(str), "%d", ssid->id);
+ res = os_snprintf(str, sizeof(str), "%d", ssid->id);
+ if (os_snprintf_error(sizeof(str), res))
+ str[sizeof(str) - 1] = '\0';
ssid = ssid->next;
wpa_supplicant_ctrl_iface_remove_network(wpa_s, str);
} else
@@ -3015,6 +3345,13 @@
{ WPA_DRIVER_CAPA_ENC_WEP40, "WEP40", 1 }
};
+static const struct cipher_info ciphers_group_mgmt[] = {
+ { WPA_DRIVER_CAPA_ENC_BIP, "AES-128-CMAC", 1 },
+ { WPA_DRIVER_CAPA_ENC_BIP_GMAC_128, "BIP-GMAC-128", 1 },
+ { WPA_DRIVER_CAPA_ENC_BIP_GMAC_256, "BIP-GMAC-256", 1 },
+ { WPA_DRIVER_CAPA_ENC_BIP_CMAC_256, "BIP-CMAC-256", 1 },
+};
+
static int ctrl_iface_get_capability_pairwise(int res, char *strict,
struct wpa_driver_capa *capa,
@@ -3042,7 +3379,7 @@
ret = os_snprintf(pos, end - pos, "%s%s",
pos == buf ? "" : " ",
ciphers[i].name);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -3078,7 +3415,36 @@
ret = os_snprintf(pos, end - pos, "%s%s",
pos == buf ? "" : " ",
ciphers[i].name);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+ }
+
+ return pos - buf;
+}
+
+
+static int ctrl_iface_get_capability_group_mgmt(int res, char *strict,
+ struct wpa_driver_capa *capa,
+ char *buf, size_t buflen)
+{
+ int ret;
+ char *pos, *end;
+ unsigned int i;
+
+ pos = buf;
+ end = pos + buflen;
+
+ if (res < 0)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(ciphers_group_mgmt); i++) {
+ if (capa->enc & ciphers_group_mgmt[i].capa) {
+ ret = os_snprintf(pos, end - pos, "%s%s",
+ pos == buf ? "" : " ",
+ ciphers_group_mgmt[i].name);
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -3110,14 +3476,14 @@
}
ret = os_snprintf(pos, end - pos, "NONE IEEE8021X");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
ret = os_snprintf(pos, end - pos, " WPA-EAP");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -3125,18 +3491,35 @@
if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
ret = os_snprintf(pos, end - pos, " WPA-PSK");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
ret = os_snprintf(pos, end - pos, " WPA-NONE");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
+#ifdef CONFIG_SUITEB
+ if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B) {
+ ret = os_snprintf(pos, end - pos, " WPA-EAP-SUITE-B");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_SUITEB */
+#ifdef CONFIG_SUITEB192
+ if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192) {
+ ret = os_snprintf(pos, end - pos, " WPA-EAP-SUITE-B-192");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_SUITEB192 */
+
return pos - buf;
}
@@ -3165,7 +3548,7 @@
WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
ret = os_snprintf(pos, end - pos, "%sRSN",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -3174,7 +3557,7 @@
WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
ret = os_snprintf(pos, end - pos, "%sWPA",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -3183,7 +3566,8 @@
}
-static int ctrl_iface_get_capability_auth_alg(int res, char *strict,
+static int ctrl_iface_get_capability_auth_alg(struct wpa_supplicant *wpa_s,
+ int res, char *strict,
struct wpa_driver_capa *capa,
char *buf, size_t buflen)
{
@@ -3206,7 +3590,7 @@
if (capa->auth & (WPA_DRIVER_AUTH_OPEN)) {
ret = os_snprintf(pos, end - pos, "%sOPEN",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -3214,7 +3598,7 @@
if (capa->auth & (WPA_DRIVER_AUTH_SHARED)) {
ret = os_snprintf(pos, end - pos, "%sSHARED",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -3222,11 +3606,21 @@
if (capa->auth & (WPA_DRIVER_AUTH_LEAP)) {
ret = os_snprintf(pos, end - pos, "%sLEAP",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
+#ifdef CONFIG_SAE
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE) {
+ ret = os_snprintf(pos, end - pos, "%sSAE",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_SAE */
+
return pos - buf;
}
@@ -3254,7 +3648,7 @@
if (capa->flags & WPA_DRIVER_FLAGS_IBSS) {
ret = os_snprintf(pos, end - pos, "%sIBSS",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -3262,11 +3656,21 @@
if (capa->flags & WPA_DRIVER_FLAGS_AP) {
ret = os_snprintf(pos, end - pos, "%sAP",
pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
+#ifdef CONFIG_MESH
+ if (capa->flags & WPA_DRIVER_FLAGS_MESH) {
+ ret = os_snprintf(pos, end - pos, "%sMESH",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_MESH */
+
return pos - buf;
}
@@ -3299,7 +3703,7 @@
continue;
}
ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:", hmode);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
chnl = wpa_s->hw.modes[j].channels;
@@ -3307,12 +3711,12 @@
if (chnl[i].flag & HOSTAPD_CHAN_DISABLED)
continue;
ret = os_snprintf(pos, end - pos, " %d", chnl[i].chan);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
ret = os_snprintf(pos, end - pos, "\n");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -3350,7 +3754,7 @@
}
ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:\n",
hmode);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
chnl = wpa_s->hw.modes[j].channels;
@@ -3359,17 +3763,17 @@
continue;
ret = os_snprintf(pos, end - pos, " %d = %d MHz%s%s\n",
chnl[i].chan, chnl[i].freq,
- chnl[i].flag & HOSTAPD_CHAN_NO_IBSS ?
- " (NO_IBSS)" : "",
+ chnl[i].flag & HOSTAPD_CHAN_NO_IR ?
+ " (NO_IR)" : "",
chnl[i].flag & HOSTAPD_CHAN_RADAR ?
" (DFS)" : "");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
ret = os_snprintf(pos, end - pos, "\n");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -3416,6 +3820,10 @@
return ctrl_iface_get_capability_group(res, strict, &capa,
buf, buflen);
+ if (os_strcmp(field, "group_mgmt") == 0)
+ return ctrl_iface_get_capability_group_mgmt(res, strict, &capa,
+ buf, buflen);
+
if (os_strcmp(field, "key_mgmt") == 0)
return ctrl_iface_get_capability_key_mgmt(res, strict, &capa,
buf, buflen);
@@ -3425,8 +3833,8 @@
buf, buflen);
if (os_strcmp(field, "auth_alg") == 0)
- return ctrl_iface_get_capability_auth_alg(res, strict, &capa,
- buf, buflen);
+ return ctrl_iface_get_capability_auth_alg(wpa_s, res, strict,
+ &capa, buf, buflen);
if (os_strcmp(field, "modes") == 0)
return ctrl_iface_get_capability_modes(res, strict, &capa,
@@ -3443,6 +3851,15 @@
return ctrl_iface_get_capability_tdls(wpa_s, buf, buflen);
#endif /* CONFIG_TDLS */
+#ifdef CONFIG_ERP
+ if (os_strcmp(field, "erp") == 0) {
+ res = os_snprintf(buf, buflen, "ERP");
+ if (os_snprintf_error(buflen, res))
+ return -1;
+ return res;
+ }
+#endif /* CONFIG_EPR */
+
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
field);
@@ -3463,20 +3880,20 @@
return start;
ret = os_snprintf(pos, end - pos, "%s=", title);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return start;
pos += ret;
d = wpabuf_head_u8(data);
for (i = 0; i < wpabuf_len(data); i++) {
ret = os_snprintf(pos, end - pos, "%02x", *d++);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return start;
pos += ret;
}
ret = os_snprintf(pos, end - pos, "\n");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return start;
pos += ret;
@@ -3498,7 +3915,7 @@
if (mask & WPA_BSS_MASK_ID) {
ret = os_snprintf(pos, end - pos, "id=%u\n", bss->id);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
@@ -3506,14 +3923,14 @@
if (mask & WPA_BSS_MASK_BSSID) {
ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
MAC2STR(bss->bssid));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
if (mask & WPA_BSS_MASK_FREQ) {
ret = os_snprintf(pos, end - pos, "freq=%d\n", bss->freq);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
@@ -3521,7 +3938,7 @@
if (mask & WPA_BSS_MASK_BEACON_INT) {
ret = os_snprintf(pos, end - pos, "beacon_int=%d\n",
bss->beacon_int);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
@@ -3529,28 +3946,28 @@
if (mask & WPA_BSS_MASK_CAPABILITIES) {
ret = os_snprintf(pos, end - pos, "capabilities=0x%04x\n",
bss->caps);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
if (mask & WPA_BSS_MASK_QUAL) {
ret = os_snprintf(pos, end - pos, "qual=%d\n", bss->qual);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
if (mask & WPA_BSS_MASK_NOISE) {
ret = os_snprintf(pos, end - pos, "noise=%d\n", bss->noise);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
if (mask & WPA_BSS_MASK_LEVEL) {
ret = os_snprintf(pos, end - pos, "level=%d\n", bss->level);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
@@ -3558,7 +3975,7 @@
if (mask & WPA_BSS_MASK_TSF) {
ret = os_snprintf(pos, end - pos, "tsf=%016llu\n",
(unsigned long long) bss->tsf);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
@@ -3569,34 +3986,34 @@
os_get_reltime(&now);
ret = os_snprintf(pos, end - pos, "age=%d\n",
(int) (now.sec - bss->last_update.sec));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
if (mask & WPA_BSS_MASK_IE) {
ret = os_snprintf(pos, end - pos, "ie=");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
ie = (const u8 *) (bss + 1);
for (i = 0; i < bss->ie_len; i++) {
ret = os_snprintf(pos, end - pos, "%02x", *ie++);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
ret = os_snprintf(pos, end - pos, "\n");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
if (mask & WPA_BSS_MASK_FLAGS) {
ret = os_snprintf(pos, end - pos, "flags=");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
@@ -3611,14 +4028,14 @@
pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
ret = os_snprintf(pos, end - pos, "[WEP]");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
if (bss_is_dmg(bss)) {
const char *s;
ret = os_snprintf(pos, end - pos, "[DMG]");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
switch (bss->caps & IEEE80211_CAP_DMG_MASK) {
@@ -3636,19 +4053,19 @@
break;
}
ret = os_snprintf(pos, end - pos, "%s", s);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
} else {
if (bss->caps & IEEE80211_CAP_IBSS) {
ret = os_snprintf(pos, end - pos, "[IBSS]");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
if (bss->caps & IEEE80211_CAP_ESS) {
ret = os_snprintf(pos, end - pos, "[ESS]");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
@@ -3656,21 +4073,21 @@
if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) ||
wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) {
ret = os_snprintf(pos, end - pos, "[P2P]");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
#ifdef CONFIG_HS20
if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) {
ret = os_snprintf(pos, end - pos, "[HS20]");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
#endif /* CONFIG_HS20 */
ret = os_snprintf(pos, end - pos, "\n");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
@@ -3678,7 +4095,7 @@
if (mask & WPA_BSS_MASK_SSID) {
ret = os_snprintf(pos, end - pos, "ssid=%s\n",
wpa_ssid_txt(bss->ssid, bss->ssid_len));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
@@ -3711,7 +4128,7 @@
WFD_IE_VENDOR_TYPE);
if (wfd) {
ret = os_snprintf(pos, end - pos, "wfd_subelems=");
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
wpabuf_free(wfd);
return 0;
}
@@ -3723,7 +4140,7 @@
wpabuf_free(wfd);
ret = os_snprintf(pos, end - pos, "\n");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
@@ -3761,9 +4178,19 @@
}
#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_MESH
+ if (mask & WPA_BSS_MASK_MESH_SCAN) {
+ ie = (const u8 *) (bss + 1);
+ ret = wpas_mesh_scan_result_text(ie, bss->ie_len, pos, end);
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
+#endif /* CONFIG_MESH */
+
if (mask & WPA_BSS_MASK_DELIM) {
ret = os_snprintf(pos, end - pos, "====\n");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return 0;
pos += ret;
}
@@ -3783,7 +4210,7 @@
struct dl_list *next;
int ret = 0;
int len;
- char *ctmp;
+ char *ctmp, *end = buf + buflen;
unsigned long mask = WPA_BSS_MASK_ALL;
if (os_strncmp(cmd, "RANGE=", 6) == 0) {
@@ -3892,8 +4319,16 @@
if (bss == bsslast) {
if ((mask & WPA_BSS_MASK_DELIM) && len &&
(bss == dl_list_last(&wpa_s->bss_id,
- struct wpa_bss, list_id)))
- os_snprintf(buf - 5, 5, "####\n");
+ struct wpa_bss, list_id))) {
+ int res;
+
+ res = os_snprintf(buf - 5, end - buf + 5,
+ "####\n");
+ if (os_snprintf_error(end - buf + 5, res)) {
+ wpa_printf(MSG_DEBUG,
+ "Could not add end delim");
+ }
+ }
break;
}
next = bss->list_id.next;
@@ -3938,7 +4373,7 @@
}
-static int wpa_supplicant_ctrl_iface_bss_flush(
+static void wpa_supplicant_ctrl_iface_bss_flush(
struct wpa_supplicant *wpa_s, char *cmd)
{
int flush_age = atoi(cmd);
@@ -3947,7 +4382,6 @@
wpa_bss_flush(wpa_s);
else
wpa_bss_flush_by_age(wpa_s, flush_age);
- return 0;
}
@@ -4173,7 +4607,7 @@
return -1;
if (wps_method == WPS_PIN_DISPLAY && pin == NULL) {
ret = os_snprintf(buf, buflen, "%08d", new_pin);
- if (ret < 0 || (size_t) ret >= buflen)
+ if (os_snprintf_error(buflen, ret))
return -1;
return ret;
}
@@ -4288,7 +4722,7 @@
if (ref == 0)
return -1;
res = os_snprintf(buf, buflen, "%llx", (long long unsigned) ref);
- if (res < 0 || (unsigned) res >= buflen)
+ if (os_snprintf_error(buflen, res))
return -1;
return res;
}
@@ -4724,7 +5158,7 @@
info->dev_capab,
info->group_capab,
info->level);
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
@@ -4735,7 +5169,7 @@
res = os_snprintf(pos, end - pos, "sec_dev_type=%s\n",
wps_dev_type_bin2str(t, devtype,
sizeof(devtype)));
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
}
@@ -4743,7 +5177,7 @@
ssid = wpas_p2p_get_persistent(wpa_s, info->p2p_device_addr, NULL, 0);
if (ssid) {
res = os_snprintf(pos, end - pos, "persistent=%d\n", ssid->id);
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
}
@@ -4755,7 +5189,7 @@
if (info->vendor_elems) {
res = os_snprintf(pos, end - pos, "vendor_elems=");
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
@@ -4764,7 +5198,7 @@
wpabuf_len(info->vendor_elems));
res = os_snprintf(pos, end - pos, "\n");
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
}
@@ -5007,6 +5441,7 @@
{
os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
wpa_s->force_long_sd = 0;
+ wpas_p2p_stop_find(wpa_s);
if (wpa_s->global->p2p)
p2p_flush(wpa_s->global->p2p);
}
@@ -5162,6 +5597,27 @@
return -1;
}
+ if (bss->ssid_len == 0) {
+ int found = 0;
+
+ wpa_printf(MSG_DEBUG, "Selected BSS entry for " MACSTR
+ " does not have SSID information", MAC2STR(bssid));
+
+ dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss,
+ list) {
+ if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
+ bss->ssid_len > 0) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ return -1;
+ wpa_printf(MSG_DEBUG,
+ "Found another matching BSS entry with SSID");
+ }
+
return interworking_connect(wpa_s, bss);
}
@@ -5180,6 +5636,8 @@
if (used < 0)
return -1;
pos = dst + used;
+ if (*pos == ' ')
+ pos++;
while (num_id < MAX_ANQP_INFO_ID) {
if (os_strncmp(pos, "hs20:", 5) == 0) {
#ifdef CONFIG_HS20
@@ -5359,6 +5817,8 @@
if (used < 0)
return -1;
pos = dst + used;
+ if (*pos == ' ')
+ pos++;
for (;;) {
int num = atoi(pos);
if (num <= 0 || num > 31)
@@ -5471,14 +5931,6 @@
#endif /* CONFIG_HS20 */
-static int wpa_supplicant_ctrl_iface_sta_autoconnect(
- struct wpa_supplicant *wpa_s, char *cmd)
-{
- wpa_s->auto_reconnect_disabled = atoi(cmd) == 0 ? 1 : 0;
- return 0;
-}
-
-
#ifdef CONFIG_AUTOSCAN
static int wpa_supplicant_ctrl_iface_autoscan(struct wpa_supplicant *wpa_s,
@@ -5594,14 +6046,14 @@
"NOISE=%d\nFREQUENCY=%u\n",
si.current_signal, si.current_txrate / 1000,
si.current_noise, si.frequency);
- if (ret < 0 || ret > end - pos)
+ if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
if (si.chanwidth != CHAN_WIDTH_UNKNOWN) {
ret = os_snprintf(pos, end - pos, "WIDTH=%s\n",
channel_width_to_string(si.chanwidth));
- if (ret < 0 || ret > end - pos)
+ if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
}
@@ -5610,7 +6062,7 @@
ret = os_snprintf(pos, end - pos,
"CENTER_FRQ1=%d\nCENTER_FRQ2=%d\n",
si.center_frq1, si.center_frq2);
- if (ret < 0 || ret > end - pos)
+ if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
}
@@ -5618,7 +6070,7 @@
if (si.avg_signal) {
ret = os_snprintf(pos, end - pos,
"AVG_RSSI=%d\n", si.avg_signal);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
}
@@ -5639,7 +6091,7 @@
ret = os_snprintf(buf, buflen, "TXGOOD=%lu\nTXBAD=%lu\nRXGOOD=%lu\n",
sta.tx_packets, sta.tx_retry_failed, sta.rx_packets);
- if (ret < 0 || (size_t) ret > buflen)
+ if (os_snprintf_error(buflen, ret))
return -1;
return ret;
}
@@ -5664,6 +6116,8 @@
}
}
ret = os_snprintf(buf, buflen, "%s\n", "OK");
+ if (os_snprintf_error(buflen, ret))
+ ret = -1;
}
return ret;
}
@@ -5729,20 +6183,24 @@
static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
{
+#ifdef CONFIG_P2P
+ struct wpa_supplicant *p2p_wpa_s = wpa_s->global->p2p_init_wpa_s ?
+ wpa_s->global->p2p_init_wpa_s : wpa_s;
+#endif /* CONFIG_P2P */
+
wpa_dbg(wpa_s, MSG_DEBUG, "Flush all wpa_supplicant state");
#ifdef CONFIG_P2P
- wpas_p2p_cancel(wpa_s);
- wpas_p2p_stop_find(wpa_s);
- p2p_ctrl_flush(wpa_s);
- wpas_p2p_group_remove(wpa_s, "*");
- wpas_p2p_service_flush(wpa_s);
- wpa_s->global->p2p_disabled = 0;
- wpa_s->global->p2p_per_sta_psk = 0;
- wpa_s->conf->num_sec_device_types = 0;
- wpa_s->p2p_disable_ip_addr_req = 0;
- os_free(wpa_s->global->p2p_go_avoid_freq.range);
- wpa_s->global->p2p_go_avoid_freq.range = NULL;
+ wpas_p2p_cancel(p2p_wpa_s);
+ p2p_ctrl_flush(p2p_wpa_s);
+ wpas_p2p_group_remove(p2p_wpa_s, "*");
+ wpas_p2p_service_flush(p2p_wpa_s);
+ p2p_wpa_s->global->p2p_disabled = 0;
+ p2p_wpa_s->global->p2p_per_sta_psk = 0;
+ p2p_wpa_s->conf->num_sec_device_types = 0;
+ p2p_wpa_s->p2p_disable_ip_addr_req = 0;
+ os_free(p2p_wpa_s->global->p2p_go_avoid_freq.range);
+ p2p_wpa_s->global->p2p_go_avoid_freq.range = NULL;
#endif /* CONFIG_P2P */
#ifdef CONFIG_WPS_TESTING
@@ -5753,6 +6211,7 @@
#ifdef CONFIG_WPS
wpa_s->wps_fragment_size = 0;
wpas_wps_cancel(wpa_s);
+ wps_registrar_flush(wpa_s->wps->registrar);
#endif /* CONFIG_WPS */
wpa_s->after_wps = 0;
wpa_s->known_wps_freq = 0;
@@ -5782,8 +6241,6 @@
wpa_s->sta_uapsd = 0;
wpa_drv_radio_disable(wpa_s, 0);
-
- wpa_bss_flush(wpa_s);
wpa_blacklist_clear(wpa_s);
wpa_s->extra_blacklist_count = 0;
wpa_supplicant_ctrl_iface_remove_network(wpa_s, "all");
@@ -5792,12 +6249,16 @@
wpa_s->conf->auto_interworking = 0;
wpa_s->conf->okc = 0;
+ wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
+ rsn_preauth_deinit(wpa_s->wpa);
+
wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME, 43200);
wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD, 70);
wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, 60);
eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
radio_remove_works(wpa_s, NULL, 1);
+ wpa_s->ext_work_in_progress = 0;
wpa_s->next_ssid = NULL;
@@ -5806,6 +6267,25 @@
#endif /* CONFIG_INTERWORKING */
wpa_s->ext_mgmt_frame_handling = 0;
+ wpa_s->ext_eapol_frame_io = 0;
+#ifdef CONFIG_TESTING_OPTIONS
+ wpa_s->extra_roc_dur = 0;
+ wpa_s->test_failure = WPAS_TEST_FAILURE_NONE;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ wpa_s->disconnected = 0;
+ os_free(wpa_s->next_scan_freqs);
+ wpa_s->next_scan_freqs = NULL;
+
+ wpa_bss_flush(wpa_s);
+ if (!dl_list_empty(&wpa_s->bss)) {
+ wpa_printf(MSG_DEBUG,
+ "BSS table not empty after flush: %u entries, current_bss=%p bssid="
+ MACSTR " pending_bssid=" MACSTR,
+ dl_list_len(&wpa_s->bss), wpa_s->current_bss,
+ MAC2STR(wpa_s->bssid),
+ MAC2STR(wpa_s->pending_bssid));
+ }
}
@@ -5829,7 +6309,7 @@
ret = os_snprintf(pos, end - pos, "%s@%s:%u:%u:%ld.%06ld\n",
work->type, work->wpa_s->ifname, work->freq,
work->started, diff.sec, diff.usec);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
break;
pos += ret;
}
@@ -5847,6 +6327,7 @@
"Timing out external radio work %u (%s)",
ework->id, work->type);
wpa_msg(work->wpa_s, MSG_INFO, EXT_RADIO_WORK_TIMEOUT "%u", ework->id);
+ work->wpa_s->ext_work_in_progress = 0;
radio_work_done(work);
os_free(ework);
}
@@ -5868,6 +6349,7 @@
wpa_dbg(work->wpa_s, MSG_DEBUG, "Starting external radio work %u (%s)",
ework->id, ework->type);
wpa_msg(work->wpa_s, MSG_INFO, EXT_RADIO_WORK_START "%u", ework->id);
+ work->wpa_s->ext_work_in_progress = 1;
if (!ework->timeout)
ework->timeout = 10;
eloop_register_timeout(ework->timeout, 0, wpas_ctrl_radio_work_timeout,
@@ -5923,7 +6405,7 @@
}
ret = os_snprintf(buf, buflen, "%u", ework->id);
- if (ret < 0 || (size_t) ret >= buflen)
+ if (os_snprintf_error(buflen, ret))
return -1;
return ret;
}
@@ -5947,6 +6429,7 @@
"Completed external radio work %u (%s)",
ework->id, ework->type);
eloop_cancel_timeout(wpas_ctrl_radio_work_timeout, work, NULL);
+ wpa_s->ext_work_in_progress = 0;
radio_work_done(work);
os_free(ework);
return 3; /* "OK\n" */
@@ -6003,31 +6486,17 @@
}
-static int set_scan_freqs(struct wpa_supplicant *wpa_s, char *val)
-{
- int *freqs = NULL;
-
- freqs = freq_range_to_channel_list(wpa_s, val);
- if (freqs == NULL)
- return -1;
-
- os_free(wpa_s->manual_scan_freqs);
- wpa_s->manual_scan_freqs = freqs;
-
- return 0;
-}
-
-
-static int scan_id_list_parse(struct wpa_supplicant *wpa_s, const char *value)
+static int scan_id_list_parse(struct wpa_supplicant *wpa_s, const char *value,
+ unsigned int *scan_id_count, int scan_id[])
{
const char *pos = value;
while (pos) {
if (*pos == ' ' || *pos == '\0')
break;
- if (wpa_s->scan_id_count == MAX_SCAN_ID)
+ if (*scan_id_count == MAX_SCAN_ID)
return -1;
- wpa_s->scan_id[wpa_s->scan_id_count++] = atoi(pos);
+ scan_id[(*scan_id_count)++] = atoi(pos);
pos = os_strchr(pos, ',');
if (pos)
pos++;
@@ -6041,54 +6510,82 @@
char *reply, int reply_size, int *reply_len)
{
char *pos;
+ unsigned int manual_scan_passive = 0;
+ unsigned int manual_scan_use_id = 0;
+ unsigned int manual_scan_only_new = 0;
+ unsigned int scan_only = 0;
+ unsigned int scan_id_count = 0;
+ int scan_id[MAX_SCAN_ID];
+ void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res);
+ int *manual_scan_freqs = NULL;
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
*reply_len = -1;
return;
}
- wpa_s->manual_scan_passive = 0;
- wpa_s->manual_scan_use_id = 0;
- wpa_s->manual_scan_only_new = 0;
- wpa_s->scan_id_count = 0;
+ if (radio_work_pending(wpa_s, "scan")) {
+ wpa_printf(MSG_DEBUG,
+ "Pending scan scheduled - reject new request");
+ *reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n");
+ return;
+ }
if (params) {
if (os_strncasecmp(params, "TYPE=ONLY", 9) == 0)
- wpa_s->scan_res_handler = scan_only_handler;
+ scan_only = 1;
pos = os_strstr(params, "freq=");
- if (pos && set_scan_freqs(wpa_s, pos + 5) < 0) {
- *reply_len = -1;
- return;
+ if (pos) {
+ manual_scan_freqs = freq_range_to_channel_list(wpa_s,
+ pos + 5);
+ if (manual_scan_freqs == NULL) {
+ *reply_len = -1;
+ goto done;
+ }
}
pos = os_strstr(params, "passive=");
if (pos)
- wpa_s->manual_scan_passive = !!atoi(pos + 8);
+ manual_scan_passive = !!atoi(pos + 8);
pos = os_strstr(params, "use_id=");
if (pos)
- wpa_s->manual_scan_use_id = atoi(pos + 7);
+ manual_scan_use_id = atoi(pos + 7);
pos = os_strstr(params, "only_new=1");
if (pos)
- wpa_s->manual_scan_only_new = 1;
+ manual_scan_only_new = 1;
pos = os_strstr(params, "scan_id=");
- if (pos && scan_id_list_parse(wpa_s, pos + 8) < 0) {
+ if (pos && scan_id_list_parse(wpa_s, pos + 8, &scan_id_count,
+ scan_id) < 0) {
*reply_len = -1;
- return;
+ goto done;
}
- } else {
- os_free(wpa_s->manual_scan_freqs);
- wpa_s->manual_scan_freqs = NULL;
- if (wpa_s->scan_res_handler == scan_only_handler)
- wpa_s->scan_res_handler = NULL;
}
+ if (scan_only)
+ scan_res_handler = scan_only_handler;
+ else if (wpa_s->scan_res_handler == scan_only_handler)
+ scan_res_handler = NULL;
+ else
+ scan_res_handler = wpa_s->scan_res_handler;
+
if (!wpa_s->sched_scanning && !wpa_s->scanning &&
((wpa_s->wpa_state <= WPA_SCANNING) ||
(wpa_s->wpa_state == WPA_COMPLETED))) {
+ wpa_s->manual_scan_passive = manual_scan_passive;
+ wpa_s->manual_scan_use_id = manual_scan_use_id;
+ wpa_s->manual_scan_only_new = manual_scan_only_new;
+ wpa_s->scan_id_count = scan_id_count;
+ os_memcpy(wpa_s->scan_id, scan_id, scan_id_count * sizeof(int));
+ wpa_s->scan_res_handler = scan_res_handler;
+ os_free(wpa_s->manual_scan_freqs);
+ wpa_s->manual_scan_freqs = manual_scan_freqs;
+ manual_scan_freqs = NULL;
+
wpa_s->normal_scans = 0;
wpa_s->scan_req = MANUAL_SCAN_REQ;
wpa_s->after_wps = 0;
@@ -6102,6 +6599,16 @@
wpa_s->manual_scan_id);
}
} else if (wpa_s->sched_scanning) {
+ wpa_s->manual_scan_passive = manual_scan_passive;
+ wpa_s->manual_scan_use_id = manual_scan_use_id;
+ wpa_s->manual_scan_only_new = manual_scan_only_new;
+ wpa_s->scan_id_count = scan_id_count;
+ os_memcpy(wpa_s->scan_id, scan_id, scan_id_count * sizeof(int));
+ wpa_s->scan_res_handler = scan_res_handler;
+ os_free(wpa_s->manual_scan_freqs);
+ wpa_s->manual_scan_freqs = manual_scan_freqs;
+ manual_scan_freqs = NULL;
+
wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to allow requested full scan to proceed");
wpa_supplicant_cancel_sched_scan(wpa_s);
wpa_s->scan_req = MANUAL_SCAN_REQ;
@@ -6117,6 +6624,9 @@
wpa_printf(MSG_DEBUG, "Ongoing scan action - reject new request");
*reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n");
}
+
+done:
+ os_free(manual_scan_freqs);
}
@@ -6256,6 +6766,266 @@
return 0;
}
+
+static int wpas_ctrl_iface_eapol_rx(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ char *pos;
+ u8 src[ETH_ALEN], *buf;
+ int used;
+ size_t len;
+
+ wpa_printf(MSG_DEBUG, "External EAPOL RX: %s", cmd);
+
+ pos = cmd;
+ used = hwaddr_aton2(pos, src);
+ if (used < 0)
+ return -1;
+ pos += used;
+ while (*pos == ' ')
+ pos++;
+
+ len = os_strlen(pos);
+ if (len & 1)
+ return -1;
+ len /= 2;
+
+ buf = os_malloc(len);
+ if (buf == NULL)
+ return -1;
+
+ if (hexstr2bin(pos, buf, len) < 0) {
+ os_free(buf);
+ return -1;
+ }
+
+ wpa_supplicant_rx_eapol(wpa_s, src, buf, len);
+ os_free(buf);
+
+ return 0;
+}
+
+
+static u16 ipv4_hdr_checksum(const void *buf, size_t len)
+{
+ size_t i;
+ u32 sum = 0;
+ const u16 *pos = buf;
+
+ for (i = 0; i < len / 2; i++)
+ sum += *pos++;
+
+ while (sum >> 16)
+ sum = (sum & 0xffff) + (sum >> 16);
+
+ return sum ^ 0xffff;
+}
+
+
+#define HWSIM_PACKETLEN 1500
+#define HWSIM_IP_LEN (HWSIM_PACKETLEN - sizeof(struct ether_header))
+
+void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ const struct ether_header *eth;
+ const struct iphdr *ip;
+ const u8 *pos;
+ unsigned int i;
+
+ if (len != HWSIM_PACKETLEN)
+ return;
+
+ eth = (const struct ether_header *) buf;
+ ip = (const struct iphdr *) (eth + 1);
+ pos = (const u8 *) (ip + 1);
+
+ if (ip->ihl != 5 || ip->version != 4 ||
+ ntohs(ip->tot_len) != HWSIM_IP_LEN)
+ return;
+
+ for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++) {
+ if (*pos != (u8) i)
+ return;
+ pos++;
+ }
+
+ wpa_msg(wpa_s, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR,
+ MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost));
+}
+
+
+static int wpas_ctrl_iface_data_test_config(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ int enabled = atoi(cmd);
+
+ if (!enabled) {
+ if (wpa_s->l2_test) {
+ l2_packet_deinit(wpa_s->l2_test);
+ wpa_s->l2_test = NULL;
+ wpa_dbg(wpa_s, MSG_DEBUG, "test data: Disabled");
+ }
+ return 0;
+ }
+
+ if (wpa_s->l2_test)
+ return 0;
+
+ wpa_s->l2_test = l2_packet_init(wpa_s->ifname, wpa_s->own_addr,
+ ETHERTYPE_IP, wpas_data_test_rx,
+ wpa_s, 1);
+ if (wpa_s->l2_test == NULL)
+ return -1;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "test data: Enabled");
+
+ return 0;
+}
+
+
+static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ u8 dst[ETH_ALEN], src[ETH_ALEN];
+ char *pos;
+ int used;
+ long int val;
+ u8 tos;
+ u8 buf[HWSIM_PACKETLEN];
+ struct ether_header *eth;
+ struct iphdr *ip;
+ u8 *dpos;
+ unsigned int i;
+
+ if (wpa_s->l2_test == NULL)
+ return -1;
+
+ /* format: <dst> <src> <tos> */
+
+ pos = cmd;
+ used = hwaddr_aton2(pos, dst);
+ if (used < 0)
+ return -1;
+ pos += used;
+ while (*pos == ' ')
+ pos++;
+ used = hwaddr_aton2(pos, src);
+ if (used < 0)
+ return -1;
+ pos += used;
+
+ val = strtol(pos, NULL, 0);
+ if (val < 0 || val > 0xff)
+ return -1;
+ tos = val;
+
+ eth = (struct ether_header *) buf;
+ os_memcpy(eth->ether_dhost, dst, ETH_ALEN);
+ os_memcpy(eth->ether_shost, src, ETH_ALEN);
+ eth->ether_type = htons(ETHERTYPE_IP);
+ ip = (struct iphdr *) (eth + 1);
+ os_memset(ip, 0, sizeof(*ip));
+ ip->ihl = 5;
+ ip->version = 4;
+ ip->ttl = 64;
+ ip->tos = tos;
+ ip->tot_len = htons(HWSIM_IP_LEN);
+ ip->protocol = 1;
+ ip->saddr = htonl(192 << 24 | 168 << 16 | 1 << 8 | 1);
+ ip->daddr = htonl(192 << 24 | 168 << 16 | 1 << 8 | 2);
+ ip->check = ipv4_hdr_checksum(ip, sizeof(*ip));
+ dpos = (u8 *) (ip + 1);
+ for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++)
+ *dpos++ = i;
+
+ if (l2_packet_send(wpa_s->l2_test, dst, ETHERTYPE_IP, buf,
+ HWSIM_PACKETLEN) < 0)
+ return -1;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "test data: TX dst=" MACSTR " src=" MACSTR
+ " tos=0x%x", MAC2STR(dst), MAC2STR(src), tos);
+
+ return 0;
+}
+
+
+static int wpas_ctrl_iface_data_test_frame(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ u8 *buf;
+ struct ether_header *eth;
+ struct l2_packet_data *l2 = NULL;
+ size_t len;
+ u16 ethertype;
+ int res = -1;
+
+ len = os_strlen(cmd);
+ if (len & 1 || len < ETH_HLEN * 2)
+ return -1;
+ len /= 2;
+
+ buf = os_malloc(len);
+ if (buf == NULL)
+ return -1;
+
+ if (hexstr2bin(cmd, buf, len) < 0)
+ goto done;
+
+ eth = (struct ether_header *) buf;
+ ethertype = ntohs(eth->ether_type);
+
+ l2 = l2_packet_init(wpa_s->ifname, wpa_s->own_addr, ethertype,
+ wpas_data_test_rx, wpa_s, 1);
+ if (l2 == NULL)
+ goto done;
+
+ res = l2_packet_send(l2, eth->ether_dhost, ethertype, buf, len);
+ wpa_dbg(wpa_s, MSG_DEBUG, "test data: TX frame res=%d", res);
+done:
+ if (l2)
+ l2_packet_deinit(l2);
+ os_free(buf);
+
+ return res < 0 ? -1 : 0;
+}
+
+
+static int wpas_ctrl_test_alloc_fail(struct wpa_supplicant *wpa_s, char *cmd)
+{
+#ifdef WPA_TRACE_BFD
+ extern char wpa_trace_fail_func[256];
+ extern unsigned int wpa_trace_fail_after;
+ char *pos;
+
+ wpa_trace_fail_after = atoi(cmd);
+ pos = os_strchr(cmd, ':');
+ if (pos) {
+ pos++;
+ os_strlcpy(wpa_trace_fail_func, pos,
+ sizeof(wpa_trace_fail_func));
+ } else {
+ wpa_trace_fail_after = 0;
+ }
+ return 0;
+#else /* WPA_TRACE_BFD */
+ return -1;
+#endif /* WPA_TRACE_BFD */
+}
+
+
+static int wpas_ctrl_get_alloc_fail(struct wpa_supplicant *wpa_s,
+ char *buf, size_t buflen)
+{
+#ifdef WPA_TRACE_BFD
+ extern char wpa_trace_fail_func[256];
+ extern unsigned int wpa_trace_fail_after;
+
+ return os_snprintf(buf, buflen, "%u:%s", wpa_trace_fail_after,
+ wpa_trace_fail_func);
+#else /* WPA_TRACE_BFD */
+ return -1;
+#endif /* WPA_TRACE_BFD */
+}
+
#endif /* CONFIG_TESTING_OPTIONS */
@@ -6268,8 +7038,13 @@
for (i = 0; i < NUM_VENDOR_ELEM_FRAMES; i++) {
if (wpa_s->vendor_elem[i]) {
- os_snprintf(buf, sizeof(buf), "frame[%u]", i);
- wpa_hexdump_buf(MSG_DEBUG, buf, wpa_s->vendor_elem[i]);
+ int res;
+
+ res = os_snprintf(buf, sizeof(buf), "frame[%u]", i);
+ if (!os_snprintf_error(sizeof(buf), res)) {
+ wpa_hexdump_buf(MSG_DEBUG, buf,
+ wpa_s->vendor_elem[i]);
+ }
}
}
@@ -6463,6 +7238,171 @@
}
+static void wpas_ctrl_neighbor_rep_cb(void *ctx, struct wpabuf *neighbor_rep)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ if (neighbor_rep) {
+ wpa_msg_ctrl(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_RXED
+ "length=%u",
+ (unsigned int) wpabuf_len(neighbor_rep));
+ wpabuf_free(neighbor_rep);
+ } else {
+ wpa_msg_ctrl(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_FAILED);
+ }
+}
+
+
+static int wpas_ctrl_iface_send_neigbor_rep(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ struct wpa_ssid ssid;
+ struct wpa_ssid *ssid_p = NULL;
+ int ret = 0;
+
+ if (os_strncmp(cmd, " ssid=", 6) == 0) {
+ ssid.ssid_len = os_strlen(cmd + 6);
+ if (ssid.ssid_len > 32)
+ return -1;
+ ssid.ssid = (u8 *) (cmd + 6);
+ ssid_p = &ssid;
+ }
+
+ ret = wpas_rrm_send_neighbor_rep_request(wpa_s, ssid_p,
+ wpas_ctrl_neighbor_rep_cb,
+ wpa_s);
+
+ return ret;
+}
+
+
+static int wpas_ctrl_iface_erp_flush(struct wpa_supplicant *wpa_s)
+{
+ eapol_sm_erp_flush(wpa_s->eapol);
+ return 0;
+}
+
+
+static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ char *token, *context = NULL;
+ unsigned int enable = ~0, type = 0;
+ u8 _addr[ETH_ALEN], _mask[ETH_ALEN];
+ u8 *addr = NULL, *mask = NULL;
+
+ while ((token = str_token(cmd, " ", &context))) {
+ if (os_strcasecmp(token, "scan") == 0) {
+ type |= MAC_ADDR_RAND_SCAN;
+ } else if (os_strcasecmp(token, "sched") == 0) {
+ type |= MAC_ADDR_RAND_SCHED_SCAN;
+ } else if (os_strcasecmp(token, "pno") == 0) {
+ type |= MAC_ADDR_RAND_PNO;
+ } else if (os_strcasecmp(token, "all") == 0) {
+ type = wpa_s->mac_addr_rand_supported;
+ } else if (os_strncasecmp(token, "enable=", 7) == 0) {
+ enable = atoi(token + 7);
+ } else if (os_strncasecmp(token, "addr=", 5) == 0) {
+ addr = _addr;
+ if (hwaddr_aton(token + 5, addr)) {
+ wpa_printf(MSG_INFO,
+ "CTRL: Invalid MAC address: %s",
+ token);
+ return -1;
+ }
+ } else if (os_strncasecmp(token, "mask=", 5) == 0) {
+ mask = _mask;
+ if (hwaddr_aton(token + 5, mask)) {
+ wpa_printf(MSG_INFO,
+ "CTRL: Invalid MAC address mask: %s",
+ token);
+ return -1;
+ }
+ } else {
+ wpa_printf(MSG_INFO,
+ "CTRL: Invalid MAC_RAND_SCAN parameter: %s",
+ token);
+ return -1;
+ }
+ }
+
+ if (!type) {
+ wpa_printf(MSG_INFO, "CTRL: MAC_RAND_SCAN no type specified");
+ return -1;
+ }
+
+ if ((wpa_s->mac_addr_rand_supported & type) != type) {
+ wpa_printf(MSG_INFO,
+ "CTRL: MAC_RAND_SCAN types=%u != supported=%u",
+ type, wpa_s->mac_addr_rand_supported);
+ return -1;
+ }
+
+ if (enable > 1) {
+ wpa_printf(MSG_INFO,
+ "CTRL: MAC_RAND_SCAN enable=<0/1> not specified");
+ return -1;
+ }
+
+ if (!enable) {
+ wpas_mac_addr_rand_scan_clear(wpa_s, type);
+ if (wpa_s->pno) {
+ if (type & MAC_ADDR_RAND_PNO) {
+ wpas_stop_pno(wpa_s);
+ wpas_start_pno(wpa_s);
+ }
+ } else if (wpa_s->sched_scanning &&
+ (type & MAC_ADDR_RAND_SCHED_SCAN)) {
+ /* simulate timeout to restart the sched scan */
+ wpa_s->sched_scan_timed_out = 1;
+ wpa_s->prev_sched_ssid = NULL;
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ }
+ return 0;
+ }
+
+ if ((addr && !mask) || (!addr && mask)) {
+ wpa_printf(MSG_INFO,
+ "CTRL: MAC_RAND_SCAN invalid addr/mask combination");
+ return -1;
+ }
+
+ if (addr && mask && (!(mask[0] & 0x01) || (addr[0] & 0x01))) {
+ wpa_printf(MSG_INFO,
+ "CTRL: MAC_RAND_SCAN cannot allow multicast address");
+ return -1;
+ }
+
+ if (type & MAC_ADDR_RAND_SCAN) {
+ wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCAN,
+ addr, mask);
+ }
+
+ if (type & MAC_ADDR_RAND_SCHED_SCAN) {
+ wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN,
+ addr, mask);
+
+ if (wpa_s->sched_scanning && !wpa_s->pno) {
+ /* simulate timeout to restart the sched scan */
+ wpa_s->sched_scan_timed_out = 1;
+ wpa_s->prev_sched_ssid = NULL;
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ }
+ }
+
+ if (type & MAC_ADDR_RAND_PNO) {
+ wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_PNO,
+ addr, mask);
+ if (wpa_s->pno) {
+ wpas_stop_pno(wpa_s);
+ wpas_start_pno(wpa_s);
+ }
+ }
+
+ return 0;
+}
+
+
char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
char *buf, size_t *resp_len)
{
@@ -6515,13 +7455,9 @@
} else if (os_strcmp(buf, "MIB") == 0) {
reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size);
if (reply_len >= 0) {
- int res;
- res = eapol_sm_get_mib(wpa_s->eapol, reply + reply_len,
- reply_size - reply_len);
- if (res < 0)
- reply_len = -1;
- else
- reply_len += res;
+ reply_len += eapol_sm_get_mib(wpa_s->eapol,
+ reply + reply_len,
+ reply_size - reply_len);
}
} else if (os_strncmp(buf, "STATUS", 6) == 0) {
reply_len = wpa_supplicant_ctrl_iface_status(
@@ -6642,8 +7578,7 @@
if (wpas_wps_er_start(wpa_s, buf + 13))
reply_len = -1;
} else if (os_strcmp(buf, "WPS_ER_STOP") == 0) {
- if (wpas_wps_er_stop(wpa_s))
- reply_len = -1;
+ wpas_wps_er_stop(wpa_s);
} else if (os_strncmp(buf, "WPS_ER_PIN ", 11) == 0) {
if (wpa_supplicant_ctrl_iface_wps_er_pin(wpa_s, buf + 11))
reply_len = -1;
@@ -6682,6 +7617,21 @@
if (wpa_supplicant_ctrl_iface_ibss_rsn(wpa_s, buf + 9))
reply_len = -1;
#endif /* CONFIG_IBSS_RSN */
+#ifdef CONFIG_MESH
+ } else if (os_strncmp(buf, "MESH_INTERFACE_ADD ", 19) == 0) {
+ reply_len = wpa_supplicant_ctrl_iface_mesh_interface_add(
+ wpa_s, buf + 19, reply, reply_size);
+ } else if (os_strcmp(buf, "MESH_INTERFACE_ADD") == 0) {
+ reply_len = wpa_supplicant_ctrl_iface_mesh_interface_add(
+ wpa_s, "", reply, reply_size);
+ } else if (os_strncmp(buf, "MESH_GROUP_ADD ", 15) == 0) {
+ if (wpa_supplicant_ctrl_iface_mesh_group_add(wpa_s, buf + 15))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "MESH_GROUP_REMOVE ", 18) == 0) {
+ if (wpa_supplicant_ctrl_iface_mesh_group_remove(wpa_s,
+ buf + 18))
+ reply_len = -1;
+#endif /* CONFIG_MESH */
#ifdef CONFIG_P2P
} else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) {
if (p2p_ctrl_find(wpa_s, buf + 9))
@@ -6965,8 +7915,7 @@
if (wpa_supplicant_ctrl_iface_roam(wpa_s, buf + 5))
reply_len = -1;
} else if (os_strncmp(buf, "STA_AUTOCONNECT ", 16) == 0) {
- if (wpa_supplicant_ctrl_iface_sta_autoconnect(wpa_s, buf + 16))
- reply_len = -1;
+ wpa_s->auto_reconnect_disabled = atoi(buf + 16) == 0;
} else if (os_strncmp(buf, "BSS_EXPIRE_AGE ", 15) == 0) {
if (wpa_supplicant_ctrl_iface_bss_expire_age(wpa_s, buf + 15))
reply_len = -1;
@@ -6975,8 +7924,7 @@
buf + 17))
reply_len = -1;
} else if (os_strncmp(buf, "BSS_FLUSH ", 10) == 0) {
- if (wpa_supplicant_ctrl_iface_bss_flush(wpa_s, buf + 10))
- reply_len = -1;
+ wpa_supplicant_ctrl_iface_bss_flush(wpa_s, buf + 10);
#ifdef CONFIG_TDLS
} else if (os_strncmp(buf, "TDLS_DISCOVER ", 14) == 0) {
if (wpa_supplicant_ctrl_iface_tdls_discover(wpa_s, buf + 14))
@@ -6987,7 +7935,23 @@
} else if (os_strncmp(buf, "TDLS_TEARDOWN ", 14) == 0) {
if (wpa_supplicant_ctrl_iface_tdls_teardown(wpa_s, buf + 14))
reply_len = -1;
+ } else if (os_strncmp(buf, "TDLS_CHAN_SWITCH ", 17) == 0) {
+ if (wpa_supplicant_ctrl_iface_tdls_chan_switch(wpa_s,
+ buf + 17))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "TDLS_CANCEL_CHAN_SWITCH ", 24) == 0) {
+ if (wpa_supplicant_ctrl_iface_tdls_cancel_chan_switch(wpa_s,
+ buf + 24))
+ reply_len = -1;
#endif /* CONFIG_TDLS */
+ } else if (os_strcmp(buf, "WMM_AC_STATUS") == 0) {
+ reply_len = wpas_wmm_ac_status(wpa_s, reply, reply_size);
+ } else if (os_strncmp(buf, "WMM_AC_ADDTS ", 13) == 0) {
+ if (wmm_ac_ctrl_addts(wpa_s, buf + 13))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "WMM_AC_DELTS ", 13) == 0) {
+ if (wmm_ac_ctrl_delts(wpa_s, buf + 13))
+ reply_len = -1;
} else if (os_strncmp(buf, "SIGNAL_POLL", 11) == 0) {
reply_len = wpa_supplicant_signal_poll(wpa_s, reply,
reply_size);
@@ -7014,8 +7978,8 @@
} else if (os_strncmp(buf, "WNM_SLEEP ", 10) == 0) {
if (wpas_ctrl_iface_wnm_sleep(wpa_s, buf + 10))
reply_len = -1;
- } else if (os_strncmp(buf, "WNM_BSS_QUERY ", 10) == 0) {
- if (wpas_ctrl_iface_wnm_bss_query(wpa_s, buf + 10))
+ } else if (os_strncmp(buf, "WNM_BSS_QUERY ", 14) == 0) {
+ if (wpas_ctrl_iface_wnm_bss_query(wpa_s, buf + 14))
reply_len = -1;
#endif /* CONFIG_WNM */
} else if (os_strcmp(buf, "FLUSH") == 0) {
@@ -7032,6 +7996,23 @@
} else if (os_strncmp(buf, "DRIVER_EVENT ", 13) == 0) {
if (wpas_ctrl_iface_driver_event(wpa_s, buf + 13) < 0)
reply_len = -1;
+ } else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) {
+ if (wpas_ctrl_iface_eapol_rx(wpa_s, buf + 9) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DATA_TEST_CONFIG ", 17) == 0) {
+ if (wpas_ctrl_iface_data_test_config(wpa_s, buf + 17) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DATA_TEST_TX ", 13) == 0) {
+ if (wpas_ctrl_iface_data_test_tx(wpa_s, buf + 13) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DATA_TEST_FRAME ", 16) == 0) {
+ if (wpas_ctrl_iface_data_test_frame(wpa_s, buf + 16) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "TEST_ALLOC_FAIL ", 16) == 0) {
+ if (wpas_ctrl_test_alloc_fail(wpa_s, buf + 16) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "GET_ALLOC_FAIL") == 0) {
+ reply_len = wpas_ctrl_get_alloc_fail(wpa_s, reply, reply_size);
#endif /* CONFIG_TESTING_OPTIONS */
} else if (os_strncmp(buf, "VENDOR_ELEM_ADD ", 16) == 0) {
if (wpas_ctrl_vendor_elem_add(wpa_s, buf + 16) < 0)
@@ -7042,6 +8023,14 @@
} else if (os_strncmp(buf, "VENDOR_ELEM_REMOVE ", 19) == 0) {
if (wpas_ctrl_vendor_elem_remove(wpa_s, buf + 19) < 0)
reply_len = -1;
+ } else if (os_strncmp(buf, "NEIGHBOR_REP_REQUEST", 20) == 0) {
+ if (wpas_ctrl_iface_send_neigbor_rep(wpa_s, buf + 20))
+ reply_len = -1;
+ } else if (os_strcmp(buf, "ERP_FLUSH") == 0) {
+ wpas_ctrl_iface_erp_flush(wpa_s);
+ } else if (os_strncmp(buf, "MAC_RAND_SCAN ", 14) == 0) {
+ if (wpas_ctrl_iface_mac_rand_scan(wpa_s, buf + 14))
+ reply_len = -1;
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
@@ -7192,7 +8181,7 @@
res = os_snprintf(pos, end - pos, "%s\t%s\t%s\n",
tmp->drv_name, tmp->ifname,
tmp->desc ? tmp->desc : "");
- if (res < 0 || res >= end - pos) {
+ if (os_snprintf_error(end - pos, res)) {
*pos = '\0';
break;
}
@@ -7218,7 +8207,7 @@
while (wpa_s) {
res = os_snprintf(pos, end - pos, "%s\n", wpa_s->ifname);
- if (res < 0 || res >= end - pos) {
+ if (os_snprintf_error(end - pos, res)) {
*pos = '\0';
break;
}
@@ -7298,6 +8287,8 @@
"P2P_PRESENCE_REQ ",
"P2P_EXT_LISTEN ",
"P2P_REMOVE_CLIENT ",
+ "WPS_NFC_TOKEN ",
+ "WPS_NFC_TAG_READ ",
"NFC_GET_HANDOVER_SEL ",
"NFC_GET_HANDOVER_REQ ",
"NFC_REPORT_HANDOVER ",
@@ -7433,12 +8424,12 @@
"p2p_state=%s\n",
MAC2STR(global->p2p_dev_addr),
p2p_get_state_txt(global->p2p));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
} else if (global->p2p) {
ret = os_snprintf(pos, end - pos, "p2p_state=DISABLED\n");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -7447,7 +8438,7 @@
#ifdef CONFIG_WIFI_DISPLAY
ret = os_snprintf(pos, end - pos, "wifi_display=%d\n",
!!global->wifi_display);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
#endif /* CONFIG_WIFI_DISPLAY */
@@ -7456,7 +8447,7 @@
ret = os_snprintf(pos, end - pos, "ifname=%s\n"
"address=" MACSTR "\n",
wpa_s->ifname, MAC2STR(wpa_s->own_addr));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -7550,6 +8541,9 @@
if (wpas_module_tests() < 0)
reply_len = -1;
#endif /* CONFIG_MODULE_TESTS */
+ } else if (os_strncmp(buf, "RELOG", 5) == 0) {
+ if (wpa_debug_reopen_file() < 0)
+ reply_len = -1;
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
diff --git a/wpa_supplicant/ctrl_iface_udp.c b/wpa_supplicant/ctrl_iface_udp.c
index 9d0674d..bf6a3df 100644
--- a/wpa_supplicant/ctrl_iface_udp.c
+++ b/wpa_supplicant/ctrl_iface_udp.c
@@ -218,7 +218,8 @@
res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
(struct sockaddr *) &from, &fromlen);
if (res < 0) {
- perror("recvfrom(ctrl_iface)");
+ wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
+ strerror(errno));
return;
}
@@ -356,7 +357,7 @@
priv->sock = socket(domain, SOCK_DGRAM, 0);
if (priv->sock < 0) {
- perror("socket(PF_INET)");
+ wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
goto fail;
}
@@ -386,7 +387,7 @@
port--;
if ((WPA_CTRL_IFACE_PORT - port) < WPA_CTRL_IFACE_PORT_LIMIT)
goto try_again;
- perror("bind(AF_INET)");
+ wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
goto fail;
}
@@ -482,7 +483,9 @@
if (sendto(priv->sock, sbuf, llen + len, 0,
(struct sockaddr *) &dst->addr,
sizeof(dst->addr)) < 0) {
- perror("sendto(CTRL_IFACE monitor)");
+ wpa_printf(MSG_ERROR,
+ "sendto(CTRL_IFACE monitor): %s",
+ strerror(errno));
dst->errors++;
if (dst->errors > 10) {
wpa_supplicant_ctrl_iface_detach(
@@ -551,7 +554,8 @@
res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
(struct sockaddr *) &from, &fromlen);
if (res < 0) {
- perror("recvfrom(ctrl_iface)");
+ wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
+ strerror(errno));
return;
}
@@ -634,7 +638,7 @@
priv->sock = socket(PF_INET, SOCK_DGRAM, 0);
if (priv->sock < 0) {
- perror("socket(PF_INET)");
+ wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
goto fail;
}
@@ -652,7 +656,7 @@
if ((port - WPA_GLOBAL_CTRL_IFACE_PORT) <
WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT)
goto try_again;
- perror("bind(AF_INET)");
+ wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
goto fail;
}
diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c
index 40082e2..b1ac766 100644
--- a/wpa_supplicant/ctrl_iface_unix.c
+++ b/wpa_supplicant/ctrl_iface_unix.c
@@ -47,6 +47,7 @@
struct wpa_supplicant *wpa_s;
int sock;
struct dl_list ctrl_dst;
+ int android_control_socket;
};
@@ -54,6 +55,7 @@
struct wpa_global *global;
int sock;
struct dl_list ctrl_dst;
+ int android_control_socket;
};
@@ -72,7 +74,7 @@
static int wpa_supplicant_ctrl_iface_attach(struct dl_list *ctrl_dst,
struct sockaddr_un *from,
- socklen_t fromlen)
+ socklen_t fromlen, int global)
{
struct wpa_ctrl_dst *dst;
char addr_txt[200];
@@ -87,7 +89,8 @@
printf_encode(addr_txt, sizeof(addr_txt),
(u8 *) from->sun_path,
fromlen - offsetof(struct sockaddr_un, sun_path));
- wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s", addr_txt);
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE %smonitor attached %s",
+ global ? "global " : "", addr_txt);
return 0;
}
@@ -172,7 +175,7 @@
if (os_strcmp(buf, "ATTACH") == 0) {
if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst, &from,
- fromlen))
+ fromlen, 0))
reply_len = 1;
else {
new_attached = 1;
@@ -270,7 +273,7 @@
}
res = os_snprintf(buf, len, "%s/%s", dir, wpa_s->ifname);
- if (res < 0 || (size_t) res >= len) {
+ if (os_snprintf_error(len, res)) {
os_free(pbuf);
os_free(buf);
return NULL;
@@ -340,8 +343,10 @@
os_snprintf(addr.sun_path, sizeof(addr.sun_path), "wpa_%s",
wpa_s->conf->ctrl_interface);
priv->sock = android_get_control_socket(addr.sun_path);
- if (priv->sock >= 0)
+ if (priv->sock >= 0) {
+ priv->android_control_socket = 1;
goto havesock;
+ }
#endif /* ANDROID */
if (os_strncmp(buf, "DIR=", 4) == 0) {
dir = buf + 4;
@@ -556,6 +561,16 @@
if (priv->sock <= 0)
return -1;
+ /*
+ * On Android, the control socket being used may be the socket
+ * that is created when wpa_supplicant is started as a /init.*.rc
+ * service. Such a socket is maintained as a key-value pair in
+ * Android's environment. Closing this control socket would leave us
+ * in a bad state with an invalid socket descriptor.
+ */
+ if (priv->android_control_socket)
+ return priv->sock;
+
eloop_unregister_read_sock(priv->sock);
close(priv->sock);
priv->sock = -1;
@@ -657,7 +672,7 @@
return;
res = os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
- if (res < 0 || (size_t) res >= sizeof(levelstr))
+ if (os_snprintf_error(sizeof(levelstr), res))
return;
idx = 0;
if (ifname) {
@@ -761,7 +776,8 @@
if (os_strcmp(buf, "ATTACH") == 0) {
/* handle ATTACH signal of first monitor interface */
if (!wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst,
- &from, fromlen)) {
+ &from, fromlen,
+ 0)) {
if (sendto(priv->sock, "OK\n", 3, 0,
(struct sockaddr *) &from, fromlen) <
0) {
@@ -816,7 +832,7 @@
if (os_strcmp(buf, "ATTACH") == 0) {
if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst, &from,
- fromlen))
+ fromlen, 1))
reply_len = 1;
else
reply_len = 2;
@@ -870,6 +886,7 @@
}
wpa_printf(MSG_DEBUG, "Using Android control socket '%s'",
ctrl + 9);
+ priv->android_control_socket = 1;
goto havesock;
}
@@ -884,6 +901,7 @@
wpa_printf(MSG_DEBUG,
"Using Android control socket '%s'",
ctrl);
+ priv->android_control_socket = 1;
goto havesock;
}
}
@@ -1064,6 +1082,16 @@
if (priv->sock <= 0)
return -1;
+ /*
+ * On Android, the control socket being used may be the socket
+ * that is created when wpa_supplicant is started as a /init.*.rc
+ * service. Such a socket is maintained as a key-value pair in
+ * Android's environment. Closing this control socket would leave us
+ * in a bad state with an invalid socket descriptor.
+ */
+ if (priv->android_control_socket)
+ return priv->sock;
+
eloop_unregister_read_sock(priv->sock);
close(priv->sock);
priv->sock = -1;
diff --git a/wpa_supplicant/dbus/dbus_common.c b/wpa_supplicant/dbus/dbus_common.c
index 5cc1505..7ef6cad 100644
--- a/wpa_supplicant/dbus/dbus_common.c
+++ b/wpa_supplicant/dbus/dbus_common.c
@@ -165,6 +165,7 @@
static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data)
{
struct wpas_dbus_priv *priv = data;
+
if (!dbus_timeout_get_enabled(timeout))
return TRUE;
@@ -180,6 +181,7 @@
static void remove_timeout(DBusTimeout *timeout, void *data)
{
struct wpas_dbus_priv *priv = data;
+
eloop_cancel_timeout(process_timeout, priv, timeout);
dbus_timeout_set_data(timeout, NULL, NULL);
}
@@ -244,8 +246,7 @@
remove_timeout,
timeout_toggled, priv,
NULL)) {
- wpa_printf(MSG_ERROR, "dbus: Failed to set callback "
- "functions");
+ wpa_printf(MSG_ERROR, "dbus: Failed to set callback functions");
return -1;
}
@@ -259,12 +260,12 @@
static DBusHandlerResult disconnect_filter(DBusConnection *conn,
- DBusMessage *message, void *data)
+ DBusMessage *message, void *data)
{
struct wpas_dbus_priv *priv = data;
if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL,
- "Disconnected")) {
+ "Disconnected")) {
wpa_printf(MSG_DEBUG, "dbus: bus disconnected, terminating");
dbus_connection_set_exit_on_disconnect(conn, FALSE);
wpa_supplicant_terminate_proc(priv->global);
@@ -284,10 +285,11 @@
priv->con = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
if (priv->con) {
dbus_connection_add_filter(priv->con, disconnect_filter, priv,
- NULL);
+ NULL);
} else {
- wpa_printf(MSG_ERROR, "dbus: Could not acquire the system "
- "bus: %s - %s", error.name, error.message);
+ wpa_printf(MSG_ERROR,
+ "dbus: Could not acquire the system bus: %s - %s",
+ error.name, error.message);
ret = -1;
}
dbus_error_free(&error);
@@ -309,7 +311,7 @@
* FIXME: is there a better solution to this problem?
*/
eloop_register_timeout(0, 50, dispatch_initial_dbus_messages,
- priv->con, NULL);
+ priv->con, NULL);
return 0;
}
@@ -345,26 +347,14 @@
return NULL;
priv->global = global;
- if (wpas_dbus_init_common(priv) < 0) {
- wpas_dbus_deinit(priv);
- return NULL;
- }
-
+ if (wpas_dbus_init_common(priv) < 0 ||
#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
- if (wpas_dbus_ctrl_iface_init(priv) < 0) {
- wpas_dbus_deinit(priv);
- return NULL;
- }
+ wpas_dbus_ctrl_iface_init(priv) < 0 ||
#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
-
#ifdef CONFIG_CTRL_IFACE_DBUS
- if (wpa_supplicant_dbus_ctrl_iface_init(priv) < 0) {
- wpas_dbus_deinit(priv);
- return NULL;
- }
+ wpa_supplicant_dbus_ctrl_iface_init(priv) < 0 ||
#endif /* CONFIG_CTRL_IFACE_DBUS */
-
- if (wpas_dbus_init_common_finish(priv) < 0) {
+ wpas_dbus_init_common_finish(priv) < 0) {
wpas_dbus_deinit(priv);
return NULL;
}
diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.c b/wpa_supplicant/dbus/dbus_dict_helpers.c
index 949ce7c..a0c44eb 100644
--- a/wpa_supplicant/dbus/dbus_dict_helpers.c
+++ b/wpa_supplicant/dbus/dbus_dict_helpers.c
@@ -66,7 +66,7 @@
const char * wpa_dbus_type_as_string(const int type)
{
- switch(type) {
+ switch (type) {
case DBUS_TYPE_BYTE:
return DBUS_TYPE_BYTE_AS_STRING;
case DBUS_TYPE_BOOLEAN:
@@ -106,11 +106,8 @@
iter_dict_entry))
return FALSE;
- if (!dbus_message_iter_append_basic(iter_dict_entry, DBUS_TYPE_STRING,
- &key))
- return FALSE;
-
- return TRUE;
+ return dbus_message_iter_append_basic(iter_dict_entry, DBUS_TYPE_STRING,
+ &key);
}
@@ -120,10 +117,8 @@
{
if (!dbus_message_iter_close_container(iter_dict_entry, iter_dict_val))
return FALSE;
- if (!dbus_message_iter_close_container(iter_dict, iter_dict_entry))
- return FALSE;
- return TRUE;
+ return dbus_message_iter_close_container(iter_dict, iter_dict_entry);
}
@@ -143,22 +138,15 @@
return FALSE;
if (!_wpa_dbus_add_dict_entry_start(iter_dict, &iter_dict_entry,
- key, value_type))
- return FALSE;
-
- if (!dbus_message_iter_open_container(&iter_dict_entry,
+ key, value_type) ||
+ !dbus_message_iter_open_container(&iter_dict_entry,
DBUS_TYPE_VARIANT,
- type_as_string, &iter_dict_val))
+ type_as_string, &iter_dict_val) ||
+ !dbus_message_iter_append_basic(&iter_dict_val, value_type, value))
return FALSE;
- if (!dbus_message_iter_append_basic(&iter_dict_val, value_type, value))
- return FALSE;
-
- if (!_wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry,
- &iter_dict_val))
- return FALSE;
-
- return TRUE;
+ return _wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry,
+ &iter_dict_val);
}
@@ -170,17 +158,13 @@
dbus_uint32_t i;
if (!_wpa_dbus_add_dict_entry_start(iter_dict, &iter_dict_entry,
- key, DBUS_TYPE_ARRAY))
- return FALSE;
-
- if (!dbus_message_iter_open_container(&iter_dict_entry,
+ key, DBUS_TYPE_ARRAY) ||
+ !dbus_message_iter_open_container(&iter_dict_entry,
DBUS_TYPE_VARIANT,
DBUS_TYPE_ARRAY_AS_STRING
DBUS_TYPE_BYTE_AS_STRING,
- &iter_dict_val))
- return FALSE;
-
- if (!dbus_message_iter_open_container(&iter_dict_val, DBUS_TYPE_ARRAY,
+ &iter_dict_val) ||
+ !dbus_message_iter_open_container(&iter_dict_val, DBUS_TYPE_ARRAY,
DBUS_TYPE_BYTE_AS_STRING,
&iter_array))
return FALSE;
@@ -195,11 +179,8 @@
if (!dbus_message_iter_close_container(&iter_dict_val, &iter_array))
return FALSE;
- if (!_wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry,
- &iter_dict_val))
- return FALSE;
-
- return TRUE;
+ return _wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry,
+ &iter_dict_val);
}
@@ -428,9 +409,7 @@
const char *value,
const dbus_uint32_t value_len)
{
- if (!key)
- return FALSE;
- if (!value && (value_len != 0))
+ if (!key || (!value && value_len != 0))
return FALSE;
return _wpa_dbus_add_dict_entry_byte_array(iter_dict, key, value,
value_len);
@@ -465,27 +444,20 @@
err = os_snprintf(array_type, sizeof(array_type),
DBUS_TYPE_ARRAY_AS_STRING "%s",
type);
- if (err < 0 || err > (int) sizeof(array_type))
+ if (os_snprintf_error(sizeof(array_type), err))
return FALSE;
- if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array)
- return FALSE;
-
- if (!_wpa_dbus_add_dict_entry_start(iter_dict, iter_dict_entry,
- key, DBUS_TYPE_ARRAY))
- return FALSE;
-
- if (!dbus_message_iter_open_container(iter_dict_entry,
+ if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array ||
+ !_wpa_dbus_add_dict_entry_start(iter_dict, iter_dict_entry,
+ key, DBUS_TYPE_ARRAY) ||
+ !dbus_message_iter_open_container(iter_dict_entry,
DBUS_TYPE_VARIANT,
array_type,
iter_dict_val))
return FALSE;
- if (!dbus_message_iter_open_container(iter_dict_val, DBUS_TYPE_ARRAY,
- type, iter_array))
- return FALSE;
-
- return TRUE;
+ return dbus_message_iter_open_container(iter_dict_val, DBUS_TYPE_ARRAY,
+ type, iter_array);
}
@@ -542,10 +514,8 @@
DBusMessageIter iter_bytes;
size_t i;
- if (!iter_array || !value)
- return FALSE;
-
- if (!dbus_message_iter_open_container(iter_array, DBUS_TYPE_ARRAY,
+ if (!iter_array || !value ||
+ !dbus_message_iter_open_container(iter_array, DBUS_TYPE_ARRAY,
DBUS_TYPE_BYTE_AS_STRING,
&iter_bytes))
return FALSE;
@@ -557,10 +527,7 @@
return FALSE;
}
- if (!dbus_message_iter_close_container(iter_array, &iter_bytes))
- return FALSE;
-
- return TRUE;
+ return dbus_message_iter_close_container(iter_array, &iter_bytes);
}
@@ -586,17 +553,12 @@
DBusMessageIter *iter_dict_val,
DBusMessageIter *iter_array)
{
- if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array)
+ if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array ||
+ !dbus_message_iter_close_container(iter_dict_val, iter_array))
return FALSE;
- if (!dbus_message_iter_close_container(iter_dict_val, iter_array))
- return FALSE;
-
- if (!_wpa_dbus_add_dict_entry_end(iter_dict, iter_dict_entry,
- iter_dict_val))
- return FALSE;
-
- return TRUE;
+ return _wpa_dbus_add_dict_entry_end(iter_dict, iter_dict_entry,
+ iter_dict_val);
}
@@ -619,12 +581,8 @@
DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
dbus_uint32_t i;
- if (!key)
- return FALSE;
- if (!items && (num_items != 0))
- return FALSE;
-
- if (!wpa_dbus_dict_begin_string_array(iter_dict, key,
+ if (!key || (!items && num_items != 0) ||
+ !wpa_dbus_dict_begin_string_array(iter_dict, key,
&iter_dict_entry, &iter_dict_val,
&iter_array))
return FALSE;
@@ -635,11 +593,8 @@
return FALSE;
}
- if (!wpa_dbus_dict_end_string_array(iter_dict, &iter_dict_entry,
- &iter_dict_val, &iter_array))
- return FALSE;
-
- return TRUE;
+ return wpa_dbus_dict_end_string_array(iter_dict, &iter_dict_entry,
+ &iter_dict_val, &iter_array);
}
@@ -662,12 +617,9 @@
DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
dbus_uint32_t i;
- if (!key)
- return FALSE;
- if (!items && (num_items != 0))
- return FALSE;
-
- if (!wpa_dbus_dict_begin_array(iter_dict, key,
+ if (!key ||
+ (!items && num_items != 0) ||
+ !wpa_dbus_dict_begin_array(iter_dict, key,
DBUS_TYPE_ARRAY_AS_STRING
DBUS_TYPE_BYTE_AS_STRING,
&iter_dict_entry, &iter_dict_val,
@@ -681,11 +633,8 @@
return FALSE;
}
- if (!wpa_dbus_dict_end_array(iter_dict, &iter_dict_entry,
- &iter_dict_val, &iter_array))
- return FALSE;
-
- return TRUE;
+ return wpa_dbus_dict_end_array(iter_dict, &iter_dict_entry,
+ &iter_dict_val, &iter_array);
}
@@ -707,16 +656,25 @@
DBusMessageIter *iter_dict,
DBusError *error)
{
+ int type;
+
+ wpa_printf(MSG_MSGDUMP, "%s: start reading a dict entry", __func__);
if (!iter || !iter_dict) {
dbus_set_error_const(error, DBUS_ERROR_FAILED,
- "[internal] missing message iterators");
+ "[internal] missing message iterators");
return FALSE;
}
- if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
+ type = dbus_message_iter_get_arg_type(iter);
+ if (type != DBUS_TYPE_ARRAY ||
dbus_message_iter_get_element_type(iter) != DBUS_TYPE_DICT_ENTRY) {
+ wpa_printf(MSG_DEBUG,
+ "%s: unexpected message argument types (arg=%c element=%c)",
+ __func__, type,
+ type != DBUS_TYPE_ARRAY ? '?' :
+ dbus_message_iter_get_element_type(iter));
dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
- "unexpected message argument types");
+ "unexpected message argument types");
return FALSE;
}
@@ -742,7 +700,6 @@
if (!buffer)
return FALSE;
- entry->bytearray_value = buffer;
entry->array_len = 0;
while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_BYTE) {
char byte;
@@ -753,21 +710,22 @@
BYTE_ARRAY_ITEM_SIZE);
if (nbuffer == NULL) {
os_free(buffer);
- wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_"
- "entry_get_byte_array out of "
- "memory trying to retrieve the "
- "string array");
+ wpa_printf(MSG_ERROR,
+ "dbus: %s out of memory trying to retrieve the string array",
+ __func__);
goto done;
}
buffer = nbuffer;
}
- entry->bytearray_value = buffer;
dbus_message_iter_get_basic(iter, &byte);
- entry->bytearray_value[count] = byte;
+ buffer[count] = byte;
entry->array_len = ++count;
dbus_message_iter_next(iter);
}
+ entry->bytearray_value = buffer;
+ wpa_hexdump_key(MSG_MSGDUMP, "dbus: byte array contents",
+ entry->bytearray_value, entry->array_len);
/* Zero-length arrays are valid. */
if (entry->array_len == 0) {
@@ -790,18 +748,16 @@
struct wpa_dbus_dict_entry *entry)
{
dbus_uint32_t count = 0;
- dbus_bool_t success = FALSE;
char **buffer, **nbuffer;
entry->strarray_value = NULL;
+ entry->array_len = 0;
entry->array_type = DBUS_TYPE_STRING;
buffer = os_calloc(STR_ARRAY_CHUNK_SIZE, STR_ARRAY_ITEM_SIZE);
if (buffer == NULL)
return FALSE;
- entry->strarray_value = buffer;
- entry->array_len = 0;
while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
const char *value;
char *str;
@@ -811,29 +767,31 @@
buffer, count + STR_ARRAY_CHUNK_SIZE,
STR_ARRAY_ITEM_SIZE);
if (nbuffer == NULL) {
- os_free(buffer);
- wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_"
- "entry_get_string_array out of "
- "memory trying to retrieve the "
- "string array");
- goto done;
+ wpa_printf(MSG_ERROR,
+ "dbus: %s out of memory trying to retrieve the string array",
+ __func__);
+ goto fail;
}
buffer = nbuffer;
}
- entry->strarray_value = buffer;
dbus_message_iter_get_basic(iter, &value);
+ wpa_printf(MSG_MSGDUMP, "%s: string_array value: %s",
+ __func__, wpa_debug_show_keys ? value : "[omitted]");
str = os_strdup(value);
if (str == NULL) {
- wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_entry_get_"
- "string_array out of memory trying to "
- "duplicate the string array");
- goto done;
+ wpa_printf(MSG_ERROR,
+ "dbus: %s out of memory trying to duplicate the string array",
+ __func__);
+ goto fail;
}
- entry->strarray_value[count] = str;
- entry->array_len = ++count;
+ buffer[count++] = str;
dbus_message_iter_next(iter);
}
+ entry->strarray_value = buffer;
+ entry->array_len = count;
+ wpa_printf(MSG_MSGDUMP, "%s: string_array length %u",
+ __func__, entry->array_len);
/* Zero-length arrays are valid. */
if (entry->array_len == 0) {
@@ -841,10 +799,15 @@
entry->strarray_value = NULL;
}
- success = TRUE;
+ return TRUE;
-done:
- return success;
+fail:
+ while (count > 0) {
+ count--;
+ os_free(buffer[count]);
+ }
+ os_free(buffer);
+ return FALSE;
}
@@ -856,15 +819,31 @@
{
struct wpa_dbus_dict_entry tmpentry;
size_t buflen = 0;
- int i;
-
- if (dbus_message_iter_get_element_type(iter) != DBUS_TYPE_BYTE)
- return FALSE;
+ int i, type;
entry->array_type = WPAS_DBUS_TYPE_BINARRAY;
entry->array_len = 0;
entry->binarray_value = NULL;
+ type = dbus_message_iter_get_arg_type(iter);
+ wpa_printf(MSG_MSGDUMP, "%s: parsing binarray type %c", __func__, type);
+ if (type == DBUS_TYPE_INVALID) {
+ /* Likely an empty array of arrays */
+ return TRUE;
+ }
+ if (type != DBUS_TYPE_ARRAY) {
+ wpa_printf(MSG_DEBUG, "%s: not an array type: %c",
+ __func__, type);
+ return FALSE;
+ }
+
+ type = dbus_message_iter_get_element_type(iter);
+ if (type != DBUS_TYPE_BYTE) {
+ wpa_printf(MSG_DEBUG, "%s: unexpected element type %c",
+ __func__, type);
+ return FALSE;
+ }
+
while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_ARRAY) {
DBusMessageIter iter_array;
@@ -884,7 +863,7 @@
os_memset(&tmpentry, 0, sizeof(tmpentry));
tmpentry.type = DBUS_TYPE_ARRAY;
if (_wpa_dbus_dict_entry_get_byte_array(&iter_array, &tmpentry)
- == FALSE)
+ == FALSE)
goto cleanup;
entry->binarray_value[entry->array_len] =
@@ -897,6 +876,8 @@
entry->array_len++;
dbus_message_iter_next(iter);
}
+ wpa_printf(MSG_MSGDUMP, "%s: binarray length %u",
+ __func__, entry->array_len);
return TRUE;
@@ -917,12 +898,11 @@
dbus_bool_t success = FALSE;
DBusMessageIter iter_array;
- if (!entry)
- return FALSE;
+ wpa_printf(MSG_MSGDUMP, "%s: array_type %c", __func__, array_type);
dbus_message_iter_recurse(iter_dict_val, &iter_array);
- switch (array_type) {
+ switch (array_type) {
case DBUS_TYPE_BYTE:
success = _wpa_dbus_dict_entry_get_byte_array(&iter_array,
entry);
@@ -936,6 +916,8 @@
success = _wpa_dbus_dict_entry_get_binarray(&iter_array, entry);
break;
default:
+ wpa_printf(MSG_MSGDUMP, "%s: unsupported array type %c",
+ __func__, array_type);
break;
}
@@ -950,42 +932,72 @@
switch (entry->type) {
case DBUS_TYPE_OBJECT_PATH:
+ dbus_message_iter_get_basic(iter, &v);
+ wpa_printf(MSG_MSGDUMP, "%s: object path value: %s",
+ __func__, v);
+ entry->str_value = os_strdup(v);
+ if (entry->str_value == NULL)
+ return FALSE;
+ break;
case DBUS_TYPE_STRING:
dbus_message_iter_get_basic(iter, &v);
+ wpa_printf(MSG_MSGDUMP, "%s: string value: %s",
+ __func__, wpa_debug_show_keys ? v : "[omitted]");
entry->str_value = os_strdup(v);
if (entry->str_value == NULL)
return FALSE;
break;
case DBUS_TYPE_BOOLEAN:
dbus_message_iter_get_basic(iter, &entry->bool_value);
+ wpa_printf(MSG_MSGDUMP, "%s: boolean value: %d",
+ __func__, entry->bool_value);
break;
case DBUS_TYPE_BYTE:
dbus_message_iter_get_basic(iter, &entry->byte_value);
+ wpa_printf(MSG_MSGDUMP, "%s: byte value: %d",
+ __func__, entry->byte_value);
break;
case DBUS_TYPE_INT16:
dbus_message_iter_get_basic(iter, &entry->int16_value);
+ wpa_printf(MSG_MSGDUMP, "%s: int16 value: %d",
+ __func__, entry->int16_value);
break;
case DBUS_TYPE_UINT16:
dbus_message_iter_get_basic(iter, &entry->uint16_value);
+ wpa_printf(MSG_MSGDUMP, "%s: uint16 value: %d",
+ __func__, entry->uint16_value);
break;
case DBUS_TYPE_INT32:
dbus_message_iter_get_basic(iter, &entry->int32_value);
+ wpa_printf(MSG_MSGDUMP, "%s: int32 value: %d",
+ __func__, entry->int32_value);
break;
case DBUS_TYPE_UINT32:
dbus_message_iter_get_basic(iter, &entry->uint32_value);
+ wpa_printf(MSG_MSGDUMP, "%s: uint32 value: %d",
+ __func__, entry->uint32_value);
break;
case DBUS_TYPE_INT64:
dbus_message_iter_get_basic(iter, &entry->int64_value);
+ wpa_printf(MSG_MSGDUMP, "%s: int64 value: %lld",
+ __func__, (long long int) entry->int64_value);
break;
case DBUS_TYPE_UINT64:
dbus_message_iter_get_basic(iter, &entry->uint64_value);
+ wpa_printf(MSG_MSGDUMP, "%s: uint64 value: %llu",
+ __func__,
+ (unsigned long long int) entry->uint64_value);
break;
case DBUS_TYPE_DOUBLE:
dbus_message_iter_get_basic(iter, &entry->double_value);
+ wpa_printf(MSG_MSGDUMP, "%s: double value: %f",
+ __func__, entry->double_value);
break;
case DBUS_TYPE_ARRAY:
return _wpa_dbus_dict_entry_get_array(iter, entry);
default:
+ wpa_printf(MSG_MSGDUMP, "%s: unsupported type %c",
+ __func__, entry->type);
return FALSE;
}
@@ -1016,26 +1028,40 @@
int type;
const char *key;
- if (!iter_dict || !entry)
+ if (!iter_dict || !entry ||
+ dbus_message_iter_get_arg_type(iter_dict) != DBUS_TYPE_DICT_ENTRY) {
+ wpa_printf(MSG_DEBUG, "%s: not a dict entry", __func__);
goto error;
-
- if (dbus_message_iter_get_arg_type(iter_dict) != DBUS_TYPE_DICT_ENTRY)
- goto error;
+ }
dbus_message_iter_recurse(iter_dict, &iter_dict_entry);
dbus_message_iter_get_basic(&iter_dict_entry, &key);
+ wpa_printf(MSG_MSGDUMP, "%s: dict entry key: %s", __func__, key);
entry->key = key;
- if (!dbus_message_iter_next(&iter_dict_entry))
+ if (!dbus_message_iter_next(&iter_dict_entry)) {
+ wpa_printf(MSG_DEBUG, "%s: no variant in dict entry", __func__);
goto error;
+ }
type = dbus_message_iter_get_arg_type(&iter_dict_entry);
- if (type != DBUS_TYPE_VARIANT)
+ if (type != DBUS_TYPE_VARIANT) {
+ wpa_printf(MSG_DEBUG,
+ "%s: unexpected dict entry variant type: %c",
+ __func__, type);
goto error;
+ }
dbus_message_iter_recurse(&iter_dict_entry, &iter_dict_val);
entry->type = dbus_message_iter_get_arg_type(&iter_dict_val);
- if (!_wpa_dbus_dict_fill_value_from_variant(entry, &iter_dict_val))
+ wpa_printf(MSG_MSGDUMP, "%s: dict entry variant content type: %c",
+ __func__, entry->type);
+ entry->array_type = DBUS_TYPE_INVALID;
+ if (!_wpa_dbus_dict_fill_value_from_variant(entry, &iter_dict_val)) {
+ wpa_printf(MSG_DEBUG,
+ "%s: failed to fetch dict values from variant",
+ __func__);
goto error;
+ }
dbus_message_iter_next(iter_dict);
return TRUE;
@@ -1090,6 +1116,8 @@
os_free(entry->bytearray_value);
break;
case DBUS_TYPE_STRING:
+ if (!entry->strarray_value)
+ break;
for (i = 0; i < entry->array_len; i++)
os_free(entry->strarray_value[i]);
os_free(entry->strarray_value);
diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.h b/wpa_supplicant/dbus/dbus_dict_helpers.h
index 9666349..b068431 100644
--- a/wpa_supplicant/dbus/dbus_dict_helpers.h
+++ b/wpa_supplicant/dbus/dbus_dict_helpers.h
@@ -72,28 +72,28 @@
/* Manual construction and addition of array elements */
dbus_bool_t wpa_dbus_dict_begin_array(DBusMessageIter *iter_dict,
- const char *key, const char *type,
- DBusMessageIter *iter_dict_entry,
- DBusMessageIter *iter_dict_val,
- DBusMessageIter *iter_array);
+ const char *key, const char *type,
+ DBusMessageIter *iter_dict_entry,
+ DBusMessageIter *iter_dict_val,
+ DBusMessageIter *iter_array);
dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict,
- const char *key,
- DBusMessageIter *iter_dict_entry,
- DBusMessageIter *iter_dict_val,
- DBusMessageIter *iter_array);
+ const char *key,
+ DBusMessageIter *iter_dict_entry,
+ DBusMessageIter *iter_dict_val,
+ DBusMessageIter *iter_array);
dbus_bool_t wpa_dbus_dict_string_array_add_element(DBusMessageIter *iter_array,
- const char *elem);
+ const char *elem);
dbus_bool_t wpa_dbus_dict_bin_array_add_element(DBusMessageIter *iter_array,
const u8 *value,
size_t value_len);
dbus_bool_t wpa_dbus_dict_end_array(DBusMessageIter *iter_dict,
- DBusMessageIter *iter_dict_entry,
- DBusMessageIter *iter_dict_val,
- DBusMessageIter *iter_array);
+ DBusMessageIter *iter_dict_entry,
+ DBusMessageIter *iter_dict_val,
+ DBusMessageIter *iter_array);
static inline dbus_bool_t
wpa_dbus_dict_end_string_array(DBusMessageIter *iter_dict,
@@ -120,7 +120,11 @@
* Reading a dict from a DBusMessage
*/
-#define WPAS_DBUS_TYPE_BINARRAY (DBUS_NUMBER_OF_TYPES + 100)
+/*
+ * Used only in struct wpa_dbus_dict_entry::array_type internally to identify
+ * special binary array case.
+ */
+#define WPAS_DBUS_TYPE_BINARRAY ((int) '@')
struct wpa_dbus_dict_entry {
int type; /** the dbus type of the dict entry's value */
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index 5e58c5b..30ef03a 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -75,8 +75,7 @@
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
- for (wpa_s = priv->global->ifaces; wpa_s; wpa_s = wpa_s->next)
- {
+ for (wpa_s = priv->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
if (wpa_s->preq_notify_peer != NULL &&
os_strcmp(name, wpa_s->preq_notify_peer) == 0 &&
(new_owner == NULL || os_strlen(new_owner) == 0)) {
@@ -148,22 +147,14 @@
dbus_message_iter_init_append(msg, &iter);
if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
- &wpa_s->dbus_new_path))
- goto err;
-
- if (properties) {
- if (!wpa_dbus_get_object_properties(
- iface, wpa_s->dbus_new_path,
- WPAS_DBUS_NEW_IFACE_INTERFACE, &iter))
- goto err;
- }
-
- dbus_connection_send(iface->con, msg, NULL);
- dbus_message_unref(msg);
- return;
-
-err:
- wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ &wpa_s->dbus_new_path) ||
+ (properties &&
+ !wpa_dbus_get_object_properties(
+ iface, wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_INTERFACE, &iter)))
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
dbus_message_unref(msg);
}
@@ -229,7 +220,7 @@
/**
- * wpas_dbus_signal_blob - Send a BSS related event signal
+ * wpas_dbus_signal_bss - Send a BSS related event signal
* @wpa_s: %wpa_supplicant network interface data
* @bss_obj_path: BSS object path
* @sig_name: signal name - BSSAdded or BSSRemoved
@@ -259,22 +250,14 @@
dbus_message_iter_init_append(msg, &iter);
if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
- &bss_obj_path))
- goto err;
-
- if (properties) {
- if (!wpa_dbus_get_object_properties(iface, bss_obj_path,
- WPAS_DBUS_NEW_IFACE_BSS,
- &iter))
- goto err;
- }
-
- dbus_connection_send(iface->con, msg, NULL);
- dbus_message_unref(msg);
- return;
-
-err:
- wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ &bss_obj_path) ||
+ (properties &&
+ !wpa_dbus_get_object_properties(iface, bss_obj_path,
+ WPAS_DBUS_NEW_IFACE_BSS,
+ &iter)))
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
dbus_message_unref(msg);
}
@@ -407,23 +390,14 @@
dbus_message_iter_init_append(msg, &iter);
path = net_obj_path;
if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
- &path))
- goto err;
-
- if (properties) {
- if (!wpa_dbus_get_object_properties(
- iface, net_obj_path, WPAS_DBUS_NEW_IFACE_NETWORK,
- &iter))
- goto err;
- }
-
- dbus_connection_send(iface->con, msg, NULL);
-
- dbus_message_unref(msg);
- return;
-
-err:
- wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ &path) ||
+ (properties &&
+ !wpa_dbus_get_object_properties(
+ iface, net_obj_path, WPAS_DBUS_NEW_IFACE_NETWORK,
+ &iter)))
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
dbus_message_unref(msg);
}
@@ -513,19 +487,12 @@
dbus_message_iter_init_append(msg, &iter);
if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
- &net_ptr))
- goto err;
- if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &field))
- goto err;
- if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &txt))
- goto err;
-
- dbus_connection_send(iface->con, msg, NULL);
- dbus_message_unref(msg);
- return;
-
-err:
- wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ &net_ptr) ||
+ !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &field) ||
+ !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &txt))
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
dbus_message_unref(msg);
}
@@ -543,6 +510,7 @@
{
char path[WPAS_DBUS_OBJECT_PATH_MAX];
+
os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
"%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
wpa_s->dbus_new_path, ssid->id);
@@ -749,15 +717,11 @@
if (cred->encr_type & WPS_ENCR_AES)
encr_type[et_num++] = "aes";
- if (wpa_s->current_ssid) {
- if (!wpa_dbus_dict_append_byte_array(
- &dict_iter, "BSSID",
- (const char *) wpa_s->current_ssid->bssid,
- ETH_ALEN))
- goto nomem;
- }
-
- if (!wpa_dbus_dict_append_byte_array(&dict_iter, "SSID",
+ if ((wpa_s->current_ssid &&
+ !wpa_dbus_dict_append_byte_array(
+ &dict_iter, "BSSID",
+ (const char *) wpa_s->current_ssid->bssid, ETH_ALEN)) ||
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "SSID",
(const char *) cred->ssid,
cred->ssid_len) ||
!wpa_dbus_dict_append_string_array(&dict_iter, "AuthType",
@@ -784,6 +748,8 @@
void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
int depth, const char *subject,
+ const char *altsubject[],
+ int num_altsubject,
const char *cert_hash,
const struct wpabuf *cert)
{
@@ -804,29 +770,23 @@
return;
dbus_message_iter_init_append(msg, &iter);
- if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
- goto nomem;
-
- if (!wpa_dbus_dict_append_uint32(&dict_iter, "depth", depth) ||
- !wpa_dbus_dict_append_string(&dict_iter, "subject", subject))
- goto nomem;
-
- if (cert_hash &&
- !wpa_dbus_dict_append_string(&dict_iter, "cert_hash", cert_hash))
- goto nomem;
-
- if (cert &&
- !wpa_dbus_dict_append_byte_array(&dict_iter, "cert",
- wpabuf_head(cert),
- wpabuf_len(cert)))
- goto nomem;
-
- if (!wpa_dbus_dict_close_write(&iter, &dict_iter))
- goto nomem;
-
- dbus_connection_send(iface->con, msg, NULL);
-
-nomem:
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+ !wpa_dbus_dict_append_uint32(&dict_iter, "depth", depth) ||
+ !wpa_dbus_dict_append_string(&dict_iter, "subject", subject) ||
+ (altsubject && num_altsubject &&
+ !wpa_dbus_dict_append_string_array(&dict_iter, "altsubject",
+ altsubject, num_altsubject)) ||
+ (cert_hash &&
+ !wpa_dbus_dict_append_string(&dict_iter, "cert_hash",
+ cert_hash)) ||
+ (cert &&
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "cert",
+ wpabuf_head(cert),
+ wpabuf_len(cert))) ||
+ !wpa_dbus_dict_close_write(&iter, &dict_iter))
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
dbus_message_unref(msg);
}
@@ -852,15 +812,12 @@
dbus_message_iter_init_append(msg, &iter);
- if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &status)
- ||
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &status) ||
!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
¶meter))
- goto nomem;
-
- dbus_connection_send(iface->con, msg, NULL);
-
-nomem:
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
dbus_message_unref(msg);
}
@@ -946,49 +903,40 @@
void wpas_dbus_signal_p2p_group_removed(struct wpa_supplicant *wpa_s,
const char *role)
{
- int error = 1;
DBusMessage *msg;
DBusMessageIter iter, dict_iter;
struct wpas_dbus_priv *iface = wpa_s->global->dbus;
+ struct wpa_supplicant *parent;
/* Do nothing if the control interface is not turned on */
if (iface == NULL)
return;
+ parent = wpa_s->parent;
+ if (parent->p2p_mgmt)
+ parent = parent->parent;
+
if (!wpa_s->dbus_groupobj_path)
return;
- msg = dbus_message_new_signal(wpa_s->parent->dbus_new_path,
+ msg = dbus_message_new_signal(parent->dbus_new_path,
WPAS_DBUS_NEW_IFACE_P2PDEVICE,
"GroupFinished");
if (msg == NULL)
return;
dbus_message_iter_init_append(msg, &iter);
- if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
- goto nomem;
-
- if (!wpa_dbus_dict_append_object_path(&dict_iter,
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+ !wpa_dbus_dict_append_object_path(&dict_iter,
"interface_object",
- wpa_s->dbus_new_path))
- goto nomem;
-
- if (!wpa_dbus_dict_append_string(&dict_iter, "role", role))
- goto nomem;
-
- if (!wpa_dbus_dict_append_object_path(&dict_iter, "group_object",
+ wpa_s->dbus_new_path) ||
+ !wpa_dbus_dict_append_string(&dict_iter, "role", role) ||
+ !wpa_dbus_dict_append_object_path(&dict_iter, "group_object",
wpa_s->dbus_groupobj_path) ||
!wpa_dbus_dict_close_write(&iter, &dict_iter))
- goto nomem;
-
- error = 0;
- dbus_connection_send(iface->con, msg, NULL);
-
-nomem:
- if (error > 0)
- wpa_printf(MSG_ERROR,
- "dbus: Failed to construct GroupFinished");
-
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
dbus_message_unref(msg);
}
@@ -1034,6 +982,9 @@
if (iface == NULL)
return;
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
+
if (request || !status) {
if (config_methods & WPS_CONFIG_DISPLAY)
_signal = request ?
@@ -1048,9 +999,10 @@
"ProvisionDiscoveryPBCResponse";
else
return; /* Unknown or un-supported method */
- } else if (!request && status)
+ } else {
/* Explicit check for failure response */
_signal = "ProvisionDiscoveryFailure";
+ }
add_pin = ((request && (config_methods & WPS_CONFIG_DISPLAY)) ||
(!request && !status &&
@@ -1119,6 +1071,9 @@
if (iface == NULL)
return;
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
+
os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
"%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
wpa_s->dbus_new_path, MAC2STR(src));
@@ -1245,8 +1200,13 @@
DBusMessage *msg;
DBusMessageIter iter, dict_iter;
struct wpas_dbus_priv *iface;
+ struct wpa_supplicant *parent;
- iface = wpa_s->parent->global->dbus;
+ parent = wpa_s->parent;
+ if (parent->p2p_mgmt)
+ parent = parent->parent;
+
+ iface = parent->global->dbus;
/* Do nothing if the control interface is not turned on */
if (iface == NULL)
@@ -1256,41 +1216,33 @@
return;
/* New interface has been created for this group */
- msg = dbus_message_new_signal(wpa_s->parent->dbus_new_path,
+ msg = dbus_message_new_signal(parent->dbus_new_path,
WPAS_DBUS_NEW_IFACE_P2PDEVICE,
"GroupStarted");
if (msg == NULL)
return;
dbus_message_iter_init_append(msg, &iter);
- if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
- goto nomem;
-
/*
* In case the device supports creating a separate interface the
* DBus client will need to know the object path for the interface
* object this group was created on, so include it here.
*/
- if (!wpa_dbus_dict_append_object_path(&dict_iter,
- "interface_object",
- wpa_s->dbus_new_path))
- goto nomem;
-
- if (!wpa_dbus_dict_append_string(&dict_iter, "role",
- client ? "client" : "GO"))
- goto nomem;
-
- if (!wpa_dbus_dict_append_object_path(&dict_iter, "group_object",
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+ !wpa_dbus_dict_append_object_path(&dict_iter,
+ "interface_object",
+ wpa_s->dbus_new_path) ||
+ !wpa_dbus_dict_append_string(&dict_iter, "role",
+ client ? "client" : "GO") ||
+ !wpa_dbus_dict_append_object_path(&dict_iter, "group_object",
wpa_s->dbus_groupobj_path) ||
- !wpa_dbus_dict_close_write(&iter, &dict_iter))
- goto nomem;
-
- dbus_connection_send(iface->con, msg, NULL);
-
- if (client)
- peer_groups_changed(wpa_s);
-
-nomem:
+ !wpa_dbus_dict_close_write(&iter, &dict_iter)) {
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ } else {
+ dbus_connection_send(iface->con, msg, NULL);
+ if (client)
+ peer_groups_changed(wpa_s);
+ }
dbus_message_unref(msg);
}
@@ -1315,6 +1267,9 @@
iface = wpa_s->global->dbus;
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
+
os_memset(freqs, 0, sizeof(freqs));
/* Do nothing if the control interface is not turned on */
if (iface == NULL)
@@ -1333,9 +1288,8 @@
return;
dbus_message_iter_init_append(msg, &iter);
- if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
- goto err;
- if (!wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+ !wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
path) ||
!wpa_dbus_dict_append_int32(&dict_iter, "status", res->status))
goto err;
@@ -1344,15 +1298,10 @@
int i = 0;
int freq_list_num = 0;
- if (res->role_go) {
- if (!wpa_dbus_dict_append_byte_array(
- &dict_iter, "passphrase",
- (const char *) res->passphrase,
- sizeof(res->passphrase)))
- goto err;
- }
-
- if (!wpa_dbus_dict_append_string(&dict_iter, "role_go",
+ if ((res->role_go &&
+ !wpa_dbus_dict_append_string(&dict_iter, "passphrase",
+ res->passphrase)) ||
+ !wpa_dbus_dict_append_string(&dict_iter, "role_go",
res->role_go ? "GO" :
"client") ||
!wpa_dbus_dict_append_int32(&dict_iter, "frequency",
@@ -1387,22 +1336,16 @@
DBUS_TYPE_INT32_AS_STRING,
&iter_dict_entry,
&iter_dict_val,
- &iter_dict_array))
- goto err;
-
- if (!dbus_message_iter_append_fixed_array(&iter_dict_array,
+ &iter_dict_array) ||
+ !dbus_message_iter_append_fixed_array(&iter_dict_array,
DBUS_TYPE_INT32,
&f_array,
- freq_list_num))
- goto err;
-
- if (!wpa_dbus_dict_end_array(&dict_iter,
+ freq_list_num) ||
+ !wpa_dbus_dict_end_array(&dict_iter,
&iter_dict_entry,
&iter_dict_val,
- &iter_dict_array))
- goto err;
-
- if (!wpa_dbus_dict_append_int32(&dict_iter, "persistent_group",
+ &iter_dict_array) ||
+ !wpa_dbus_dict_append_int32(&dict_iter, "persistent_group",
res->persistent_group) ||
!wpa_dbus_dict_append_uint32(&dict_iter,
"peer_config_timeout",
@@ -1441,6 +1384,9 @@
if (iface == NULL)
return;
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
+
msg = dbus_message_new_signal(wpa_s->dbus_new_path,
WPAS_DBUS_NEW_IFACE_P2PDEVICE,
"InvitationResult");
@@ -1449,23 +1395,16 @@
return;
dbus_message_iter_init_append(msg, &iter);
- if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
- goto nomem;
-
- if (!wpa_dbus_dict_append_int32(&dict_iter, "status", status))
- goto nomem;
- if (bssid) {
- if (!wpa_dbus_dict_append_byte_array(&dict_iter, "BSSID",
- (const char *) bssid,
- ETH_ALEN))
- goto nomem;
- }
- if (!wpa_dbus_dict_close_write(&iter, &dict_iter))
- goto nomem;
-
- dbus_connection_send(iface->con, msg, NULL);
-
-nomem:
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+ !wpa_dbus_dict_append_int32(&dict_iter, "status", status) ||
+ (bssid &&
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "BSSID",
+ (const char *) bssid,
+ ETH_ALEN)) ||
+ !wpa_dbus_dict_close_write(&iter, &dict_iter))
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
dbus_message_unref(msg);
}
@@ -1486,6 +1425,7 @@
DBusMessage *msg;
DBusMessageIter iter;
char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+ struct wpa_supplicant *parent;
iface = wpa_s->global->dbus;
@@ -1496,10 +1436,14 @@
if (!wpa_s->dbus_groupobj_path)
return;
+ parent = wpa_s->parent;
+ if (parent->p2p_mgmt)
+ parent = parent->parent;
+
os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
"%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
COMPACT_MACSTR,
- wpa_s->parent->dbus_new_path, MAC2STR(peer_addr));
+ parent->dbus_new_path, MAC2STR(peer_addr));
msg = dbus_message_new_signal(wpa_s->dbus_groupobj_path,
WPAS_DBUS_NEW_IFACE_P2P_GROUP,
@@ -1510,18 +1454,12 @@
dbus_message_iter_init_append(msg, &iter);
path = peer_obj_path;
if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
- &path))
- goto err;
-
- dbus_connection_send(iface->con, msg, NULL);
- dbus_message_unref(msg);
-
- wpas_dbus_signal_peer_groups_changed(wpa_s->parent, peer_addr);
-
- return;
-
-err:
- wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ &path)) {
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ } else {
+ dbus_connection_send(iface->con, msg, NULL);
+ wpas_dbus_signal_peer_groups_changed(parent, peer_addr);
+ }
dbus_message_unref(msg);
}
@@ -1542,6 +1480,7 @@
DBusMessage *msg;
DBusMessageIter iter;
char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+ struct wpa_supplicant *parent;
iface = wpa_s->global->dbus;
@@ -1552,10 +1491,14 @@
if (!wpa_s->dbus_groupobj_path)
return;
+ parent = wpa_s->parent;
+ if (parent->p2p_mgmt)
+ parent = parent->parent;
+
os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
"%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
COMPACT_MACSTR,
- wpa_s->dbus_groupobj_path, MAC2STR(peer_addr));
+ parent->dbus_new_path, MAC2STR(peer_addr));
msg = dbus_message_new_signal(wpa_s->dbus_groupobj_path,
WPAS_DBUS_NEW_IFACE_P2P_GROUP,
@@ -1566,19 +1509,13 @@
dbus_message_iter_init_append(msg, &iter);
path = peer_obj_path;
if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
- &path))
- goto err;
-
- dbus_connection_send(iface->con, msg, NULL);
- dbus_message_unref(msg);
-
- wpas_dbus_signal_peer_groups_changed(wpa_s->parent, peer_addr);
-
- return;
-
-err:
- wpa_printf(MSG_ERROR, "dbus: Failed to construct PeerDisconnected "
- "signal");
+ &path)) {
+ wpa_printf(MSG_ERROR,
+ "dbus: Failed to construct PeerDisconnected signal");
+ } else {
+ dbus_connection_send(iface->con, msg, NULL);
+ wpas_dbus_signal_peer_groups_changed(parent, peer_addr);
+ }
dbus_message_unref(msg);
}
@@ -1605,22 +1542,26 @@
DBusMessageIter iter, dict_iter;
struct wpas_dbus_priv *iface;
char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
iface = wpa_s->global->dbus;
/* Do nothing if the control interface is not turned on */
if (iface == NULL)
return;
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
+
+ /* Check if this is a known peer */
+ if (!p2p_peer_known(wpa_s->global->p2p, sa))
+ return;
+
msg = dbus_message_new_signal(wpa_s->dbus_new_path,
WPAS_DBUS_NEW_IFACE_P2PDEVICE,
"ServiceDiscoveryRequest");
if (msg == NULL)
return;
- /* Check if this is a known peer */
- if (!p2p_peer_known(wpa_s->global->p2p, sa))
- goto error;
-
os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
"%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
COMPACT_MACSTR, wpa_s->dbus_new_path, MAC2STR(sa));
@@ -1628,11 +1569,8 @@
path = peer_obj_path;
dbus_message_iter_init_append(msg, &iter);
- if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
- goto error;
-
-
- if (!wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+ !wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
path) ||
!wpa_dbus_dict_append_int32(&dict_iter, "frequency", freq) ||
!wpa_dbus_dict_append_int32(&dict_iter, "dialog_token",
@@ -1643,13 +1581,9 @@
(const char *) tlvs,
tlvs_len) ||
!wpa_dbus_dict_close_write(&iter, &dict_iter))
- goto error;
-
- dbus_connection_send(iface->con, msg, NULL);
- dbus_message_unref(msg);
- return;
-error:
- wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
dbus_message_unref(msg);
}
@@ -1674,21 +1608,25 @@
DBusMessageIter iter, dict_iter;
struct wpas_dbus_priv *iface;
char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
iface = wpa_s->global->dbus;
/* Do nothing if the control interface is not turned on */
if (iface == NULL)
return;
- msg = dbus_message_new_signal(wpa_s->dbus_new_path,
- WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- "ServiceDiscoveryResponse");
- if (msg == NULL)
- return;
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
/* Check if this is a known peer */
if (!p2p_peer_known(wpa_s->global->p2p, sa))
- goto error;
+ return;
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ "ServiceDiscoveryResponse");
+ if (msg == NULL)
+ return;
os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
"%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
@@ -1697,10 +1635,8 @@
path = peer_obj_path;
dbus_message_iter_init_append(msg, &iter);
- if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
- goto error;
-
- if (!wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+ !wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
path) ||
!wpa_dbus_dict_append_uint16(&dict_iter, "update_indicator",
update_indic) ||
@@ -1708,17 +1644,13 @@
(const char *) tlvs,
tlvs_len) ||
!wpa_dbus_dict_close_write(&iter, &dict_iter))
- goto error;
-
-
- dbus_connection_send(iface->con, msg, NULL);
- dbus_message_unref(msg);
- return;
-error:
- wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
dbus_message_unref(msg);
}
+
/**
* wpas_dbus_signal_persistent_group - Send a persistent group related
* event signal
@@ -1744,6 +1676,9 @@
if (iface == NULL)
return;
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
+
os_snprintf(pgrp_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
"%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%u",
wpa_s->dbus_new_path, id);
@@ -1757,23 +1692,15 @@
dbus_message_iter_init_append(msg, &iter);
path = pgrp_obj_path;
if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
- &path))
- goto err;
+ &path) ||
+ (properties &&
+ !wpa_dbus_get_object_properties(
+ iface, pgrp_obj_path,
+ WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP, &iter)))
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
- if (properties) {
- if (!wpa_dbus_get_object_properties(
- iface, pgrp_obj_path,
- WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP, &iter))
- goto err;
- }
-
- dbus_connection_send(iface->con, msg, NULL);
-
- dbus_message_unref(msg);
- return;
-
-err:
- wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
dbus_message_unref(msg);
}
@@ -1832,6 +1759,9 @@
if (iface == NULL)
return;
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
+
msg = dbus_message_new_signal(wpa_s->dbus_new_path,
WPAS_DBUS_NEW_IFACE_P2PDEVICE,
"WpsFailed");
@@ -1853,7 +1783,7 @@
dbus_message_unref(msg);
}
-#endif /*CONFIG_P2P*/
+#endif /* CONFIG_P2P */
/**
@@ -2047,7 +1977,7 @@
static const struct wpa_dbus_method_desc wpas_dbus_global_methods[] = {
{ "CreateInterface", WPAS_DBUS_NEW_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_create_interface,
+ (WPADBusMethodHandler) wpas_dbus_handler_create_interface,
{
{ "args", "a{sv}", ARG_IN },
{ "path", "o", ARG_OUT },
@@ -2055,14 +1985,14 @@
}
},
{ "RemoveInterface", WPAS_DBUS_NEW_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_remove_interface,
+ (WPADBusMethodHandler) wpas_dbus_handler_remove_interface,
{
{ "path", "o", ARG_IN },
END_ARGS
}
},
{ "GetInterface", WPAS_DBUS_NEW_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_get_interface,
+ (WPADBusMethodHandler) wpas_dbus_handler_get_interface,
{
{ "ifname", "s", ARG_IN },
{ "path", "o", ARG_OUT },
@@ -2120,14 +2050,6 @@
END_ARGS
}
},
- { "NetworkRequest", WPAS_DBUS_NEW_IFACE_INTERFACE,
- {
- { "path", "o", ARG_OUT },
- { "field", "s", ARG_OUT },
- { "text", "s", ARG_OUT },
- END_ARGS
- }
- },
/* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
{ "PropertiesChanged", WPAS_DBUS_NEW_INTERFACE,
{
@@ -2154,8 +2076,8 @@
obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
if (!obj_desc) {
- wpa_printf(MSG_ERROR, "Not enough memory "
- "to create object description");
+ wpa_printf(MSG_ERROR,
+ "Not enough memory to create object description");
return -1;
}
@@ -2269,16 +2191,16 @@
net_obj_path);
obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
if (!obj_desc) {
- wpa_printf(MSG_ERROR, "Not enough memory "
- "to create object description");
+ wpa_printf(MSG_ERROR,
+ "Not enough memory to create object description");
goto err;
}
/* allocate memory for handlers arguments */
arg = os_zalloc(sizeof(struct network_handler_args));
if (!arg) {
- wpa_printf(MSG_ERROR, "Not enough memory "
- "to create arguments for method");
+ wpa_printf(MSG_ERROR,
+ "Not enough memory to create arguments for method");
goto err;
}
@@ -2484,15 +2406,15 @@
obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
if (!obj_desc) {
- wpa_printf(MSG_ERROR, "Not enough memory "
- "to create object description");
+ wpa_printf(MSG_ERROR,
+ "Not enough memory to create object description");
goto err;
}
arg = os_zalloc(sizeof(struct bss_handler_args));
if (!arg) {
- wpa_printf(MSG_ERROR, "Not enough memory "
- "to create arguments for handler");
+ wpa_printf(MSG_ERROR,
+ "Not enough memory to create arguments for handler");
goto err;
}
arg->wpa_s = wpa_s;
@@ -2525,27 +2447,27 @@
static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
{ "Scan", WPAS_DBUS_NEW_IFACE_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_scan,
+ (WPADBusMethodHandler) wpas_dbus_handler_scan,
{
{ "args", "a{sv}", ARG_IN },
END_ARGS
}
},
{ "SignalPoll", WPAS_DBUS_NEW_IFACE_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_signal_poll,
+ (WPADBusMethodHandler) wpas_dbus_handler_signal_poll,
{
{ "args", "a{sv}", ARG_OUT },
END_ARGS
}
},
{ "Disconnect", WPAS_DBUS_NEW_IFACE_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_disconnect,
+ (WPADBusMethodHandler) wpas_dbus_handler_disconnect,
{
END_ARGS
}
},
{ "AddNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_add_network,
+ (WPADBusMethodHandler) wpas_dbus_handler_add_network,
{
{ "args", "a{sv}", ARG_IN },
{ "path", "o", ARG_OUT },
@@ -2553,39 +2475,39 @@
}
},
{ "Reassociate", WPAS_DBUS_NEW_IFACE_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_reassociate,
+ (WPADBusMethodHandler) wpas_dbus_handler_reassociate,
{
END_ARGS
}
},
{ "Reattach", WPAS_DBUS_NEW_IFACE_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_reattach,
+ (WPADBusMethodHandler) wpas_dbus_handler_reattach,
{
END_ARGS
}
},
{ "RemoveNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_remove_network,
+ (WPADBusMethodHandler) wpas_dbus_handler_remove_network,
{
{ "path", "o", ARG_IN },
END_ARGS
}
},
{ "RemoveAllNetworks", WPAS_DBUS_NEW_IFACE_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_remove_all_networks,
+ (WPADBusMethodHandler) wpas_dbus_handler_remove_all_networks,
{
END_ARGS
}
},
{ "SelectNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_select_network,
+ (WPADBusMethodHandler) wpas_dbus_handler_select_network,
{
{ "path", "o", ARG_IN },
END_ARGS
}
},
{ "NetworkReply", WPAS_DBUS_NEW_IFACE_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_network_reply,
+ (WPADBusMethodHandler) wpas_dbus_handler_network_reply,
{
{ "path", "o", ARG_IN },
{ "field", "s", ARG_IN },
@@ -2595,7 +2517,7 @@
},
#ifndef CONFIG_NO_CONFIG_BLOBS
{ "AddBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_add_blob,
+ (WPADBusMethodHandler) wpas_dbus_handler_add_blob,
{
{ "name", "s", ARG_IN },
{ "data", "ay", ARG_IN },
@@ -2603,7 +2525,7 @@
}
},
{ "GetBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_get_blob,
+ (WPADBusMethodHandler) wpas_dbus_handler_get_blob,
{
{ "name", "s", ARG_IN },
{ "data", "ay", ARG_OUT },
@@ -2611,7 +2533,7 @@
}
},
{ "RemoveBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_remove_blob,
+ (WPADBusMethodHandler) wpas_dbus_handler_remove_blob,
{
{ "name", "s", ARG_IN },
END_ARGS
@@ -2620,7 +2542,7 @@
#endif /* CONFIG_NO_CONFIG_BLOBS */
{ "SetPKCS11EngineAndModulePath", WPAS_DBUS_NEW_IFACE_INTERFACE,
(WPADBusMethodHandler)
- &wpas_dbus_handler_set_pkcs11_engine_and_module_path,
+ wpas_dbus_handler_set_pkcs11_engine_and_module_path,
{
{ "pkcs11_engine_path", "s", ARG_IN },
{ "pkcs11_module_path", "s", ARG_IN },
@@ -2629,7 +2551,7 @@
},
#ifdef CONFIG_WPS
{ "Start", WPAS_DBUS_NEW_IFACE_WPS,
- (WPADBusMethodHandler) &wpas_dbus_handler_wps_start,
+ (WPADBusMethodHandler) wpas_dbus_handler_wps_start,
{
{ "args", "a{sv}", ARG_IN },
{ "output", "a{sv}", ARG_OUT },
@@ -2639,41 +2561,41 @@
#endif /* CONFIG_WPS */
#ifdef CONFIG_P2P
{ "Find", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_find,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_find,
{
{ "args", "a{sv}", ARG_IN },
END_ARGS
}
},
{ "StopFind", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_stop_find,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_stop_find,
{
END_ARGS
}
},
{ "Listen", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_listen,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_listen,
{
{ "timeout", "i", ARG_IN },
END_ARGS
}
},
{ "ExtendedListen", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_extendedlisten,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_extendedlisten,
{
{ "args", "a{sv}", ARG_IN },
END_ARGS
}
},
{ "PresenceRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_presence_request,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_presence_request,
{
{ "args", "a{sv}", ARG_IN },
END_ARGS
}
},
{ "ProvisionDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_prov_disc_req,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_prov_disc_req,
{
{ "peer", "o", ARG_IN },
{ "config_method", "s", ARG_IN },
@@ -2681,7 +2603,7 @@
}
},
{ "Connect", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_connect,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_connect,
{
{ "args", "a{sv}", ARG_IN },
{ "generated_pin", "s", ARG_OUT },
@@ -2689,60 +2611,60 @@
}
},
{ "GroupAdd", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_group_add,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_group_add,
{
{ "args", "a{sv}", ARG_IN },
END_ARGS
}
},
{ "Invite", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_invite,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_invite,
{
{ "args", "a{sv}", ARG_IN },
END_ARGS
}
},
{ "Disconnect", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_disconnect,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_disconnect,
{
END_ARGS
}
},
{ "RejectPeer", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_rejectpeer,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_rejectpeer,
{
{ "peer", "o", ARG_IN },
END_ARGS
}
},
{ "Flush", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_flush,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_flush,
{
END_ARGS
}
},
{ "AddService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_add_service,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_add_service,
{
{ "args", "a{sv}", ARG_IN },
END_ARGS
}
},
{ "DeleteService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_delete_service,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_delete_service,
{
{ "args", "a{sv}", ARG_IN },
END_ARGS
}
},
{ "FlushService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_flush_service,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_flush_service,
{
END_ARGS
}
},
{ "ServiceDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_req,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_service_sd_req,
{
{ "args", "a{sv}", ARG_IN },
{ "ref", "t", ARG_OUT },
@@ -2750,27 +2672,27 @@
}
},
{ "ServiceDiscoveryResponse", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_res,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_service_sd_res,
{
{ "args", "a{sv}", ARG_IN },
END_ARGS
}
},
{ "ServiceDiscoveryCancelRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_cancel_req,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_service_sd_cancel_req,
{
{ "args", "t", ARG_IN },
END_ARGS
}
},
{ "ServiceUpdate", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_update,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_service_update,
{
END_ARGS
}
},
{ "ServiceDiscoveryExternal", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- (WPADBusMethodHandler)wpas_dbus_handler_p2p_serv_disc_external,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_serv_disc_external,
{
{ "arg", "i", ARG_IN },
END_ARGS
@@ -2800,7 +2722,7 @@
},
#endif /* CONFIG_P2P */
{ "FlushBSS", WPAS_DBUS_NEW_IFACE_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_flush_bss,
+ (WPADBusMethodHandler) wpas_dbus_handler_flush_bss,
{
{ "age", "u", ARG_IN },
END_ARGS
@@ -2821,20 +2743,20 @@
},
#endif /* CONFIG_AP */
{ "EAPLogoff", WPAS_DBUS_NEW_IFACE_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_eap_logoff,
+ (WPADBusMethodHandler) wpas_dbus_handler_eap_logoff,
{
END_ARGS
}
},
{ "EAPLogon", WPAS_DBUS_NEW_IFACE_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_eap_logon,
+ (WPADBusMethodHandler) wpas_dbus_handler_eap_logon,
{
END_ARGS
}
},
#ifdef CONFIG_AUTOSCAN
{ "AutoScan", WPAS_DBUS_NEW_IFACE_INTERFACE,
- (WPADBusMethodHandler) &wpas_dbus_handler_autoscan,
+ (WPADBusMethodHandler) wpas_dbus_handler_autoscan,
{
{ "arg", "s", ARG_IN },
END_ARGS
@@ -3080,12 +3002,6 @@
},
#endif /* CONFIG_WPS */
#ifdef CONFIG_P2P
- { "P2PStateChanged", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
- {
- { "states", "a{ss}", ARG_OUT },
- END_ARGS
- }
- },
{ "DeviceFound", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
{
{ "path", "o", ARG_OUT },
@@ -3246,6 +3162,14 @@
END_ARGS
}
},
+ { "NetworkRequest", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ {
+ { "path", "o", ARG_OUT },
+ { "field", "s", ARG_OUT },
+ { "text", "s", ARG_OUT },
+ END_ARGS
+ }
+ },
{ NULL, NULL, { END_ARGS } }
};
@@ -3272,8 +3196,8 @@
obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
if (!obj_desc) {
- wpa_printf(MSG_ERROR, "Not enough memory "
- "to create object description");
+ wpa_printf(MSG_ERROR,
+ "Not enough memory to create object description");
goto err;
}
@@ -3308,7 +3232,7 @@
if (wpa_s == NULL || wpa_s->global == NULL)
return 0;
ctrl_iface = wpa_s->global->dbus;
- if (ctrl_iface == NULL)
+ if (ctrl_iface == NULL || wpa_s->dbus_new_path == NULL)
return 0;
wpa_printf(MSG_DEBUG, "dbus: Unregister interface object '%s'",
@@ -3415,6 +3339,9 @@
DBusMessageIter iter;
char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
+
iface = wpa_s->global->dbus;
/* Do nothing if the control interface is not turned on */
@@ -3434,15 +3361,10 @@
path = peer_obj_path;
if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
&path))
- goto err;
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
- dbus_connection_send(iface->con, msg, NULL);
-
- dbus_message_unref(msg);
- return;
-
-err:
- wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
dbus_message_unref(msg);
}
@@ -3500,6 +3422,9 @@
if (ctrl_iface == NULL)
return 0;
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
+
os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
"%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
wpa_s->dbus_new_path, MAC2STR(dev_addr));
@@ -3508,16 +3433,16 @@
peer_obj_path);
obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
if (!obj_desc) {
- wpa_printf(MSG_ERROR, "Not enough memory "
- "to create object description");
+ wpa_printf(MSG_ERROR,
+ "Not enough memory to create object description");
goto err;
}
/* allocate memory for handlers arguments */
arg = os_zalloc(sizeof(struct peer_handler_args));
if (!arg) {
- wpa_printf(MSG_ERROR, "Not enough memory "
- "to create arguments for method");
+ wpa_printf(MSG_ERROR,
+ "Not enough memory to create arguments for method");
goto err;
}
@@ -3559,6 +3484,10 @@
if (wpa_s == NULL || wpa_s->global == NULL ||
wpa_s->dbus_new_path == NULL)
return 0;
+
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
+
ctrl_iface = wpa_s->global->dbus;
if (ctrl_iface == NULL)
return 0;
@@ -3580,6 +3509,9 @@
{
char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
+
os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
"%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
wpa_s->dbus_new_path, MAC2STR(dev_addr));
@@ -3685,8 +3617,8 @@
group_obj_path);
obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
if (!obj_desc) {
- wpa_printf(MSG_ERROR, "Not enough memory "
- "to create object description");
+ wpa_printf(MSG_ERROR,
+ "Not enough memory to create object description");
goto err;
}
@@ -3723,6 +3655,9 @@
if (wpa_s == NULL || wpa_s->global == NULL)
return;
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
+
ctrl_iface = wpa_s->global->dbus;
if (ctrl_iface == NULL)
return;
@@ -3783,6 +3718,9 @@
if (ssid->disabled != 2 && !ssid->p2p_persistent_group)
return -1; /* should we return w/o complaining? */
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
+
ctrl_iface = wpa_s->global->dbus;
if (ctrl_iface == NULL)
return 0;
@@ -3799,8 +3737,8 @@
pgrp_obj_path);
obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
if (!obj_desc) {
- wpa_printf(MSG_ERROR, "dbus: Not enough memory to create "
- "object description");
+ wpa_printf(MSG_ERROR,
+ "dbus: Not enough memory to create object description");
goto err;
}
@@ -3811,8 +3749,8 @@
/* allocate memory for handlers arguments */
arg = os_zalloc(sizeof(struct network_handler_args));
if (!arg) {
- wpa_printf(MSG_ERROR, "dbus: Not enough memory to create "
- "arguments for method");
+ wpa_printf(MSG_ERROR,
+ "dbus: Not enough memory to create arguments for method");
goto err;
}
@@ -3862,6 +3800,10 @@
if (wpa_s == NULL || wpa_s->global == NULL ||
wpa_s->dbus_new_path == NULL)
return 0;
+
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
+
ctrl_iface = wpa_s->global->dbus;
if (ctrl_iface == NULL)
return 0;
diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h
index 5f32bbf..d162d2b 100644
--- a/wpa_supplicant/dbus/dbus_new.h
+++ b/wpa_supplicant/dbus/dbus_new.h
@@ -215,6 +215,8 @@
struct wps_event_fail *fail);
void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
int depth, const char *subject,
+ const char *altsubject[],
+ int num_altsubject,
const char *cert_hash,
const struct wpabuf *cert);
void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s,
@@ -484,6 +486,8 @@
static inline void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
int depth,
const char *subject,
+ const char *altsubject[],
+ int num_altsubject,
const char *cert_hash,
const struct wpabuf *cert)
{
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 9f6c4a3..e7c2dd8 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -2,7 +2,7 @@
* WPA Supplicant / dbus-based control interface
* Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
* Copyright (c) 2009-2010, Witold Sowa <witold.sowa@gmail.com>
- * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -29,13 +29,13 @@
#include "dbus_common_i.h"
#include "drivers/driver.h"
-static const char *debug_strings[] = {
+static const char * const debug_strings[] = {
"excessive", "msgdump", "debug", "info", "warning", "error", NULL
};
/**
- * wpas_dbus_error_unknown_error - Return a new InvalidArgs error message
+ * wpas_dbus_error_unknown_error - Return a new UnknownError error message
* @message: Pointer to incoming dbus message this error refers to
* @arg: Optional string appended to error message
* Returns: a dbus error message
@@ -45,20 +45,6 @@
DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message,
const char *arg)
{
- /*
- * This function can be called as a result of a failure
- * within internal getter calls, which will call this function
- * with a NULL message parameter. However, dbus_message_new_error
- * looks very unkindly (i.e, abort()) on a NULL message, so
- * in this case, we should not call it.
- */
- if (message == NULL) {
- wpa_printf(MSG_INFO, "dbus: wpas_dbus_error_unknown_error "
- "called with NULL message (arg=%s)",
- arg ? arg : "N/A");
- return NULL;
- }
-
return dbus_message_new_error(message, WPAS_DBUS_ERROR_UNKNOWN_ERROR,
arg);
}
@@ -73,9 +59,9 @@
*/
static DBusMessage * wpas_dbus_error_iface_unknown(DBusMessage *message)
{
- return dbus_message_new_error(message, WPAS_DBUS_ERROR_IFACE_UNKNOWN,
- "wpa_supplicant knows nothing about "
- "this interface.");
+ return dbus_message_new_error(
+ message, WPAS_DBUS_ERROR_IFACE_UNKNOWN,
+ "wpa_supplicant knows nothing about this interface.");
}
@@ -88,9 +74,9 @@
*/
static DBusMessage * wpas_dbus_error_network_unknown(DBusMessage *message)
{
- return dbus_message_new_error(message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
- "There is no such a network in this "
- "interface.");
+ return dbus_message_new_error(
+ message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
+ "There is no such a network in this interface.");
}
@@ -106,9 +92,9 @@
{
DBusMessage *reply;
- reply = dbus_message_new_error(message, WPAS_DBUS_ERROR_INVALID_ARGS,
- "Did not receive correct message "
- "arguments.");
+ reply = dbus_message_new_error(
+ message, WPAS_DBUS_ERROR_INVALID_ARGS,
+ "Did not receive correct message arguments.");
if (arg != NULL)
dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg,
DBUS_TYPE_INVALID);
@@ -125,20 +111,23 @@
*
* Convenience function to create and return a scan error
*/
-DBusMessage * wpas_dbus_error_scan_error(DBusMessage *message,
- const char *error)
+static DBusMessage * wpas_dbus_error_scan_error(DBusMessage *message,
+ const char *error)
{
- DBusMessage *reply;
-
- reply = dbus_message_new_error(message,
- WPAS_DBUS_ERROR_IFACE_SCAN_ERROR,
- error);
-
- return reply;
+ return dbus_message_new_error(message,
+ WPAS_DBUS_ERROR_IFACE_SCAN_ERROR,
+ error);
}
-static const char *dont_quote[] = {
+DBusMessage * wpas_dbus_error_no_memory(DBusMessage *message)
+{
+ wpa_printf(MSG_DEBUG, "dbus: Failed to allocate memory");
+ return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
+}
+
+
+static const char * const dont_quote[] = {
"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
"opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
"bssid", "scan_freq", "freq_list", NULL
@@ -147,6 +136,7 @@
static dbus_bool_t should_quote_opt(const char *key)
{
int i = 0;
+
while (dont_quote[i] != NULL) {
if (os_strcmp(key, dont_quote[i]) == 0)
return FALSE;
@@ -233,7 +223,7 @@
ret = os_snprintf(value, size, "\"%s\"",
entry.str_value);
- if (ret < 0 || (size_t) ret != (size - 1))
+ if (os_snprintf_error(size, ret))
goto error;
} else {
value = os_strdup(entry.str_value);
@@ -247,7 +237,7 @@
ret = os_snprintf(value, size, "%u",
entry.uint32_value);
- if (ret <= 0)
+ if (os_snprintf_error(size, ret))
goto error;
} else if (entry.type == DBUS_TYPE_INT32) {
value = os_zalloc(size);
@@ -256,7 +246,7 @@
ret = os_snprintf(value, size, "%d",
entry.int32_value);
- if (ret <= 0)
+ if (os_snprintf_error(size, ret))
goto error;
} else
goto error;
@@ -264,6 +254,19 @@
if (wpa_config_set(ssid, entry.key, value, 0) < 0)
goto error;
+ if (os_strcmp(entry.key, "bssid") != 0 &&
+ os_strcmp(entry.key, "priority") != 0)
+ wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
+
+ if (wpa_s->current_ssid == ssid ||
+ wpa_s->current_ssid == NULL) {
+ /*
+ * Invalidate the EAP session cache if anything in the
+ * current or previously used configuration changes.
+ */
+ eapol_sm_invalidate_cached_session(wpa_s->eapol);
+ }
+
if ((os_strcmp(entry.key, "psk") == 0 &&
value[0] == '"' && ssid->ssid_len) ||
(os_strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
@@ -306,27 +309,21 @@
if (!dbus_type_is_basic(type)) {
dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: given type is not basic", __func__);
+ "%s: given type is not basic", __func__);
return FALSE;
}
if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
- wpa_dbus_type_as_string(type),
- &variant_iter))
- goto error;
-
- if (!dbus_message_iter_append_basic(&variant_iter, type, val))
- goto error;
-
- if (!dbus_message_iter_close_container(iter, &variant_iter))
- goto error;
+ wpa_dbus_type_as_string(type),
+ &variant_iter) ||
+ !dbus_message_iter_append_basic(&variant_iter, type, val) ||
+ !dbus_message_iter_close_container(iter, &variant_iter)) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: error constructing reply", __func__);
+ return FALSE;
+ }
return TRUE;
-
-error:
- dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: error constructing reply", __func__);
- return FALSE;
}
@@ -389,7 +386,7 @@
if (!dbus_type_is_basic(type)) {
dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: given type is not basic", __func__);
+ "%s: given type is not basic", __func__);
return FALSE;
}
@@ -397,20 +394,15 @@
type_str[1] = sub_type_str[0];
if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
- type_str, &variant_iter)) {
- dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: failed to construct message 1", __func__);
- return FALSE;
- }
-
- if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
+ type_str, &variant_iter) ||
+ !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
sub_type_str, &array_iter)) {
dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: failed to construct message 2", __func__);
+ "%s: failed to construct message", __func__);
return FALSE;
}
- switch(type) {
+ switch (type) {
case DBUS_TYPE_BYTE:
case DBUS_TYPE_BOOLEAN:
element_size = 1;
@@ -436,7 +428,7 @@
break;
default:
dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: unknown element type %d", __func__, type);
+ "%s: unknown element type %d", __func__, type);
return FALSE;
}
@@ -450,15 +442,10 @@
}
}
- if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) {
+ if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
+ !dbus_message_iter_close_container(iter, &variant_iter)) {
dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: failed to construct message 3", __func__);
- return FALSE;
- }
-
- if (!dbus_message_iter_close_container(iter, &variant_iter)) {
- dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: failed to construct message 4", __func__);
+ "%s: failed to construct message 3", __func__);
return FALSE;
}
@@ -501,15 +488,11 @@
inner_type_str[1] = sub_type_str[0];
if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
- type_str, &variant_iter)) {
- dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: failed to construct message 1", __func__);
- return FALSE;
- }
- if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
+ type_str, &variant_iter) ||
+ !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
inner_type_str, &array_iter)) {
dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: failed to construct message 2", __func__);
+ "%s: failed to construct message", __func__);
return FALSE;
}
@@ -520,15 +503,10 @@
}
- if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) {
+ if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
+ !dbus_message_iter_close_container(iter, &variant_iter)) {
dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: failed to close message 2", __func__);
- return FALSE;
- }
-
- if (!dbus_message_iter_close_container(iter, &variant_iter)) {
- dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: failed to close message 1", __func__);
+ "%s: failed to close message", __func__);
return FALSE;
}
@@ -566,34 +544,34 @@
while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto error;
- if (!os_strcmp(entry.key, "Driver") &&
- (entry.type == DBUS_TYPE_STRING)) {
+ if (os_strcmp(entry.key, "Driver") == 0 &&
+ entry.type == DBUS_TYPE_STRING) {
os_free(driver);
driver = os_strdup(entry.str_value);
wpa_dbus_dict_entry_clear(&entry);
if (driver == NULL)
- goto error;
- } else if (!os_strcmp(entry.key, "Ifname") &&
- (entry.type == DBUS_TYPE_STRING)) {
+ goto oom;
+ } else if (os_strcmp(entry.key, "Ifname") == 0 &&
+ entry.type == DBUS_TYPE_STRING) {
os_free(ifname);
ifname = os_strdup(entry.str_value);
wpa_dbus_dict_entry_clear(&entry);
if (ifname == NULL)
- goto error;
- } else if (!os_strcmp(entry.key, "ConfigFile") &&
- (entry.type == DBUS_TYPE_STRING)) {
+ goto oom;
+ } else if (os_strcmp(entry.key, "ConfigFile") == 0 &&
+ entry.type == DBUS_TYPE_STRING) {
os_free(confname);
confname = os_strdup(entry.str_value);
wpa_dbus_dict_entry_clear(&entry);
if (confname == NULL)
- goto error;
- } else if (!os_strcmp(entry.key, "BridgeIfname") &&
- (entry.type == DBUS_TYPE_STRING)) {
+ goto oom;
+ } else if (os_strcmp(entry.key, "BridgeIfname") == 0 &&
+ entry.type == DBUS_TYPE_STRING) {
os_free(bridge_ifname);
bridge_ifname = os_strdup(entry.str_value);
wpa_dbus_dict_entry_clear(&entry);
if (bridge_ifname == NULL)
- goto error;
+ goto oom;
} else {
wpa_dbus_dict_entry_clear(&entry);
goto error;
@@ -608,28 +586,30 @@
* an error if we already control it.
*/
if (wpa_supplicant_get_iface(global, ifname) != NULL) {
- reply = dbus_message_new_error(message,
- WPAS_DBUS_ERROR_IFACE_EXISTS,
- "wpa_supplicant already "
- "controls this interface.");
+ reply = dbus_message_new_error(
+ message, WPAS_DBUS_ERROR_IFACE_EXISTS,
+ "wpa_supplicant already controls this interface.");
} else {
struct wpa_supplicant *wpa_s;
struct wpa_interface iface;
+
os_memset(&iface, 0, sizeof(iface));
iface.driver = driver;
iface.ifname = ifname;
iface.confname = confname;
iface.bridge_ifname = bridge_ifname;
/* Otherwise, have wpa_supplicant attach to it. */
- if ((wpa_s = wpa_supplicant_add_iface(global, &iface))) {
+ wpa_s = wpa_supplicant_add_iface(global, &iface);
+ if (wpa_s) {
const char *path = wpa_s->dbus_new_path;
+
reply = dbus_message_new_method_return(message);
dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
- &path, DBUS_TYPE_INVALID);
+ &path, DBUS_TYPE_INVALID);
} else {
reply = wpas_dbus_error_unknown_error(
- message, "wpa_supplicant couldn't grab this "
- "interface.");
+ message,
+ "wpa_supplicant couldn't grab this interface.");
}
}
@@ -643,6 +623,9 @@
error:
reply = wpas_dbus_error_invalid_args(message, NULL);
goto out;
+oom:
+ reply = wpas_dbus_error_no_memory(message);
+ goto out;
}
@@ -672,8 +655,8 @@
reply = wpas_dbus_error_iface_unknown(message);
else if (wpa_supplicant_remove_iface(global, wpa_s, 0)) {
reply = wpas_dbus_error_unknown_error(
- message, "wpa_supplicant couldn't remove this "
- "interface.");
+ message,
+ "wpa_supplicant couldn't remove this interface.");
}
return reply;
@@ -707,13 +690,11 @@
path = wpa_s->dbus_new_path;
reply = dbus_message_new_method_return(message);
if (reply == NULL)
- return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
+ return wpas_dbus_error_no_memory(message);
if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID)) {
dbus_message_unref(reply);
- return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
+ return wpas_dbus_error_no_memory(message);
}
return reply;
@@ -756,8 +737,8 @@
* Getter for "DebugTimestamp" property.
*/
dbus_bool_t wpas_dbus_getter_debug_timestamp(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+ DBusError *error,
+ void *user_data)
{
return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
&wpa_debug_timestamp, error);
@@ -812,8 +793,8 @@
if (val < 0 ||
wpa_supplicant_set_debug_params(global, val, wpa_debug_timestamp,
wpa_debug_show_keys)) {
- dbus_set_error_const(error, DBUS_ERROR_FAILED, "wrong debug "
- "level value");
+ dbus_set_error_const(error, DBUS_ERROR_FAILED,
+ "wrong debug level value");
return FALSE;
}
@@ -963,8 +944,8 @@
* and P2P that are determined at compile time.
*/
dbus_bool_t wpas_dbus_getter_global_capabilities(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+ DBusError *error,
+ void *user_data)
{
const char *capabilities[5] = { NULL, NULL, NULL, NULL, NULL };
size_t num_items = 0;
@@ -993,8 +974,8 @@
char **type, DBusMessage **reply)
{
if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_STRING) {
- wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
- "Type must be a string");
+ wpa_printf(MSG_DEBUG, "%s[dbus]: Type must be a string",
+ __func__);
*reply = wpas_dbus_error_invalid_args(
message, "Wrong Type value type. String required");
return -1;
@@ -1016,36 +997,36 @@
int len;
if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
- wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ssids "
- "must be an array of arrays of bytes");
+ wpa_printf(MSG_DEBUG,
+ "%s[dbus]: ssids must be an array of arrays of bytes",
+ __func__);
*reply = wpas_dbus_error_invalid_args(
- message, "Wrong SSIDs value type. Array of arrays of "
- "bytes required");
+ message,
+ "Wrong SSIDs value type. Array of arrays of bytes required");
return -1;
}
dbus_message_iter_recurse(var, &array_iter);
if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY ||
- dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE)
- {
- wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ssids "
- "must be an array of arrays of bytes");
+ dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE) {
+ wpa_printf(MSG_DEBUG,
+ "%s[dbus]: ssids must be an array of arrays of bytes",
+ __func__);
*reply = wpas_dbus_error_invalid_args(
- message, "Wrong SSIDs value type. Array of arrays of "
- "bytes required");
+ message,
+ "Wrong SSIDs value type. Array of arrays of bytes required");
return -1;
}
- while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY)
- {
+ while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY) {
if (ssids_num >= WPAS_MAX_SCAN_SSIDS) {
- wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
- "Too many ssids specified on scan dbus "
- "call");
+ wpa_printf(MSG_DEBUG,
+ "%s[dbus]: Too many ssids specified on scan dbus call",
+ __func__);
*reply = wpas_dbus_error_invalid_args(
- message, "Too many ssids specified. Specify "
- "at most four");
+ message,
+ "Too many ssids specified. Specify at most four");
return -1;
}
@@ -1055,9 +1036,8 @@
if (len > MAX_SSID_LEN) {
wpa_printf(MSG_DEBUG,
- "wpas_dbus_handler_scan[dbus]: "
- "SSID too long (len=%d max_len=%d)",
- len, MAX_SSID_LEN);
+ "%s[dbus]: SSID too long (len=%d max_len=%d)",
+ __func__, len, MAX_SSID_LEN);
*reply = wpas_dbus_error_invalid_args(
message, "Invalid SSID: too long");
return -1;
@@ -1066,12 +1046,7 @@
if (len != 0) {
ssid = os_malloc(len);
if (ssid == NULL) {
- wpa_printf(MSG_DEBUG,
- "wpas_dbus_handler_scan[dbus]: "
- "out of memory. Cannot allocate "
- "memory for SSID");
- *reply = dbus_message_new_error(
- message, DBUS_ERROR_NO_MEMORY, NULL);
+ *reply = wpas_dbus_error_no_memory(message);
return -1;
}
os_memcpy(ssid, val, len);
@@ -1103,28 +1078,28 @@
int len;
if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
- wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ies must "
- "be an array of arrays of bytes");
+ wpa_printf(MSG_DEBUG,
+ "%s[dbus]: ies must be an array of arrays of bytes",
+ __func__);
*reply = wpas_dbus_error_invalid_args(
- message, "Wrong IEs value type. Array of arrays of "
- "bytes required");
+ message,
+ "Wrong IEs value type. Array of arrays of bytes required");
return -1;
}
dbus_message_iter_recurse(var, &array_iter);
if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY ||
- dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE)
- {
- wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ies must "
- "be an array of arrays of bytes");
+ dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE) {
+ wpa_printf(MSG_DEBUG,
+ "%s[dbus]: ies must be an array of arrays of bytes",
+ __func__);
*reply = wpas_dbus_error_invalid_args(
message, "Wrong IEs value type. Array required");
return -1;
}
- while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY)
- {
+ while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY) {
dbus_message_iter_recurse(&array_iter, &sub_array_iter);
dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len);
@@ -1135,12 +1110,8 @@
nies = os_realloc(ies, ies_len + len);
if (nies == NULL) {
- wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
- "out of memory. Cannot allocate memory for "
- "IE");
os_free(ies);
- *reply = dbus_message_new_error(
- message, DBUS_ERROR_NO_MEMORY, NULL);
+ *reply = wpas_dbus_error_no_memory(message);
return -1;
}
ies = nies;
@@ -1166,11 +1137,12 @@
int freqs_num = 0;
if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
- wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
- "Channels must be an array of structs");
+ wpa_printf(MSG_DEBUG,
+ "%s[dbus]: Channels must be an array of structs",
+ __func__);
*reply = wpas_dbus_error_invalid_args(
- message, "Wrong Channels value type. Array of structs "
- "required");
+ message,
+ "Wrong Channels value type. Array of structs required");
return -1;
}
@@ -1178,11 +1150,11 @@
if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_STRUCT) {
wpa_printf(MSG_DEBUG,
- "wpas_dbus_handler_scan[dbus]: Channels must be an "
- "array of structs");
+ "%s[dbus]: Channels must be an array of structs",
+ __func__);
*reply = wpas_dbus_error_invalid_args(
- message, "Wrong Channels value type. Array of structs "
- "required");
+ message,
+ "Wrong Channels value type. Array of structs required");
return -1;
}
@@ -1194,14 +1166,14 @@
if (dbus_message_iter_get_arg_type(&sub_array_iter) !=
DBUS_TYPE_UINT32) {
- wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
- "Channel must by specified by struct of "
- "two UINT32s %c",
+ wpa_printf(MSG_DEBUG,
+ "%s[dbus]: Channel must by specified by struct of two UINT32s %c",
+ __func__,
dbus_message_iter_get_arg_type(
&sub_array_iter));
*reply = wpas_dbus_error_invalid_args(
- message, "Wrong Channel struct. Two UINT32s "
- "required");
+ message,
+ "Wrong Channel struct. Two UINT32s required");
os_free(freqs);
return -1;
}
@@ -1210,9 +1182,9 @@
if (!dbus_message_iter_next(&sub_array_iter) ||
dbus_message_iter_get_arg_type(&sub_array_iter) !=
DBUS_TYPE_UINT32) {
- wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
- "Channel must by specified by struct of "
- "two UINT32s");
+ wpa_printf(MSG_DEBUG,
+ "%s[dbus]: Channel must by specified by struct of two UINT32s",
+ __func__);
*reply = wpas_dbus_error_invalid_args(
message,
"Wrong Channel struct. Two UINT32s required");
@@ -1232,11 +1204,7 @@
freqs = nfreqs;
}
if (freqs == NULL) {
- wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
- "out of memory. can't allocate memory for "
- "freqs");
- *reply = dbus_message_new_error(
- message, DBUS_ERROR_NO_MEMORY, NULL);
+ *reply = wpas_dbus_error_no_memory(message);
return -1;
}
@@ -1251,10 +1219,7 @@
os_free(freqs);
freqs = nfreqs;
if (freqs == NULL) {
- wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
- "out of memory. Can't allocate memory for freqs");
- *reply = dbus_message_new_error(
- message, DBUS_ERROR_NO_MEMORY, NULL);
+ *reply = wpas_dbus_error_no_memory(message);
return -1;
}
freqs[freqs_num] = 0;
@@ -1270,8 +1235,8 @@
DBusMessage **reply)
{
if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_BOOLEAN) {
- wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
- "Type must be a boolean");
+ wpa_printf(MSG_DEBUG, "%s[dbus]: Type must be a boolean",
+ __func__);
*reply = wpas_dbus_error_invalid_args(
message, "Wrong Type value type. Boolean required");
return -1;
@@ -1308,7 +1273,7 @@
dbus_message_iter_recurse(&iter, &dict_iter);
while (dbus_message_iter_get_arg_type(&dict_iter) ==
- DBUS_TYPE_DICT_ENTRY) {
+ DBUS_TYPE_DICT_ENTRY) {
dbus_message_iter_recurse(&dict_iter, &entry_iter);
dbus_message_iter_get_basic(&entry_iter, &key);
dbus_message_iter_next(&entry_iter);
@@ -1337,8 +1302,8 @@
&reply) < 0)
goto out;
} else {
- wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
- "Unknown argument %s", key);
+ wpa_printf(MSG_DEBUG, "%s[dbus]: Unknown argument %s",
+ __func__, key);
reply = wpas_dbus_error_invalid_args(message, key);
goto out;
}
@@ -1347,19 +1312,20 @@
}
if (!type) {
- wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
- "Scan type not specified");
+ wpa_printf(MSG_DEBUG, "%s[dbus]: Scan type not specified",
+ __func__);
reply = wpas_dbus_error_invalid_args(message, key);
goto out;
}
- if (!os_strcmp(type, "passive")) {
+ if (os_strcmp(type, "passive") == 0) {
if (params.num_ssids || params.extra_ies_len) {
- wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
- "SSIDs or IEs specified for passive scan.");
+ wpa_printf(MSG_DEBUG,
+ "%s[dbus]: SSIDs or IEs specified for passive scan.",
+ __func__);
reply = wpas_dbus_error_invalid_args(
- message, "You can specify only Channels in "
- "passive scan");
+ message,
+ "You can specify only Channels in passive scan");
goto out;
} else if (params.freqs && params.freqs[0]) {
if (wpa_supplicant_trigger_scan(wpa_s, ¶ms)) {
@@ -1370,7 +1336,7 @@
wpa_s->scan_req = MANUAL_SCAN_REQ;
wpa_supplicant_req_scan(wpa_s, 0, 0);
}
- } else if (!os_strcmp(type, "active")) {
+ } else if (os_strcmp(type, "active") == 0) {
if (!params.num_ssids) {
/* Add wildcard ssid */
params.num_ssids++;
@@ -1383,8 +1349,8 @@
message, "Scan request rejected");
}
} else {
- wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
- "Unknown scan type: %s", type);
+ wpa_printf(MSG_DEBUG, "%s[dbus]: Unknown scan type: %s",
+ __func__, type);
reply = wpas_dbus_error_invalid_args(message,
"Wrong scan type");
goto out;
@@ -1433,45 +1399,30 @@
dbus_message_iter_init_append(reply, &iter);
if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
- "a{sv}", &variant_iter))
- goto nomem;
- if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
- goto nomem;
-
- if (!wpa_dbus_dict_append_int32(&iter_dict, "rssi", si.current_signal))
- goto nomem;
- if (!wpa_dbus_dict_append_int32(&iter_dict, "linkspeed",
- si.current_txrate / 1000))
- goto nomem;
- if (!wpa_dbus_dict_append_int32(&iter_dict, "noise", si.current_noise))
- goto nomem;
- if (!wpa_dbus_dict_append_uint32(&iter_dict, "frequency", si.frequency))
- goto nomem;
-
- if (si.chanwidth != CHAN_WIDTH_UNKNOWN) {
- if (!wpa_dbus_dict_append_string(&iter_dict, "width",
- channel_width_to_string(si.chanwidth)))
- goto nomem;
- }
-
- if (si.center_frq1 > 0 && si.center_frq2 > 0) {
- if (!wpa_dbus_dict_append_int32(&iter_dict, "center-frq1",
- si.center_frq1))
- goto nomem;
- if (!wpa_dbus_dict_append_int32(&iter_dict, "center-frq2",
- si.center_frq2))
- goto nomem;
- }
-
- if (si.avg_signal) {
- if (!wpa_dbus_dict_append_int32(&iter_dict, "avg-rssi",
- si.avg_signal))
- goto nomem;
- }
-
- if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
- goto nomem;
- if (!dbus_message_iter_close_container(&iter, &variant_iter))
+ "a{sv}", &variant_iter) ||
+ !wpa_dbus_dict_open_write(&variant_iter, &iter_dict) ||
+ !wpa_dbus_dict_append_int32(&iter_dict, "rssi",
+ si.current_signal) ||
+ !wpa_dbus_dict_append_int32(&iter_dict, "linkspeed",
+ si.current_txrate / 1000) ||
+ !wpa_dbus_dict_append_int32(&iter_dict, "noise",
+ si.current_noise) ||
+ !wpa_dbus_dict_append_uint32(&iter_dict, "frequency",
+ si.frequency) ||
+ (si.chanwidth != CHAN_WIDTH_UNKNOWN &&
+ !wpa_dbus_dict_append_string(
+ &iter_dict, "width",
+ channel_width_to_string(si.chanwidth))) ||
+ (si.center_frq1 > 0 && si.center_frq2 > 0 &&
+ (!wpa_dbus_dict_append_int32(&iter_dict, "center-frq1",
+ si.center_frq1) ||
+ !wpa_dbus_dict_append_int32(&iter_dict, "center-frq2",
+ si.center_frq2))) ||
+ (si.avg_signal &&
+ !wpa_dbus_dict_append_int32(&iter_dict, "avg-rssi",
+ si.avg_signal)) ||
+ !wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
+ !dbus_message_iter_close_container(&iter, &variant_iter))
goto nomem;
return reply;
@@ -1479,8 +1430,7 @@
nomem:
if (reply)
dbus_message_unref(reply);
- reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
- return reply;
+ return wpas_dbus_error_no_memory(message);
}
@@ -1530,12 +1480,11 @@
ssid = wpa_config_add_network(wpa_s->conf);
if (ssid == NULL) {
- wpa_printf(MSG_ERROR, "wpas_dbus_handler_add_network[dbus]: "
- "can't add new interface.");
+ wpa_printf(MSG_ERROR, "%s[dbus]: can't add new interface.",
+ __func__);
reply = wpas_dbus_error_unknown_error(
message,
- "wpa_supplicant could not add "
- "a network on this interface.");
+ "wpa_supplicant could not add a network on this interface.");
goto err;
}
wpas_notify_network_added(wpa_s, ssid);
@@ -1544,9 +1493,9 @@
dbus_error_init(&error);
if (!set_network_properties(wpa_s, ssid, &iter, &error)) {
- wpa_printf(MSG_DEBUG, "wpas_dbus_handler_add_network[dbus]:"
- "control interface couldn't set network "
- "properties");
+ wpa_printf(MSG_DEBUG,
+ "%s[dbus]: control interface couldn't set network properties",
+ __func__);
reply = wpas_dbus_reply_new_from_error(message, &error,
DBUS_ERROR_INVALID_ARGS,
"Failed to add network");
@@ -1561,15 +1510,13 @@
reply = dbus_message_new_method_return(message);
if (reply == NULL) {
- reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
+ reply = wpas_dbus_error_no_memory(message);
goto err;
}
if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID)) {
dbus_message_unref(reply);
- reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
+ reply = wpas_dbus_error_no_memory(message);
goto err;
}
@@ -1642,7 +1589,7 @@
{
DBusMessage *reply = NULL;
const char *op;
- char *iface = NULL, *net_id = NULL;
+ char *iface, *net_id;
int id;
struct wpa_ssid *ssid;
int was_disabled;
@@ -1652,7 +1599,9 @@
/* Extract the network ID and ensure the network */
/* is actually a child of this interface */
- iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
+ iface = wpas_dbus_new_decompose_object_path(op,
+ WPAS_DBUS_NEW_NETWORKS_PART,
+ &net_id);
if (iface == NULL || net_id == NULL ||
os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
reply = wpas_dbus_error_invalid_args(message, op);
@@ -1680,25 +1629,24 @@
wpa_supplicant_deauthenticate(wpa_s,
WLAN_REASON_DEAUTH_LEAVING);
else if (!was_disabled && wpa_s->sched_scanning) {
- wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to remove "
- "network from filters");
+ wpa_printf(MSG_DEBUG,
+ "Stop ongoing sched_scan to remove network from filters");
wpa_supplicant_cancel_sched_scan(wpa_s);
wpa_supplicant_req_scan(wpa_s, 0, 0);
}
if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
wpa_printf(MSG_ERROR,
- "wpas_dbus_handler_remove_network[dbus]: "
- "error occurred when removing network %d", id);
+ "%s[dbus]: error occurred when removing network %d",
+ __func__, id);
reply = wpas_dbus_error_unknown_error(
- message, "error removing the specified network on "
- "this interface.");
+ message,
+ "error removing the specified network on is interface.");
goto out;
}
out:
os_free(iface);
- os_free(net_id);
return reply;
}
@@ -1711,9 +1659,8 @@
if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
wpa_printf(MSG_ERROR,
- "wpas_dbus_handler_remove_all_networks[dbus]: "
- "error occurred when removing network %d",
- ssid->id);
+ "%s[dbus]: error occurred when removing network %d",
+ __func__, ssid->id);
return;
}
@@ -1756,7 +1703,7 @@
{
DBusMessage *reply = NULL;
const char *op;
- char *iface = NULL, *net_id = NULL;
+ char *iface, *net_id;
int id;
struct wpa_ssid *ssid;
@@ -1765,7 +1712,9 @@
/* Extract the network ID and ensure the network */
/* is actually a child of this interface */
- iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
+ iface = wpas_dbus_new_decompose_object_path(op,
+ WPAS_DBUS_NEW_NETWORKS_PART,
+ &net_id);
if (iface == NULL || net_id == NULL ||
os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
reply = wpas_dbus_error_invalid_args(message, op);
@@ -1790,7 +1739,6 @@
out:
os_free(iface);
- os_free(net_id);
return reply;
}
@@ -1809,20 +1757,22 @@
#ifdef IEEE8021X_EAPOL
DBusMessage *reply = NULL;
const char *op, *field, *value;
- char *iface = NULL, *net_id = NULL;
+ char *iface, *net_id;
int id;
struct wpa_ssid *ssid;
if (!dbus_message_get_args(message, NULL,
- DBUS_TYPE_OBJECT_PATH, &op,
- DBUS_TYPE_STRING, &field,
- DBUS_TYPE_STRING, &value,
- DBUS_TYPE_INVALID))
+ DBUS_TYPE_OBJECT_PATH, &op,
+ DBUS_TYPE_STRING, &field,
+ DBUS_TYPE_STRING, &value,
+ DBUS_TYPE_INVALID))
return wpas_dbus_error_invalid_args(message, NULL);
/* Extract the network ID and ensure the network */
/* is actually a child of this interface */
- iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
+ iface = wpas_dbus_new_decompose_object_path(op,
+ WPAS_DBUS_NEW_NETWORKS_PART,
+ &net_id);
if (iface == NULL || net_id == NULL ||
os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
reply = wpas_dbus_error_invalid_args(message, op);
@@ -1852,7 +1802,6 @@
out:
os_free(iface);
- os_free(net_id);
return reply;
#else /* IEEE8021X_EAPOL */
wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
@@ -1898,26 +1847,18 @@
blob = os_zalloc(sizeof(*blob));
if (!blob) {
- reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
+ reply = wpas_dbus_error_no_memory(message);
goto err;
}
blob->data = os_malloc(blob_len);
- if (!blob->data) {
- reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
+ blob->name = os_strdup(blob_name);
+ if (!blob->data || !blob->name) {
+ reply = wpas_dbus_error_no_memory(message);
goto err;
}
os_memcpy(blob->data, blob_data, blob_len);
-
blob->len = blob_len;
- blob->name = os_strdup(blob_name);
- if (!blob->name) {
- reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
- goto err;
- }
wpa_config_set_blob(wpa_s->conf, blob);
wpas_notify_blob_added(wpa_s, blob->name);
@@ -1962,39 +1903,21 @@
}
reply = dbus_message_new_method_return(message);
- if (!reply) {
- reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
- goto out;
- }
+ if (!reply)
+ return wpas_dbus_error_no_memory(message);
dbus_message_iter_init_append(reply, &iter);
if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
DBUS_TYPE_BYTE_AS_STRING,
- &array_iter)) {
+ &array_iter) ||
+ !dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE,
+ &(blob->data), blob->len) ||
+ !dbus_message_iter_close_container(&iter, &array_iter)) {
dbus_message_unref(reply);
- reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
- goto out;
+ reply = wpas_dbus_error_no_memory(message);
}
- if (!dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE,
- &(blob->data), blob->len)) {
- dbus_message_unref(reply);
- reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
- goto out;
- }
-
- if (!dbus_message_iter_close_container(&iter, &array_iter)) {
- dbus_message_unref(reply);
- reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
- goto out;
- }
-
-out:
return reply;
}
@@ -2076,11 +1999,10 @@
if (arg != NULL && os_strlen(arg) > 0) {
char *tmp;
+
tmp = os_strdup(arg);
if (tmp == NULL) {
- reply = dbus_message_new_error(message,
- DBUS_ERROR_NO_MEMORY,
- NULL);
+ reply = wpas_dbus_error_no_memory(message);
} else {
os_free(wpa_s->conf->autoscan);
wpa_s->conf->autoscan = tmp;
@@ -2342,8 +2264,7 @@
pkcs11_module_path))
return dbus_message_new_error(
message, DBUS_ERROR_FAILED,
- "Reinit of the EAPOL state machine with the new PKCS "
- "#11 engine and module path failed.");
+ "Reinit of the EAPOL state machine with the new PKCS #11 engine and module path failed.");
wpa_dbus_mark_property_changed(
wpa_s->global->dbus, wpa_s->dbus_new_path,
@@ -2376,10 +2297,8 @@
const char *scans[] = { "active", "passive", "ssid" };
if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
- "a{sv}", &variant_iter))
- goto nomem;
-
- if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
+ "a{sv}", &variant_iter) ||
+ !wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
goto nomem;
res = wpa_drv_get_capa(wpa_s, &capa);
@@ -2387,6 +2306,7 @@
/***** pairwise cipher */
if (res < 0) {
const char *args[] = {"ccmp", "tkip", "none"};
+
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "Pairwise", args,
ARRAY_SIZE(args)))
@@ -2395,46 +2315,26 @@
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Pairwise",
&iter_dict_entry,
&iter_dict_val,
- &iter_array))
- goto nomem;
-
- if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "ccmp-256"))
- goto nomem;
- }
-
- if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "gcmp-256"))
- goto nomem;
- }
-
- if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "ccmp"))
- goto nomem;
- }
-
- if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "gcmp"))
- goto nomem;
- }
-
- if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "tkip"))
- goto nomem;
- }
-
- if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "none"))
- goto nomem;
- }
-
- if (!wpa_dbus_dict_end_string_array(&iter_dict,
+ &iter_array) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "ccmp-256")) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "gcmp-256")) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "ccmp")) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "gcmp")) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "tkip")) ||
+ ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "none")) ||
+ !wpa_dbus_dict_end_string_array(&iter_dict,
&iter_dict_entry,
&iter_dict_val,
&iter_array))
@@ -2446,6 +2346,7 @@
const char *args[] = {
"ccmp", "tkip", "wep104", "wep40"
};
+
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "Group", args,
ARRAY_SIZE(args)))
@@ -2454,52 +2355,29 @@
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Group",
&iter_dict_entry,
&iter_dict_val,
- &iter_array))
- goto nomem;
-
- if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "ccmp-256"))
- goto nomem;
- }
-
- if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "gcmp-256"))
- goto nomem;
- }
-
- if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "ccmp"))
- goto nomem;
- }
-
- if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "gcmp"))
- goto nomem;
- }
-
- if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "tkip"))
- goto nomem;
- }
-
- if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "wep104"))
- goto nomem;
- }
-
- if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "wep40"))
- goto nomem;
- }
-
- if (!wpa_dbus_dict_end_string_array(&iter_dict,
+ &iter_array) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "ccmp-256")) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "gcmp-256")) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "ccmp")) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "gcmp")) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "tkip")) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "wep104")) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "wep40")) ||
+ !wpa_dbus_dict_end_string_array(&iter_dict,
&iter_dict_entry,
&iter_dict_val,
&iter_array))
@@ -2523,28 +2401,22 @@
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "KeyMgmt",
&iter_dict_entry,
&iter_dict_val,
- &iter_array))
- goto nomem;
-
- if (!wpa_dbus_dict_string_array_add_element(&iter_array,
- "none"))
- goto nomem;
-
- if (!wpa_dbus_dict_string_array_add_element(&iter_array,
+ &iter_array) ||
+ !wpa_dbus_dict_string_array_add_element(&iter_array,
+ "none") ||
+ !wpa_dbus_dict_string_array_add_element(&iter_array,
"ieee8021x"))
goto nomem;
if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "wpa-eap"))
+ &iter_array, "wpa-eap") ||
+ ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "wpa-ft-eap")))
goto nomem;
- if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT)
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "wpa-ft-eap"))
- goto nomem;
-
/* TODO: Ensure that driver actually supports sha256 encryption. */
#ifdef CONFIG_IEEE80211W
if (!wpa_dbus_dict_string_array_add_element(
@@ -2556,14 +2428,13 @@
if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "wpa-psk"))
+ &iter_array, "wpa-psk") ||
+ ((capa.key_mgmt &
+ WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "wpa-ft-psk")))
goto nomem;
- if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK)
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "wpa-ft-psk"))
- goto nomem;
-
/* TODO: Ensure that driver actually supports sha256 encryption. */
#ifdef CONFIG_IEEE80211W
if (!wpa_dbus_dict_string_array_add_element(
@@ -2572,11 +2443,10 @@
#endif /* CONFIG_IEEE80211W */
}
- if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "wpa-none"))
- goto nomem;
- }
+ if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
+ !wpa_dbus_dict_string_array_add_element(&iter_array,
+ "wpa-none"))
+ goto nomem;
#ifdef CONFIG_WPS
@@ -2595,6 +2465,7 @@
/***** WPA protocol */
if (res < 0) {
const char *args[] = { "rsn", "wpa" };
+
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "Protocol", args,
ARRAY_SIZE(args)))
@@ -2603,24 +2474,16 @@
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Protocol",
&iter_dict_entry,
&iter_dict_val,
- &iter_array))
- goto nomem;
-
- if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "rsn"))
- goto nomem;
- }
-
- if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "wpa"))
- goto nomem;
- }
-
- if (!wpa_dbus_dict_end_string_array(&iter_dict,
+ &iter_array) ||
+ ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "rsn")) ||
+ ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "wpa")) ||
+ !wpa_dbus_dict_end_string_array(&iter_dict,
&iter_dict_entry,
&iter_dict_val,
&iter_array))
@@ -2630,6 +2493,7 @@
/***** auth alg */
if (res < 0) {
const char *args[] = { "open", "shared", "leap" };
+
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "AuthAlg", args,
ARRAY_SIZE(args)))
@@ -2641,25 +2505,16 @@
&iter_array))
goto nomem;
- if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "open"))
- goto nomem;
- }
-
- if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "shared"))
- goto nomem;
- }
-
- if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "leap"))
- goto nomem;
- }
-
- if (!wpa_dbus_dict_end_string_array(&iter_dict,
+ if (((capa.auth & WPA_DRIVER_AUTH_OPEN) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "open")) ||
+ ((capa.auth & WPA_DRIVER_AUTH_SHARED) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "shared")) ||
+ ((capa.auth & WPA_DRIVER_AUTH_LEAP) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "leap")) ||
+ !wpa_dbus_dict_end_string_array(&iter_dict,
&iter_dict_entry,
&iter_dict_val,
&iter_array))
@@ -2675,32 +2530,18 @@
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Modes",
&iter_dict_entry,
&iter_dict_val,
- &iter_array))
- goto nomem;
-
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "infrastructure"))
- goto nomem;
-
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "ad-hoc"))
- goto nomem;
-
- if (res >= 0) {
- if (capa.flags & (WPA_DRIVER_FLAGS_AP)) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "ap"))
- goto nomem;
- }
-
- if (capa.flags & (WPA_DRIVER_FLAGS_P2P_CAPABLE)) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "p2p"))
- goto nomem;
- }
- }
-
- if (!wpa_dbus_dict_end_string_array(&iter_dict,
+ &iter_array) ||
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "infrastructure") ||
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "ad-hoc") ||
+ (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_AP) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "ap")) ||
+ (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_P2P_CAPABLE) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "p2p")) ||
+ !wpa_dbus_dict_end_string_array(&iter_dict,
&iter_dict_entry,
&iter_dict_val,
&iter_array))
@@ -2715,9 +2556,8 @@
goto nomem;
}
- if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
- goto nomem;
- if (!dbus_message_iter_close_container(iter, &variant_iter))
+ if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
+ !dbus_message_iter_close_container(iter, &variant_iter))
goto nomem;
return TRUE;
@@ -2778,7 +2618,7 @@
* Getter for "scanning" property.
*/
dbus_bool_t wpas_dbus_getter_scanning(DBusMessageIter *iter, DBusError *error,
- void *user_data)
+ void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
@@ -2900,6 +2740,7 @@
{
struct wpa_supplicant *wpa_s = user_data;
dbus_int32_t reason = wpa_s->disconnect_reason;
+
return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
&reason, error);
}
@@ -3154,8 +2995,8 @@
const char *driver;
if (wpa_s->driver == NULL || wpa_s->driver->name == NULL) {
- wpa_printf(MSG_DEBUG, "wpas_dbus_getter_driver[dbus]: "
- "wpa_s has no driver set");
+ wpa_printf(MSG_DEBUG, "%s[dbus]: wpa_s has no driver set",
+ __func__);
dbus_set_error(error, DBUS_ERROR_FAILED, "%s: no driver set",
__func__);
return FALSE;
@@ -3275,6 +3116,7 @@
{
struct wpa_supplicant *wpa_s = user_data;
const char *bridge_ifname = wpa_s->bridge_ifname;
+
return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
&bridge_ifname, error);
}
@@ -3349,14 +3191,6 @@
unsigned int i = 0, num = 0;
dbus_bool_t success = FALSE;
- if (wpa_s->conf == NULL) {
- wpa_printf(MSG_ERROR, "%s[dbus]: An error occurred getting "
- "networks list.", __func__);
- dbus_set_error(error, DBUS_ERROR_FAILED, "%s: an error "
- "occurred getting the networks list", __func__);
- return FALSE;
- }
-
for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
if (!network_is_persistent_group(ssid))
num++;
@@ -3373,7 +3207,8 @@
continue;
paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
if (paths[i] == NULL) {
- dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory");
+ dbus_set_error(error, DBUS_ERROR_NO_MEMORY,
+ "no memory");
goto out;
}
@@ -3411,16 +3246,6 @@
struct wpa_supplicant *wpa_s = user_data;
const char *pkcs11_engine_path;
- if (wpa_s->conf == NULL) {
- wpa_printf(MSG_ERROR,
- "wpas_dbus_getter_pkcs11_engine_path[dbus]: An "
- "error occurred getting the PKCS #11 engine path.");
- dbus_set_error_const(
- error, DBUS_ERROR_FAILED,
- "An error occured getting the PKCS #11 engine path.");
- return FALSE;
- }
-
if (wpa_s->conf->pkcs11_engine_path == NULL)
pkcs11_engine_path = "";
else
@@ -3446,16 +3271,6 @@
struct wpa_supplicant *wpa_s = user_data;
const char *pkcs11_module_path;
- if (wpa_s->conf == NULL) {
- wpa_printf(MSG_ERROR,
- "wpas_dbus_getter_pkcs11_module_path[dbus]: An "
- "error occurred getting the PKCS #11 module path.");
- dbus_set_error_const(
- error, DBUS_ERROR_FAILED,
- "An error occured getting the PKCS #11 module path.");
- return FALSE;
- }
-
if (wpa_s->conf->pkcs11_module_path == NULL)
pkcs11_module_path = "";
else
@@ -3534,7 +3349,7 @@
if (!res) {
wpa_printf(MSG_ERROR, "%s[dbus]: no bss with id %d found",
- func_name, args->id);
+ func_name, args->id);
dbus_set_error(error, DBUS_ERROR_FAILED,
"%s: BSS %d not found",
func_name, args->id);
@@ -3775,7 +3590,7 @@
DBusMessageIter iter_dict, variant_iter;
const char *group;
const char *pairwise[5]; /* max 5 pairwise ciphers is supported */
- const char *key_mgmt[7]; /* max 7 key managements may be supported */
+ const char *key_mgmt[9]; /* max 9 key managements may be supported */
int n;
if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
@@ -3799,6 +3614,14 @@
key_mgmt[n++] = "wpa-ft-eap";
if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
key_mgmt[n++] = "wpa-eap-sha256";
+#ifdef CONFIG_SUITEB
+ if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
+ key_mgmt[n++] = "wpa-eap-suite-b";
+#endif /* CONFIG_SUITEB */
+#ifdef CONFIG_SUITEB192
+ if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ key_mgmt[n++] = "wpa-eap-suite-b-192";
+#endif /* CONFIG_SUITEB192 */
if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE)
key_mgmt[n++] = "wpa-none";
@@ -3872,9 +3695,8 @@
goto nomem;
}
- if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
- goto nomem;
- if (!dbus_message_iter_close_container(iter, &variant_iter))
+ if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
+ !dbus_message_iter_close_container(iter, &variant_iter))
goto nomem;
return TRUE;
@@ -3908,12 +3730,10 @@
os_memset(&wpa_data, 0, sizeof(wpa_data));
ie = wpa_bss_get_vendor_ie(res, WPA_IE_VENDOR_TYPE);
- if (ie) {
- if (wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
- dbus_set_error_const(error, DBUS_ERROR_FAILED,
- "failed to parse WPA IE");
- return FALSE;
- }
+ if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
+ dbus_set_error_const(error, DBUS_ERROR_FAILED,
+ "failed to parse WPA IE");
+ return FALSE;
}
return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error);
@@ -3943,12 +3763,10 @@
os_memset(&wpa_data, 0, sizeof(wpa_data));
ie = wpa_bss_get_ie(res, WLAN_EID_RSN);
- if (ie) {
- if (wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
- dbus_set_error_const(error, DBUS_ERROR_FAILED,
- "failed to parse RSN IE");
- return FALSE;
- }
+ if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
+ dbus_set_error_const(error, DBUS_ERROR_FAILED,
+ "failed to parse RSN IE");
+ return FALSE;
}
return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error);
@@ -3980,10 +3798,8 @@
return FALSE;
if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
- "a{sv}", &variant_iter))
- goto nomem;
-
- if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
+ "a{sv}", &variant_iter) ||
+ !wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
goto nomem;
#ifdef CONFIG_WPS
@@ -3993,15 +3809,14 @@
type = "pbc";
else if (wps_is_selected_pin_registrar(wps_ie))
type = "pin";
+
+ wpabuf_free(wps_ie);
}
#endif /* CONFIG_WPS */
- if (!wpa_dbus_dict_append_string(&iter_dict, "Type", type))
- goto nomem;
-
- if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
- goto nomem;
- if (!dbus_message_iter_close_container(iter, &variant_iter))
+ if (!wpa_dbus_dict_append_string(&iter_dict, "Type", type) ||
+ !wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
+ !dbus_message_iter_close_container(iter, &variant_iter))
goto nomem;
return TRUE;
@@ -4223,8 +4038,7 @@
name = os_strdup(dbus_message_get_sender(message));
if (!name)
- return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- "out of memory");
+ return wpas_dbus_error_no_memory(message);
wpa_s->preq_notify_peer = name;
@@ -4304,28 +4118,22 @@
dbus_message_iter_init_append(msg, &iter);
- if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
- goto fail;
- if (addr && !wpa_dbus_dict_append_byte_array(&dict_iter, "addr",
- (const char *) addr,
- ETH_ALEN))
- goto fail;
- if (dst && !wpa_dbus_dict_append_byte_array(&dict_iter, "dst",
- (const char *) dst,
- ETH_ALEN))
- goto fail;
- if (bssid && !wpa_dbus_dict_append_byte_array(&dict_iter, "bssid",
- (const char *) bssid,
- ETH_ALEN))
- goto fail;
- if (ie && ie_len && !wpa_dbus_dict_append_byte_array(&dict_iter, "ies",
- (const char *) ie,
- ie_len))
- goto fail;
- if (ssi_signal && !wpa_dbus_dict_append_int32(&dict_iter, "signal",
- ssi_signal))
- goto fail;
- if (!wpa_dbus_dict_close_write(&iter, &dict_iter))
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+ (addr && !wpa_dbus_dict_append_byte_array(&dict_iter, "addr",
+ (const char *) addr,
+ ETH_ALEN)) ||
+ (dst && !wpa_dbus_dict_append_byte_array(&dict_iter, "dst",
+ (const char *) dst,
+ ETH_ALEN)) ||
+ (bssid && !wpa_dbus_dict_append_byte_array(&dict_iter, "bssid",
+ (const char *) bssid,
+ ETH_ALEN)) ||
+ (ie && ie_len && !wpa_dbus_dict_append_byte_array(&dict_iter, "ies",
+ (const char *) ie,
+ ie_len)) ||
+ (ssi_signal && !wpa_dbus_dict_append_int32(&dict_iter, "signal",
+ ssi_signal)) ||
+ !wpa_dbus_dict_close_write(&iter, &dict_iter))
goto fail;
dbus_connection_send(priv->con, msg, NULL);
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index f6a83cd..6113db5 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -55,8 +55,8 @@
void *user_data);
dbus_bool_t wpas_dbus_getter_debug_timestamp(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
+ DBusError *error,
+ void *user_data);
dbus_bool_t wpas_dbus_getter_debug_show_keys(DBusMessageIter *iter,
DBusError *error,
@@ -319,6 +319,7 @@
const char *arg);
DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message,
const char *arg);
+DBusMessage * wpas_dbus_error_no_memory(DBusMessage *message);
DBusMessage * wpas_dbus_handler_subscribe_preq(
DBusMessage *message, struct wpa_supplicant *wpa_s);
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index 7867f0c..9c880a2 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -35,9 +35,9 @@
* @addr - out param must be of ETH_ALEN size
* Returns 0 if valid (including MAC), -1 otherwise
*/
-static int parse_peer_object_path(char *peer_path, u8 addr[ETH_ALEN])
+static int parse_peer_object_path(const char *peer_path, u8 addr[ETH_ALEN])
{
- char *p;
+ const char *p;
if (!peer_path)
return -1;
@@ -57,12 +57,12 @@
*
* Convenience function to create and return an invalid persistent group error.
*/
-static DBusMessage * wpas_dbus_error_persistent_group_unknown(
- DBusMessage *message)
+static DBusMessage *
+wpas_dbus_error_persistent_group_unknown(DBusMessage *message)
{
- return dbus_message_new_error(message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
- "There is no such persistent group in "
- "this P2P device.");
+ return dbus_message_new_error(
+ message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
+ "There is no such persistent group in this P2P device.");
}
@@ -74,7 +74,7 @@
DBusMessageIter iter;
DBusMessageIter iter_dict;
unsigned int timeout = 0;
- enum p2p_discovery_type type = P2P_FIND_ONLY_SOCIAL;
+ enum p2p_discovery_type type = P2P_FIND_START_WITH_FULL;
int num_req_dev_types = 0;
unsigned int i;
u8 *req_dev_types = NULL;
@@ -89,12 +89,12 @@
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto error;
- if (!os_strcmp(entry.key, "Timeout") &&
- (entry.type == DBUS_TYPE_INT32)) {
+ if (os_strcmp(entry.key, "Timeout") == 0 &&
+ entry.type == DBUS_TYPE_INT32) {
timeout = entry.uint32_value;
} else if (os_strcmp(entry.key, "RequestedDeviceTypes") == 0) {
- if ((entry.type != DBUS_TYPE_ARRAY) ||
- (entry.array_type != WPAS_DBUS_TYPE_BINARRAY))
+ if (entry.type != DBUS_TYPE_ARRAY ||
+ entry.array_type != WPAS_DBUS_TYPE_BINARRAY)
goto error_clear;
os_free(req_dev_types);
@@ -105,20 +105,20 @@
for (i = 0; i < entry.array_len; i++) {
if (wpabuf_len(entry.binarray_value[i]) !=
- WPS_DEV_TYPE_LEN)
+ WPS_DEV_TYPE_LEN)
goto error_clear;
os_memcpy(req_dev_types + i * WPS_DEV_TYPE_LEN,
wpabuf_head(entry.binarray_value[i]),
WPS_DEV_TYPE_LEN);
}
num_req_dev_types = entry.array_len;
- } else if (!os_strcmp(entry.key, "DiscoveryType") &&
- (entry.type == DBUS_TYPE_STRING)) {
- if (!os_strcmp(entry.str_value, "start_with_full"))
+ } else if (os_strcmp(entry.key, "DiscoveryType") == 0 &&
+ entry.type == DBUS_TYPE_STRING) {
+ if (os_strcmp(entry.str_value, "start_with_full") == 0)
type = P2P_FIND_START_WITH_FULL;
- else if (!os_strcmp(entry.str_value, "social"))
+ else if (os_strcmp(entry.str_value, "social") == 0)
type = P2P_FIND_ONLY_SOCIAL;
- else if (!os_strcmp(entry.str_value, "progressive"))
+ else if (os_strcmp(entry.str_value, "progressive") == 0)
type = P2P_FIND_PROGRESSIVE;
else
goto error_clear;
@@ -127,6 +127,9 @@
wpa_dbus_dict_entry_clear(&entry);
}
+ if (wpa_s->p2p_dev)
+ wpa_s = wpa_s->p2p_dev;
+
wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types,
NULL, 0);
os_free(req_dev_types);
@@ -144,6 +147,9 @@
DBusMessage * wpas_dbus_handler_p2p_stop_find(DBusMessage *message,
struct wpa_supplicant *wpa_s)
{
+ if (wpa_s->p2p_dev)
+ wpa_s = wpa_s->p2p_dev;
+
wpas_p2p_stop_find(wpa_s);
return NULL;
}
@@ -162,6 +168,9 @@
if (parse_peer_object_path(peer_object_path, peer_addr) < 0)
return wpas_dbus_error_invalid_args(message, NULL);
+ if (wpa_s->p2p_dev)
+ wpa_s = wpa_s->p2p_dev;
+
if (wpas_p2p_reject(wpa_s, peer_addr) < 0)
return wpas_dbus_error_unknown_error(message,
"Failed to call wpas_p2p_reject method.");
@@ -177,12 +186,16 @@
if (!dbus_message_get_args(message, NULL, DBUS_TYPE_INT32, &timeout,
DBUS_TYPE_INVALID))
- return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
+ return wpas_dbus_error_no_memory(message);
- if (wpas_p2p_listen(wpa_s, (unsigned int)timeout))
- return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
+ if (wpa_s->p2p_dev)
+ wpa_s = wpa_s->p2p_dev;
+
+ if (wpas_p2p_listen(wpa_s, (unsigned int) timeout)) {
+ return dbus_message_new_error(message,
+ WPAS_DBUS_ERROR_UNKNOWN_ERROR,
+ "Could not start P2P listen");
+ }
return NULL;
}
@@ -206,17 +219,20 @@
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto error;
- if (!os_strcmp(entry.key, "period") &&
- (entry.type == DBUS_TYPE_INT32))
+ if (os_strcmp(entry.key, "period") == 0 &&
+ entry.type == DBUS_TYPE_INT32)
period = entry.uint32_value;
- else if (!os_strcmp(entry.key, "interval") &&
- (entry.type == DBUS_TYPE_INT32))
+ else if (os_strcmp(entry.key, "interval") == 0 &&
+ entry.type == DBUS_TYPE_INT32)
interval = entry.uint32_value;
else
goto error_clear;
wpa_dbus_dict_entry_clear(&entry);
}
+ if (wpa_s->p2p_dev)
+ wpa_s = wpa_s->p2p_dev;
+
if (wpas_p2p_ext_listen(wpa_s, period, interval))
return wpas_dbus_error_unknown_error(
message, "failed to initiate a p2p_ext_listen.");
@@ -248,16 +264,16 @@
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto error;
- if (!os_strcmp(entry.key, "duration1") &&
- (entry.type == DBUS_TYPE_INT32))
+ if (os_strcmp(entry.key, "duration1") == 0 &&
+ entry.type == DBUS_TYPE_INT32)
dur1 = entry.uint32_value;
- else if (!os_strcmp(entry.key, "interval1") &&
+ else if (os_strcmp(entry.key, "interval1") == 0 &&
entry.type == DBUS_TYPE_INT32)
int1 = entry.uint32_value;
- else if (!os_strcmp(entry.key, "duration2") &&
+ else if (os_strcmp(entry.key, "duration2") == 0 &&
entry.type == DBUS_TYPE_INT32)
dur2 = entry.uint32_value;
- else if (!os_strcmp(entry.key, "interval2") &&
+ else if (os_strcmp(entry.key, "interval2") == 0 &&
entry.type == DBUS_TYPE_INT32)
int2 = entry.uint32_value;
else
@@ -265,6 +281,10 @@
wpa_dbus_dict_entry_clear(&entry);
}
+
+ if (wpa_s->p2p_dev)
+ wpa_s = wpa_s->p2p_dev;
+
if (wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2) < 0)
return wpas_dbus_error_unknown_error(message,
"Failed to invoke presence request.");
@@ -289,7 +309,6 @@
int persistent_group = 0;
int freq = 0;
char *iface = NULL;
- char *net_id_str = NULL;
unsigned int group_id = 0;
struct wpa_ssid *ssid;
@@ -302,15 +321,16 @@
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto inv_args;
- if (!os_strcmp(entry.key, "persistent") &&
- (entry.type == DBUS_TYPE_BOOLEAN)) {
- persistent_group = (entry.bool_value == TRUE) ? 1 : 0;
- } else if (!os_strcmp(entry.key, "frequency") &&
- (entry.type == DBUS_TYPE_INT32)) {
+ if (os_strcmp(entry.key, "persistent") == 0 &&
+ entry.type == DBUS_TYPE_BOOLEAN) {
+ persistent_group = entry.bool_value;
+ } else if (os_strcmp(entry.key, "frequency") == 0 &&
+ entry.type == DBUS_TYPE_INT32) {
freq = entry.int32_value;
if (freq <= 0)
goto inv_args_clear;
- } else if (!os_strcmp(entry.key, "persistent_group_object") &&
+ } else if (os_strcmp(entry.key, "persistent_group_object") ==
+ 0 &&
entry.type == DBUS_TYPE_OBJECT_PATH)
pg_object_path = os_strdup(entry.str_value);
else
@@ -319,15 +339,21 @@
wpa_dbus_dict_entry_clear(&entry);
}
+ if (wpa_s->p2p_dev)
+ wpa_s = wpa_s->p2p_dev;
+
if (pg_object_path != NULL) {
+ char *net_id_str;
+
/*
* A persistent group Object Path is defined meaning we want
* to re-invoke a persistent group.
*/
- iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1,
- &net_id_str, NULL);
- if (iface == NULL ||
+ iface = wpas_dbus_new_decompose_object_path(
+ pg_object_path, WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART,
+ &net_id_str);
+ if (iface == NULL || net_id_str == NULL ||
os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
reply =
wpas_dbus_error_invalid_args(message,
@@ -359,7 +385,6 @@
out:
os_free(pg_object_path);
- os_free(net_id_str);
os_free(iface);
return reply;
inv_args_clear:
@@ -394,8 +419,7 @@
"P2P is not available for this interface");
}
dbus_set_error_const(error, DBUS_ERROR_FAILED,
- "P2P is not available for this "
- "interface");
+ "P2P is not available for this interface");
return FALSE;
}
return TRUE;
@@ -410,6 +434,9 @@
if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL))
return reply;
+ if (wpa_s->p2p_dev)
+ wpa_s = wpa_s->p2p_dev;
+
os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
wpa_s->force_long_sd = 0;
p2p_flush(wpa_s->global->p2p);
@@ -450,42 +477,42 @@
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto inv_args;
- if (!os_strcmp(entry.key, "peer") &&
- (entry.type == DBUS_TYPE_OBJECT_PATH)) {
+ if (os_strcmp(entry.key, "peer") == 0 &&
+ entry.type == DBUS_TYPE_OBJECT_PATH) {
peer_object_path = os_strdup(entry.str_value);
- } else if (!os_strcmp(entry.key, "persistent") &&
- (entry.type == DBUS_TYPE_BOOLEAN)) {
- persistent_group = (entry.bool_value == TRUE) ? 1 : 0;
- } else if (!os_strcmp(entry.key, "join") &&
- (entry.type == DBUS_TYPE_BOOLEAN)) {
- join = (entry.bool_value == TRUE) ? 1 : 0;
- } else if (!os_strcmp(entry.key, "authorize_only") &&
- (entry.type == DBUS_TYPE_BOOLEAN)) {
- authorize_only = (entry.bool_value == TRUE) ? 1 : 0;
- } else if (!os_strcmp(entry.key, "frequency") &&
- (entry.type == DBUS_TYPE_INT32)) {
+ } else if (os_strcmp(entry.key, "persistent") == 0 &&
+ entry.type == DBUS_TYPE_BOOLEAN) {
+ persistent_group = entry.bool_value;
+ } else if (os_strcmp(entry.key, "join") == 0 &&
+ entry.type == DBUS_TYPE_BOOLEAN) {
+ join = entry.bool_value;
+ } else if (os_strcmp(entry.key, "authorize_only") == 0 &&
+ entry.type == DBUS_TYPE_BOOLEAN) {
+ authorize_only = entry.bool_value;
+ } else if (os_strcmp(entry.key, "frequency") == 0 &&
+ entry.type == DBUS_TYPE_INT32) {
freq = entry.int32_value;
if (freq <= 0)
goto inv_args_clear;
- } else if (!os_strcmp(entry.key, "go_intent") &&
- (entry.type == DBUS_TYPE_INT32)) {
+ } else if (os_strcmp(entry.key, "go_intent") == 0 &&
+ entry.type == DBUS_TYPE_INT32) {
go_intent = entry.int32_value;
if ((go_intent < 0) || (go_intent > 15))
goto inv_args_clear;
- } else if (!os_strcmp(entry.key, "wps_method") &&
- (entry.type == DBUS_TYPE_STRING)) {
- if (!os_strcmp(entry.str_value, "pbc"))
+ } else if (os_strcmp(entry.key, "wps_method") == 0 &&
+ entry.type == DBUS_TYPE_STRING) {
+ if (os_strcmp(entry.str_value, "pbc") == 0)
wps_method = WPS_PBC;
- else if (!os_strcmp(entry.str_value, "pin"))
+ else if (os_strcmp(entry.str_value, "pin") == 0)
wps_method = WPS_PIN_DISPLAY;
- else if (!os_strcmp(entry.str_value, "display"))
+ else if (os_strcmp(entry.str_value, "display") == 0)
wps_method = WPS_PIN_DISPLAY;
- else if (!os_strcmp(entry.str_value, "keypad"))
+ else if (os_strcmp(entry.str_value, "keypad") == 0)
wps_method = WPS_PIN_KEYPAD;
else
goto inv_args_clear;
- } else if (!os_strcmp(entry.key, "pin") &&
- (entry.type == DBUS_TYPE_STRING)) {
+ } else if (os_strcmp(entry.key, "pin") == 0 &&
+ entry.type == DBUS_TYPE_STRING) {
pin = os_strdup(entry.str_value);
} else
goto inv_args_clear;
@@ -493,17 +520,20 @@
wpa_dbus_dict_entry_clear(&entry);
}
- if (!peer_object_path || (wps_method == WPS_NOT_READY) ||
- (parse_peer_object_path(peer_object_path, addr) < 0) ||
+ if (wps_method == WPS_NOT_READY ||
+ parse_peer_object_path(peer_object_path, addr) < 0 ||
!p2p_peer_known(wpa_s->global->p2p, addr))
goto inv_args;
/*
* Validate the wps_method specified and the pin value.
*/
- if ((!pin || !pin[0]) && (wps_method == WPS_PIN_KEYPAD))
+ if ((!pin || !pin[0]) && wps_method == WPS_PIN_KEYPAD)
goto inv_args;
+ if (wpa_s->p2p_dev)
+ wpa_s = wpa_s->p2p_dev;
+
new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
persistent_group, 0, join, authorize_only,
go_intent, freq, -1, 0, 0, 0);
@@ -511,6 +541,7 @@
if (new_pin >= 0) {
char npin[9];
char *generated_pin;
+
os_snprintf(npin, sizeof(npin), "%08d", new_pin);
generated_pin = npin;
reply = dbus_message_new_method_return(message);
@@ -519,8 +550,8 @@
} else {
switch (new_pin) {
case -2:
- err_msg = "connect failed due to channel "
- "unavailability.";
+ err_msg =
+ "connect failed due to channel unavailability.";
iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNAVAILABLE;
break;
@@ -566,7 +597,6 @@
char *peer_object_path = NULL;
char *pg_object_path = NULL;
char *iface = NULL;
- char *net_id_str = NULL;
u8 peer_addr[ETH_ALEN];
unsigned int group_id = 0;
int persistent = 0;
@@ -584,12 +614,13 @@
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto err;
- if (!os_strcmp(entry.key, "peer") &&
- (entry.type == DBUS_TYPE_OBJECT_PATH)) {
+ if (os_strcmp(entry.key, "peer") == 0 &&
+ entry.type == DBUS_TYPE_OBJECT_PATH) {
peer_object_path = os_strdup(entry.str_value);
wpa_dbus_dict_entry_clear(&entry);
- } else if (!os_strcmp(entry.key, "persistent_group_object") &&
- (entry.type == DBUS_TYPE_OBJECT_PATH)) {
+ } else if (os_strcmp(entry.key, "persistent_group_object") ==
+ 0 &&
+ entry.type == DBUS_TYPE_OBJECT_PATH) {
pg_object_path = os_strdup(entry.str_value);
persistent = 1;
wpa_dbus_dict_entry_clear(&entry);
@@ -599,21 +630,25 @@
}
}
- if (!peer_object_path ||
- (parse_peer_object_path(peer_object_path, peer_addr) < 0) ||
- !p2p_peer_known(wpa_s->global->p2p, peer_addr)) {
+ if (parse_peer_object_path(peer_object_path, peer_addr) < 0 ||
+ !p2p_peer_known(wpa_s->global->p2p, peer_addr))
goto err;
- }
+
+ if (wpa_s->p2p_dev)
+ wpa_s = wpa_s->p2p_dev;
if (persistent) {
+ char *net_id_str;
/*
* A group ID is defined meaning we want to re-invoke a
* persistent group
*/
- iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1,
- &net_id_str, NULL);
- if (iface == NULL ||
+ iface = wpas_dbus_new_decompose_object_path(
+ pg_object_path,
+ WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART,
+ &net_id_str);
+ if (iface == NULL || net_id_str == NULL ||
os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
reply = wpas_dbus_error_invalid_args(message,
pg_object_path);
@@ -652,6 +687,7 @@
}
out:
+ os_free(iface);
os_free(pg_object_path);
os_free(peer_object_path);
return reply;
@@ -690,6 +726,9 @@
os_strcmp(config_method, "pushbutton"))
return wpas_dbus_error_invalid_args(message, NULL);
+ if (wpa_s->p2p_dev)
+ wpa_s = wpa_s->p2p_dev;
+
if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method,
WPAS_P2P_PD_FOR_GO_NEG) < 0)
return wpas_dbus_error_unknown_error(message,
@@ -719,6 +758,9 @@
if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error))
return FALSE;
+ if (wpa_s->p2p_dev)
+ wpa_s = wpa_s->p2p_dev;
+
if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
"a{sv}", &variant_iter) ||
!wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
@@ -732,8 +774,8 @@
/* Primary device type */
if (!wpa_dbus_dict_append_byte_array(&dict_iter, "PrimaryDeviceType",
- (char *)wpa_s->conf->device_type,
- WPS_DEV_TYPE_LEN))
+ (char *) wpa_s->conf->device_type,
+ WPS_DEV_TYPE_LEN))
goto err_no_mem;
/* Secondary device types */
@@ -768,75 +810,37 @@
wpa_s->conf->wps_vendor_ext[i];
}
- if (num_vendor_extensions &&
- !wpa_dbus_dict_append_wpabuf_array(&dict_iter,
- "VendorExtension",
- vendor_ext,
- num_vendor_extensions))
- goto err_no_mem;
-
- /* GO Intent */
- if (!wpa_dbus_dict_append_uint32(&dict_iter, "GOIntent",
- wpa_s->conf->p2p_go_intent))
- goto err_no_mem;
-
- /* Persistent Reconnect */
- if (!wpa_dbus_dict_append_bool(&dict_iter, "PersistentReconnect",
- wpa_s->conf->persistent_reconnect))
- goto err_no_mem;
-
- /* Listen Reg Class */
- if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenRegClass",
- wpa_s->conf->p2p_listen_reg_class))
- goto err_no_mem;
-
- /* Listen Channel */
- if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenChannel",
- wpa_s->conf->p2p_listen_channel))
- goto err_no_mem;
-
- /* Oper Reg Class */
- if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperRegClass",
- wpa_s->conf->p2p_oper_reg_class))
- goto err_no_mem;
-
- /* Oper Channel */
- if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperChannel",
- wpa_s->conf->p2p_oper_channel))
- goto err_no_mem;
-
- /* SSID Postfix */
- if (wpa_s->conf->p2p_ssid_postfix &&
- !wpa_dbus_dict_append_string(&dict_iter, "SsidPostfix",
- wpa_s->conf->p2p_ssid_postfix))
- goto err_no_mem;
-
- /* Intra Bss */
- if (!wpa_dbus_dict_append_bool(&dict_iter, "IntraBss",
- wpa_s->conf->p2p_intra_bss))
- goto err_no_mem;
-
- /* Group Idle */
- if (!wpa_dbus_dict_append_uint32(&dict_iter, "GroupIdle",
- wpa_s->conf->p2p_group_idle))
- goto err_no_mem;
-
- /* Dissasociation low ack */
- if (!wpa_dbus_dict_append_uint32(&dict_iter, "disassoc_low_ack",
- wpa_s->conf->disassoc_low_ack))
- goto err_no_mem;
-
- /* No Group Iface */
- if (!wpa_dbus_dict_append_bool(&dict_iter, "NoGroupIface",
- wpa_s->conf->p2p_no_group_iface))
- goto err_no_mem;
-
- /* P2P Search Delay */
- if (!wpa_dbus_dict_append_uint32(&dict_iter, "p2p_search_delay",
- wpa_s->conf->p2p_search_delay))
- goto err_no_mem;
-
- if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
+ if ((num_vendor_extensions &&
+ !wpa_dbus_dict_append_wpabuf_array(&dict_iter,
+ "VendorExtension",
+ vendor_ext,
+ num_vendor_extensions)) ||
+ !wpa_dbus_dict_append_uint32(&dict_iter, "GOIntent",
+ wpa_s->conf->p2p_go_intent) ||
+ !wpa_dbus_dict_append_bool(&dict_iter, "PersistentReconnect",
+ wpa_s->conf->persistent_reconnect) ||
+ !wpa_dbus_dict_append_uint32(&dict_iter, "ListenRegClass",
+ wpa_s->conf->p2p_listen_reg_class) ||
+ !wpa_dbus_dict_append_uint32(&dict_iter, "ListenChannel",
+ wpa_s->conf->p2p_listen_channel) ||
+ !wpa_dbus_dict_append_uint32(&dict_iter, "OperRegClass",
+ wpa_s->conf->p2p_oper_reg_class) ||
+ !wpa_dbus_dict_append_uint32(&dict_iter, "OperChannel",
+ wpa_s->conf->p2p_oper_channel) ||
+ (wpa_s->conf->p2p_ssid_postfix &&
+ !wpa_dbus_dict_append_string(&dict_iter, "SsidPostfix",
+ wpa_s->conf->p2p_ssid_postfix)) ||
+ !wpa_dbus_dict_append_bool(&dict_iter, "IntraBss",
+ wpa_s->conf->p2p_intra_bss) ||
+ !wpa_dbus_dict_append_uint32(&dict_iter, "GroupIdle",
+ wpa_s->conf->p2p_group_idle) ||
+ !wpa_dbus_dict_append_uint32(&dict_iter, "disassoc_low_ack",
+ wpa_s->conf->disassoc_low_ack) ||
+ !wpa_dbus_dict_append_bool(&dict_iter, "NoGroupIface",
+ wpa_s->conf->p2p_no_group_iface) ||
+ !wpa_dbus_dict_append_uint32(&dict_iter, "p2p_search_delay",
+ wpa_s->conf->p2p_search_delay) ||
+ !wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
!dbus_message_iter_close_container(iter, &variant_iter))
goto err_no_mem;
@@ -860,6 +864,9 @@
if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error))
return FALSE;
+ if (wpa_s->p2p_dev)
+ wpa_s = wpa_s->p2p_dev;
+
dbus_message_iter_recurse(iter, &variant_iter);
if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict, error))
return FALSE;
@@ -915,8 +922,8 @@
wpa_s->conf->changed_parameters |=
CFG_CHANGED_SEC_DEVICE_TYPE;
} else if (os_strcmp(entry.key, "VendorExtension") == 0) {
- if ((entry.type != DBUS_TYPE_ARRAY) ||
- (entry.array_type != WPAS_DBUS_TYPE_BINARRAY) ||
+ if (entry.type != DBUS_TYPE_ARRAY ||
+ entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
(entry.array_len > P2P_MAX_WPS_VENDOR_EXT))
goto error;
@@ -932,30 +939,30 @@
} else
wpa_s->conf->wps_vendor_ext[i] = NULL;
}
- } else if ((os_strcmp(entry.key, "GOIntent") == 0) &&
- (entry.type == DBUS_TYPE_UINT32) &&
+ } else if (os_strcmp(entry.key, "GOIntent") == 0 &&
+ entry.type == DBUS_TYPE_UINT32 &&
(entry.uint32_value <= 15))
wpa_s->conf->p2p_go_intent = entry.uint32_value;
- else if ((os_strcmp(entry.key, "PersistentReconnect") == 0) &&
- (entry.type == DBUS_TYPE_BOOLEAN))
+ else if (os_strcmp(entry.key, "PersistentReconnect") == 0 &&
+ entry.type == DBUS_TYPE_BOOLEAN)
wpa_s->conf->persistent_reconnect = entry.bool_value;
- else if ((os_strcmp(entry.key, "ListenRegClass") == 0) &&
- (entry.type == DBUS_TYPE_UINT32)) {
+ else if (os_strcmp(entry.key, "ListenRegClass") == 0 &&
+ entry.type == DBUS_TYPE_UINT32) {
wpa_s->conf->p2p_listen_reg_class = entry.uint32_value;
wpa_s->conf->changed_parameters |=
CFG_CHANGED_P2P_LISTEN_CHANNEL;
- } else if ((os_strcmp(entry.key, "ListenChannel") == 0) &&
- (entry.type == DBUS_TYPE_UINT32)) {
+ } else if (os_strcmp(entry.key, "ListenChannel") == 0 &&
+ entry.type == DBUS_TYPE_UINT32) {
wpa_s->conf->p2p_listen_channel = entry.uint32_value;
wpa_s->conf->changed_parameters |=
CFG_CHANGED_P2P_LISTEN_CHANNEL;
- } else if ((os_strcmp(entry.key, "OperRegClass") == 0) &&
- (entry.type == DBUS_TYPE_UINT32)) {
+ } else if (os_strcmp(entry.key, "OperRegClass") == 0 &&
+ entry.type == DBUS_TYPE_UINT32) {
wpa_s->conf->p2p_oper_reg_class = entry.uint32_value;
wpa_s->conf->changed_parameters |=
CFG_CHANGED_P2P_OPER_CHANNEL;
- } else if ((os_strcmp(entry.key, "OperChannel") == 0) &&
- (entry.type == DBUS_TYPE_UINT32)) {
+ } else if (os_strcmp(entry.key, "OperChannel") == 0 &&
+ entry.type == DBUS_TYPE_UINT32) {
wpa_s->conf->p2p_oper_channel = entry.uint32_value;
wpa_s->conf->changed_parameters |=
CFG_CHANGED_P2P_OPER_CHANNEL;
@@ -974,13 +981,13 @@
wpa_s->conf->changed_parameters |=
CFG_CHANGED_P2P_SSID_POSTFIX;
- } else if ((os_strcmp(entry.key, "IntraBss") == 0) &&
- (entry.type == DBUS_TYPE_BOOLEAN)) {
+ } else if (os_strcmp(entry.key, "IntraBss") == 0 &&
+ entry.type == DBUS_TYPE_BOOLEAN) {
wpa_s->conf->p2p_intra_bss = entry.bool_value;
wpa_s->conf->changed_parameters |=
CFG_CHANGED_P2P_INTRA_BSS;
- } else if ((os_strcmp(entry.key, "GroupIdle") == 0) &&
- (entry.type == DBUS_TYPE_UINT32))
+ } else if (os_strcmp(entry.key, "GroupIdle") == 0 &&
+ entry.type == DBUS_TYPE_UINT32)
wpa_s->conf->p2p_group_idle = entry.uint32_value;
else if (os_strcmp(entry.key, "disassoc_low_ack") == 0 &&
entry.type == DBUS_TYPE_UINT32)
@@ -1260,8 +1267,8 @@
dbus_bool_t wpas_dbus_getter_p2p_peer_config_method(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+ DBusError *error,
+ void *user_data)
{
struct peer_handler_args *peer_args = user_data;
const struct p2p_peer_info *info;
@@ -1285,8 +1292,8 @@
dbus_bool_t wpas_dbus_getter_p2p_peer_level(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+ DBusError *error,
+ void *user_data)
{
struct peer_handler_args *peer_args = user_data;
const struct p2p_peer_info *info;
@@ -1310,8 +1317,8 @@
dbus_bool_t wpas_dbus_getter_p2p_peer_device_capability(DBusMessageIter *iter,
- DBusError *error,
- void *user_data)
+ DBusError *error,
+ void *user_data)
{
struct peer_handler_args *peer_args = user_data;
const struct p2p_peer_info *info;
@@ -1369,8 +1376,7 @@
info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
peer_args->p2p_device_addr, 0);
if (info == NULL) {
- dbus_set_error(error, DBUS_ERROR_FAILED,
- "failed to find peer");
+ dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer");
return FALSE;
}
@@ -1378,18 +1384,13 @@
DBUS_TYPE_ARRAY_AS_STRING
DBUS_TYPE_ARRAY_AS_STRING
DBUS_TYPE_BYTE_AS_STRING,
- &variant_iter)) {
- dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: failed to construct message 1", __func__);
- return FALSE;
- }
-
- if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
+ &variant_iter) ||
+ !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
DBUS_TYPE_ARRAY_AS_STRING
DBUS_TYPE_BYTE_AS_STRING,
&array_iter)) {
dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: failed to construct message 2", __func__);
+ "%s: failed to construct message 1", __func__);
return FALSE;
}
@@ -1404,29 +1405,14 @@
if (!dbus_message_iter_open_container(
&array_iter, DBUS_TYPE_ARRAY,
DBUS_TYPE_BYTE_AS_STRING,
- &inner_array_iter)) {
- dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: failed to construct "
- "message 3 (%d)",
- __func__, i);
- return FALSE;
- }
-
- if (!dbus_message_iter_append_fixed_array(
+ &inner_array_iter) ||
+ !dbus_message_iter_append_fixed_array(
&inner_array_iter, DBUS_TYPE_BYTE,
- &sec_dev_type_list, WPS_DEV_TYPE_LEN)) {
- dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: failed to construct "
- "message 4 (%d)",
- __func__, i);
- return FALSE;
- }
-
- if (!dbus_message_iter_close_container(
+ &sec_dev_type_list, WPS_DEV_TYPE_LEN) ||
+ !dbus_message_iter_close_container(
&array_iter, &inner_array_iter)) {
dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: failed to construct "
- "message 5 (%d)",
+ "%s: failed to construct message 2 (%d)",
__func__, i);
return FALSE;
}
@@ -1435,15 +1421,10 @@
}
}
- if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) {
+ if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
+ !dbus_message_iter_close_container(iter, &variant_iter)) {
dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: failed to construct message 6", __func__);
- return FALSE;
- }
-
- if (!dbus_message_iter_close_container(iter, &variant_iter)) {
- dbus_set_error(error, DBUS_ERROR_FAILED,
- "%s: failed to construct message 7", __func__);
+ "%s: failed to construct message 3", __func__);
return FALSE;
}
@@ -1583,7 +1564,7 @@
struct peer_handler_args *peer_args = user_data;
const struct p2p_peer_info *info;
struct peer_group_data data;
- struct wpa_supplicant *wpa_s_go;
+ struct wpa_supplicant *wpa_s, *wpa_s_go;
dbus_bool_t success = FALSE;
info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
@@ -1595,8 +1576,12 @@
}
os_memset(&data, 0, sizeof(data));
- wpa_s_go = wpas_get_p2p_client_iface(peer_args->wpa_s,
- info->p2p_device_addr);
+
+ wpa_s = peer_args->wpa_s;
+ if (wpa_s->p2p_dev)
+ wpa_s = wpa_s->p2p_dev;
+
+ wpa_s_go = wpas_get_p2p_client_iface(wpa_s, info->p2p_device_addr);
if (wpa_s_go) {
data.paths = os_calloc(1, sizeof(char *));
if (data.paths == NULL)
@@ -1651,15 +1636,6 @@
unsigned int i = 0, num = 0;
dbus_bool_t success = FALSE;
- if (wpa_s->conf == NULL) {
- wpa_printf(MSG_ERROR, "dbus: %s: "
- "An error occurred getting persistent groups list",
- __func__);
- dbus_set_error_const(error, DBUS_ERROR_FAILED, "an error "
- "occurred getting persistent groups list");
- return FALSE;
- }
-
for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
if (network_is_persistent_group(ssid))
num++;
@@ -1772,12 +1748,12 @@
ssid = wpa_config_add_network(wpa_s->conf);
if (ssid == NULL) {
- wpa_printf(MSG_ERROR, "dbus: %s: "
- "Cannot add new persistent group", __func__);
+ wpa_printf(MSG_ERROR,
+ "dbus: %s: Cannot add new persistent group",
+ __func__);
reply = wpas_dbus_error_unknown_error(
message,
- "wpa_supplicant could not add "
- "a persistent group on this interface.");
+ "wpa_supplicant could not add a persistent group on this interface.");
goto err;
}
@@ -1790,13 +1766,12 @@
dbus_error_init(&error);
if (!set_network_properties(wpa_s, ssid, &iter, &error)) {
- wpa_printf(MSG_DEBUG, "dbus: %s: "
- "Control interface could not set persistent group "
- "properties", __func__);
- reply = wpas_dbus_reply_new_from_error(message, &error,
- DBUS_ERROR_INVALID_ARGS,
- "Failed to set network "
- "properties");
+ wpa_printf(MSG_DEBUG,
+ "dbus: %s: Control interface could not set persistent group properties",
+ __func__);
+ reply = wpas_dbus_reply_new_from_error(
+ message, &error, DBUS_ERROR_INVALID_ARGS,
+ "Failed to set network properties");
dbus_error_free(&error);
goto err;
}
@@ -1808,15 +1783,13 @@
reply = dbus_message_new_method_return(message);
if (reply == NULL) {
- reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
+ reply = wpas_dbus_error_no_memory(message);
goto err;
}
if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID)) {
dbus_message_unref(reply);
- reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
+ reply = wpas_dbus_error_no_memory(message);
goto err;
}
@@ -1846,7 +1819,7 @@
{
DBusMessage *reply = NULL;
const char *op;
- char *iface = NULL, *persistent_group_id = NULL;
+ char *iface = NULL, *persistent_group_id;
int id;
struct wpa_ssid *ssid;
@@ -1857,10 +1830,11 @@
* Extract the network ID and ensure the network is actually a child of
* this interface.
*/
- iface = wpas_dbus_new_decompose_object_path(op, 1,
- &persistent_group_id,
- NULL);
- if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+ iface = wpas_dbus_new_decompose_object_path(
+ op, WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART,
+ &persistent_group_id);
+ if (iface == NULL || persistent_group_id == NULL ||
+ os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
reply = wpas_dbus_error_invalid_args(message, op);
goto out;
}
@@ -1880,19 +1854,17 @@
wpas_notify_persistent_group_removed(wpa_s, ssid);
if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
- wpa_printf(MSG_ERROR, "dbus: %s: "
- "error occurred when removing persistent group %d",
+ wpa_printf(MSG_ERROR,
+ "dbus: %s: error occurred when removing persistent group %d",
__func__, id);
reply = wpas_dbus_error_unknown_error(
message,
- "error removing the specified persistent group on "
- "this interface.");
+ "error removing the specified persistent group on this interface.");
goto out;
}
out:
os_free(iface);
- os_free(persistent_group_id);
return reply;
}
@@ -1903,8 +1875,8 @@
wpas_notify_persistent_group_removed(wpa_s, ssid);
if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
- wpa_printf(MSG_ERROR, "dbus: %s: "
- "error occurred when removing persistent group %d",
+ wpa_printf(MSG_ERROR,
+ "dbus: %s: error occurred when removing persistent group %d",
__func__, ssid->id);
return;
}
@@ -2012,6 +1984,7 @@
DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
+
if (wpa_s->current_ssid == NULL)
return FALSE;
return wpas_dbus_simple_array_property_getter(
@@ -2072,15 +2045,14 @@
void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
- u8 role = wpas_get_p2p_role(wpa_s);
- char *p_pass = NULL;
+ char *p_pass;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
- /* Verify correct role for this property */
- if (role == WPAS_P2P_ROLE_GO) {
- if (wpa_s->current_ssid == NULL)
- return FALSE;
- p_pass = wpa_s->current_ssid->passphrase;
- } else
+ if (ssid == NULL)
+ return FALSE;
+
+ p_pass = ssid->passphrase;
+ if (!p_pass)
p_pass = "";
return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
@@ -2093,20 +2065,20 @@
DBusError *error, void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
- u8 role = wpas_get_p2p_role(wpa_s);
u8 *p_psk = NULL;
u8 psk_len = 0;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
- /* Verify correct role for this property */
- if (role == WPAS_P2P_ROLE_CLIENT) {
- if (wpa_s->current_ssid == NULL)
- return FALSE;
- p_psk = wpa_s->current_ssid->psk;
- psk_len = 32;
+ if (ssid == NULL)
+ return FALSE;
+
+ if (ssid->psk_set) {
+ p_psk = ssid->psk;
+ psk_len = sizeof(ssid->psk);
}
return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
- &p_psk, psk_len, error);
+ p_psk, psk_len, error);
}
@@ -2150,7 +2122,7 @@
void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
- DBusMessageIter variant_iter, iter_dict;
+ DBusMessageIter variant_iter, iter_dict, array_iter, sub;
struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
unsigned int i;
struct hostapd_data *hapd = NULL;
@@ -2162,6 +2134,82 @@
return FALSE;
dbus_message_iter_recurse(iter, &variant_iter);
+ if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY)
+ return FALSE;
+
+ /*
+ * This is supposed to be array of bytearrays (aay), but the earlier
+ * implementation used a dict with "WPSVendorExtensions" as the key in
+ * this setter function which does not match the format used by the
+ * getter function. For backwards compatibility, allow both formats to
+ * be used in the setter.
+ */
+ if (dbus_message_iter_get_element_type(&variant_iter) ==
+ DBUS_TYPE_ARRAY) {
+ /* This is the proper format matching the getter */
+ struct wpabuf *vals[MAX_WPS_VENDOR_EXTENSIONS];
+
+ dbus_message_iter_recurse(&variant_iter, &array_iter);
+
+ if (dbus_message_iter_get_arg_type(&array_iter) !=
+ DBUS_TYPE_ARRAY ||
+ dbus_message_iter_get_element_type(&array_iter) !=
+ DBUS_TYPE_BYTE) {
+ wpa_printf(MSG_DEBUG,
+ "dbus: Not an array of array of bytes");
+ return FALSE;
+ }
+
+ i = 0;
+ os_memset(vals, 0, sizeof(vals));
+
+ while (dbus_message_iter_get_arg_type(&array_iter) ==
+ DBUS_TYPE_ARRAY) {
+ char *val;
+ int len;
+
+ if (i == MAX_WPS_VENDOR_EXTENSIONS) {
+ wpa_printf(MSG_DEBUG,
+ "dbus: Too many WPSVendorExtensions values");
+ i = MAX_WPS_VENDOR_EXTENSIONS + 1;
+ break;
+ }
+
+ dbus_message_iter_recurse(&array_iter, &sub);
+ dbus_message_iter_get_fixed_array(&sub, &val, &len);
+ wpa_hexdump(MSG_DEBUG, "dbus: WPSVendorExtentions[]",
+ val, len);
+ vals[i] = wpabuf_alloc_copy(val, len);
+ if (vals[i] == NULL) {
+ i = MAX_WPS_VENDOR_EXTENSIONS + 1;
+ break;
+ }
+ i++;
+ dbus_message_iter_next(&array_iter);
+ }
+
+ if (i > MAX_WPS_VENDOR_EXTENSIONS) {
+ for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++)
+ wpabuf_free(vals[i]);
+ return FALSE;
+ }
+
+ for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
+ wpabuf_free(hapd->conf->wps_vendor_ext[i]);
+ hapd->conf->wps_vendor_ext[i] = vals[i];
+ }
+
+ hostapd_update_wps(hapd);
+
+ return TRUE;
+ }
+
+ if (dbus_message_iter_get_element_type(&variant_iter) !=
+ DBUS_TYPE_DICT_ENTRY)
+ return FALSE;
+
+ wpa_printf(MSG_DEBUG,
+ "dbus: Try to use backwards compatibility version of WPSVendorExtensions setter");
if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict, error))
return FALSE;
@@ -2179,6 +2227,7 @@
goto error;
for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
+ wpabuf_free(hapd->conf->wps_vendor_ext[i]);
if (i < entry.array_len) {
hapd->conf->wps_vendor_ext[i] =
entry.binarray_value[i];
@@ -2227,30 +2276,31 @@
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto error;
- if (!os_strcmp(entry.key, "service_type") &&
- (entry.type == DBUS_TYPE_STRING)) {
- if (!os_strcmp(entry.str_value, "upnp"))
+ if (os_strcmp(entry.key, "service_type") == 0 &&
+ entry.type == DBUS_TYPE_STRING) {
+ if (os_strcmp(entry.str_value, "upnp") == 0)
upnp = 1;
- else if (!os_strcmp(entry.str_value, "bonjour"))
+ else if (os_strcmp(entry.str_value, "bonjour") == 0)
bonjour = 1;
else
goto error_clear;
- } else if (!os_strcmp(entry.key, "version") &&
- entry.type == DBUS_TYPE_INT32) {
+ } else if (os_strcmp(entry.key, "version") == 0 &&
+ entry.type == DBUS_TYPE_INT32) {
version = entry.uint32_value;
- } else if (!os_strcmp(entry.key, "service") &&
- (entry.type == DBUS_TYPE_STRING)) {
+ } else if (os_strcmp(entry.key, "service") == 0 &&
+ entry.type == DBUS_TYPE_STRING) {
+ os_free(service);
service = os_strdup(entry.str_value);
- } else if (!os_strcmp(entry.key, "query")) {
- if ((entry.type != DBUS_TYPE_ARRAY) ||
- (entry.array_type != DBUS_TYPE_BYTE))
+ } else if (os_strcmp(entry.key, "query") == 0) {
+ if (entry.type != DBUS_TYPE_ARRAY ||
+ entry.array_type != DBUS_TYPE_BYTE)
goto error_clear;
query = wpabuf_alloc_copy(
entry.bytearray_value,
entry.array_len);
- } else if (!os_strcmp(entry.key, "response")) {
- if ((entry.type != DBUS_TYPE_ARRAY) ||
- (entry.array_type != DBUS_TYPE_BYTE))
+ } else if (os_strcmp(entry.key, "response") == 0) {
+ if (entry.type != DBUS_TYPE_ARRAY ||
+ entry.array_type != DBUS_TYPE_BYTE)
goto error_clear;
resp = wpabuf_alloc_copy(entry.bytearray_value,
entry.array_len);
@@ -2265,8 +2315,6 @@
if (wpas_p2p_service_add_upnp(wpa_s, version, service) != 0)
goto error;
- os_free(service);
- service = NULL;
} else if (bonjour == 1) {
if (query == NULL || resp == NULL)
goto error;
@@ -2278,6 +2326,7 @@
} else
goto error;
+ os_free(service);
return reply;
error_clear:
wpa_dbus_dict_entry_clear(&entry);
@@ -2312,11 +2361,11 @@
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto error;
- if (!os_strcmp(entry.key, "service_type") &&
- (entry.type == DBUS_TYPE_STRING)) {
- if (!os_strcmp(entry.str_value, "upnp"))
+ if (os_strcmp(entry.key, "service_type") == 0 &&
+ entry.type == DBUS_TYPE_STRING) {
+ if (os_strcmp(entry.str_value, "upnp") == 0)
upnp = 1;
- else if (!os_strcmp(entry.str_value, "bonjour"))
+ else if (os_strcmp(entry.str_value, "bonjour") == 0)
bonjour = 1;
else
goto error_clear;
@@ -2327,13 +2376,14 @@
while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto error;
- if (!os_strcmp(entry.key, "version") &&
+ if (os_strcmp(entry.key, "version") == 0 &&
entry.type == DBUS_TYPE_INT32)
version = entry.uint32_value;
- else if (!os_strcmp(entry.key, "service") &&
- entry.type == DBUS_TYPE_STRING)
+ else if (os_strcmp(entry.key, "service") == 0 &&
+ entry.type == DBUS_TYPE_STRING) {
+ os_free(service);
service = os_strdup(entry.str_value);
- else
+ } else
goto error_clear;
wpa_dbus_dict_entry_clear(&entry);
@@ -2343,7 +2393,6 @@
goto error;
ret = wpas_p2p_service_del_upnp(wpa_s, version, service);
- os_free(service);
if (ret != 0)
goto error;
} else if (bonjour == 1) {
@@ -2351,10 +2400,11 @@
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto error;
- if (!os_strcmp(entry.key, "query")) {
- if ((entry.type != DBUS_TYPE_ARRAY) ||
- (entry.array_type != DBUS_TYPE_BYTE))
+ if (os_strcmp(entry.key, "query") == 0) {
+ if (entry.type != DBUS_TYPE_ARRAY ||
+ entry.array_type != DBUS_TYPE_BYTE)
goto error_clear;
+ wpabuf_free(query);
query = wpabuf_alloc_copy(
entry.bytearray_value,
entry.array_len);
@@ -2370,14 +2420,17 @@
ret = wpas_p2p_service_del_bonjour(wpa_s, query);
if (ret != 0)
goto error;
- wpabuf_free(query);
} else
goto error;
+ wpabuf_free(query);
+ os_free(service);
return reply;
error_clear:
wpa_dbus_dict_entry_clear(&entry);
error:
+ wpabuf_free(query);
+ os_free(service);
return wpas_dbus_error_invalid_args(message, NULL);
}
@@ -2413,22 +2466,22 @@
while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto error;
- if (!os_strcmp(entry.key, "peer_object") &&
+ if (os_strcmp(entry.key, "peer_object") == 0 &&
entry.type == DBUS_TYPE_OBJECT_PATH) {
peer_object_path = os_strdup(entry.str_value);
- } else if (!os_strcmp(entry.key, "service_type") &&
+ } else if (os_strcmp(entry.key, "service_type") == 0 &&
entry.type == DBUS_TYPE_STRING) {
- if (!os_strcmp(entry.str_value, "upnp"))
+ if (os_strcmp(entry.str_value, "upnp") == 0)
upnp = 1;
else
goto error_clear;
- } else if (!os_strcmp(entry.key, "version") &&
+ } else if (os_strcmp(entry.key, "version") == 0 &&
entry.type == DBUS_TYPE_INT32) {
version = entry.uint32_value;
- } else if (!os_strcmp(entry.key, "service") &&
+ } else if (os_strcmp(entry.key, "service") == 0 &&
entry.type == DBUS_TYPE_STRING) {
service = os_strdup(entry.str_value);
- } else if (!os_strcmp(entry.key, "tlv")) {
+ } else if (os_strcmp(entry.key, "tlv") == 0) {
if (entry.type != DBUS_TYPE_ARRAY ||
entry.array_type != DBUS_TYPE_BYTE)
goto error_clear;
@@ -2506,16 +2559,17 @@
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto error;
- if (!os_strcmp(entry.key, "peer_object") &&
+ if (os_strcmp(entry.key, "peer_object") == 0 &&
entry.type == DBUS_TYPE_OBJECT_PATH) {
peer_object_path = os_strdup(entry.str_value);
- } else if (!os_strcmp(entry.key, "frequency") &&
+ } else if (os_strcmp(entry.key, "frequency") == 0 &&
entry.type == DBUS_TYPE_INT32) {
freq = entry.uint32_value;
- } else if (!os_strcmp(entry.key, "dialog_token") &&
- entry.type == DBUS_TYPE_UINT32) {
+ } else if (os_strcmp(entry.key, "dialog_token") == 0 &&
+ (entry.type == DBUS_TYPE_UINT32 ||
+ entry.type == DBUS_TYPE_INT32)) {
dlg_tok = entry.uint32_value;
- } else if (!os_strcmp(entry.key, "tlvs")) {
+ } else if (os_strcmp(entry.key, "tlvs") == 0) {
if (entry.type != DBUS_TYPE_ARRAY ||
entry.array_type != DBUS_TYPE_BYTE)
goto error_clear;
@@ -2526,12 +2580,9 @@
wpa_dbus_dict_entry_clear(&entry);
}
- if (!peer_object_path ||
- (parse_peer_object_path(peer_object_path, addr) < 0) ||
- !p2p_peer_known(wpa_s->global->p2p, addr))
- goto error;
-
- if (tlv == NULL)
+ if (parse_peer_object_path(peer_object_path, addr) < 0 ||
+ !p2p_peer_known(wpa_s->global->p2p, addr) ||
+ tlv == NULL)
goto error;
wpas_p2p_sd_response(wpa_s, freq, addr, (u8) dlg_tok, tlv);
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.h b/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
index 6e67c89..fdaccba 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
@@ -109,34 +109,34 @@
*/
dbus_bool_t wpas_dbus_getter_p2p_peer_device_name(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
+ DBusError *error,
+ void *user_data);
dbus_bool_t wpas_dbus_getter_p2p_peer_primary_device_type(
DBusMessageIter *iter, DBusError *error, void *user_data);
dbus_bool_t wpas_dbus_getter_p2p_peer_config_method(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
+ DBusError *error,
+ void *user_data);
dbus_bool_t wpas_dbus_getter_p2p_peer_level(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
+ DBusError *error,
+ void *user_data);
dbus_bool_t wpas_dbus_getter_p2p_peer_device_capability(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
+ DBusError *error,
+ void *user_data);
dbus_bool_t wpas_dbus_getter_p2p_peer_group_capability(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
+ DBusError *error,
+ void *user_data);
dbus_bool_t wpas_dbus_getter_p2p_peer_secondary_device_types(
DBusMessageIter *iter, DBusError *error, void *user_data);
dbus_bool_t wpas_dbus_getter_p2p_peer_vendor_extension(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
+ DBusError *error,
+ void *user_data);
dbus_bool_t wpas_dbus_getter_p2p_peer_ies(DBusMessageIter *iter,
DBusError *error,
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_wps.c b/wpa_supplicant/dbus/dbus_new_handlers_wps.c
index 8ecf7db..a94a0e5 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_wps.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_wps.c
@@ -41,8 +41,8 @@
dbus_message_iter_recurse(entry_iter, &variant_iter);
if (dbus_message_iter_get_arg_type(&variant_iter) !=
DBUS_TYPE_STRING) {
- wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Role type, "
- "string required");
+ wpa_printf(MSG_DEBUG,
+ "dbus: WPS.Start - Wrong Role type, string required");
*reply = wpas_dbus_error_invalid_args(message,
"Role must be a string");
return -1;
@@ -70,10 +70,9 @@
char *val;
dbus_message_iter_recurse(entry_iter, &variant_iter);
- if (dbus_message_iter_get_arg_type(&variant_iter) !=
- DBUS_TYPE_STRING) {
- wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Type type, "
- "string required");
+ if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_STRING) {
+ wpa_printf(MSG_DEBUG,
+ "dbus: WPS.Start - Wrong Type type, string required");
*reply = wpas_dbus_error_invalid_args(message,
"Type must be a string");
return -1;
@@ -105,8 +104,8 @@
if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY ||
dbus_message_iter_get_element_type(&variant_iter) !=
DBUS_TYPE_BYTE) {
- wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Bssid type, "
- "byte array required");
+ wpa_printf(MSG_DEBUG,
+ "dbus: WPS.Start - Wrong Bssid type, byte array required");
*reply = wpas_dbus_error_invalid_args(
message, "Bssid must be a byte array");
return -1;
@@ -114,8 +113,8 @@
dbus_message_iter_recurse(&variant_iter, &array_iter);
dbus_message_iter_get_fixed_array(&array_iter, ¶ms->bssid, &len);
if (len != ETH_ALEN) {
- wpa_printf(MSG_DEBUG, "dbus: WPS.Stsrt - Wrong Bssid length "
- "%d", len);
+ wpa_printf(MSG_DEBUG, "dbus: WPS.Stsrt - Wrong Bssid length %d",
+ len);
*reply = wpas_dbus_error_invalid_args(message,
"Bssid is wrong length");
return -1;
@@ -132,10 +131,9 @@
DBusMessageIter variant_iter;
dbus_message_iter_recurse(entry_iter, &variant_iter);
- if (dbus_message_iter_get_arg_type(&variant_iter) !=
- DBUS_TYPE_STRING) {
- wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Pin type, "
- "string required");
+ if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_STRING) {
+ wpa_printf(MSG_DEBUG,
+ "dbus: WPS.Start - Wrong Pin type, string required");
*reply = wpas_dbus_error_invalid_args(message,
"Pin must be a string");
return -1;
@@ -158,8 +156,8 @@
if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY ||
dbus_message_iter_get_element_type(&variant_iter) !=
DBUS_TYPE_BYTE) {
- wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong "
- "P2PDeviceAddress type, byte array required");
+ wpa_printf(MSG_DEBUG,
+ "dbus: WPS.Start - Wrong P2PDeviceAddress type, byte array required");
*reply = wpas_dbus_error_invalid_args(
message, "P2PDeviceAddress must be a byte array");
return -1;
@@ -168,11 +166,11 @@
dbus_message_iter_get_fixed_array(&array_iter, ¶ms->p2p_dev_addr,
&len);
if (len != ETH_ALEN) {
- wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong "
- "P2PDeviceAddress length %d", len);
- *reply = wpas_dbus_error_invalid_args(message,
- "P2PDeviceAddress "
- "has wrong length");
+ wpa_printf(MSG_DEBUG,
+ "dbus: WPS.Start - Wrong P2PDeviceAddress length %d",
+ len);
+ *reply = wpas_dbus_error_invalid_args(
+ message, "P2PDeviceAddress has wrong length");
return -1;
}
return 0;
@@ -249,54 +247,54 @@
dbus_message_iter_next(&dict_iter);
}
+#ifdef CONFIG_AP
+ if (wpa_s->ap_iface && params.type == 1) {
+ if (params.pin == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "dbus: WPS.Start - Pin required for registrar role");
+ return wpas_dbus_error_invalid_args(
+ message, "Pin required for registrar role.");
+ }
+ ret = wpa_supplicant_ap_wps_pin(wpa_s,
+ params.bssid,
+ params.pin,
+ npin, sizeof(npin), 0);
+ } else if (wpa_s->ap_iface) {
+ ret = wpa_supplicant_ap_wps_pbc(wpa_s,
+ params.bssid,
+ params.p2p_dev_addr);
+ } else
+#endif /* CONFIG_AP */
if (params.role == 0) {
wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Role not specified");
return wpas_dbus_error_invalid_args(message,
"Role not specified");
- } else if (params.role == 1 && params.type == 0) {
+ } else if (params.role == 2) {
+ if (params.pin == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "dbus: WPS.Start - Pin required for registrar role");
+ return wpas_dbus_error_invalid_args(
+ message, "Pin required for registrar role.");
+ }
+ ret = wpas_wps_start_reg(wpa_s, params.bssid, params.pin,
+ NULL);
+ } else if (params.type == 0) {
wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Type not specified");
return wpas_dbus_error_invalid_args(message,
"Type not specified");
- } else if (params.role == 2 && params.pin == NULL) {
- wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Pin required for "
- "registrar role");
- return wpas_dbus_error_invalid_args(
- message, "Pin required for registrar role.");
- }
-
- if (params.role == 2)
- ret = wpas_wps_start_reg(wpa_s, params.bssid, params.pin,
- NULL);
- else if (params.type == 1) {
-#ifdef CONFIG_AP
- if (wpa_s->ap_iface)
- ret = wpa_supplicant_ap_wps_pin(wpa_s,
- params.bssid,
- params.pin,
- npin, sizeof(npin), 0);
- else
-#endif /* CONFIG_AP */
- {
- ret = wpas_wps_start_pin(wpa_s, params.bssid,
- params.pin, 0,
- DEV_PW_DEFAULT);
- if (ret > 0)
- os_snprintf(npin, sizeof(npin), "%08d", ret);
- }
+ } else if (params.type == 1) {
+ ret = wpas_wps_start_pin(wpa_s, params.bssid,
+ params.pin, 0,
+ DEV_PW_DEFAULT);
+ if (ret > 0)
+ os_snprintf(npin, sizeof(npin), "%08d", ret);
} else {
-#ifdef CONFIG_AP
- if (wpa_s->ap_iface)
- ret = wpa_supplicant_ap_wps_pbc(wpa_s,
- params.bssid,
- params.p2p_dev_addr);
- else
-#endif /* CONFIG_AP */
ret = wpas_wps_start_pbc(wpa_s, params.bssid, 0);
}
if (ret < 0) {
- wpa_printf(MSG_DEBUG, "dbus: WPS.Start wpas_wps_failed in "
- "role %s and key %s",
+ wpa_printf(MSG_DEBUG,
+ "dbus: WPS.Start wpas_wps_failed in role %s and key %s",
(params.role == 1 ? "enrollee" : "registrar"),
(params.type == 0 ? "" :
(params.type == 1 ? "pin" : "pbc")));
@@ -305,31 +303,16 @@
}
reply = dbus_message_new_method_return(message);
- if (!reply) {
- return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
- }
+ if (!reply)
+ return wpas_dbus_error_no_memory(message);
dbus_message_iter_init_append(reply, &iter);
- if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) {
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+ (os_strlen(npin) > 0 &&
+ !wpa_dbus_dict_append_string(&dict_iter, "Pin", npin)) ||
+ !wpa_dbus_dict_close_write(&iter, &dict_iter)) {
dbus_message_unref(reply);
- return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
- }
-
- if (os_strlen(npin) > 0) {
- if (!wpa_dbus_dict_append_string(&dict_iter, "Pin", npin)) {
- dbus_message_unref(reply);
- return dbus_message_new_error(message,
- DBUS_ERROR_NO_MEMORY,
- NULL);
- }
- }
-
- if (!wpa_dbus_dict_close_write(&iter, &dict_iter)) {
- dbus_message_unref(reply);
- return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- NULL);
+ return wpas_dbus_error_no_memory(message);
}
return reply;
@@ -351,7 +334,8 @@
void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
- dbus_bool_t process = (wpa_s->conf->wps_cred_processing != 1);
+ dbus_bool_t process = wpa_s->conf->wps_cred_processing != 1;
+
return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
&process, error);
}
@@ -378,7 +362,7 @@
&process_credentials))
return FALSE;
- old_pc = (wpa_s->conf->wps_cred_processing != 1);
+ old_pc = wpa_s->conf->wps_cred_processing != 1;
wpa_s->conf->wps_cred_processing = (process_credentials ? 2 : 1);
if ((wpa_s->conf->wps_cred_processing != 1) != old_pc)
@@ -408,6 +392,8 @@
struct wpa_supplicant *wpa_s = user_data;
char *methods = wpa_s->conf->config_methods;
+ if (methods == NULL)
+ methods = "";
return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
&methods, error);
}
diff --git a/wpa_supplicant/dbus/dbus_new_helpers.c b/wpa_supplicant/dbus/dbus_new_helpers.c
index 750522d..15b0901 100644
--- a/wpa_supplicant/dbus/dbus_new_helpers.c
+++ b/wpa_supplicant/dbus/dbus_new_helpers.c
@@ -15,6 +15,7 @@
#include "dbus_common_i.h"
#include "dbus_new.h"
#include "dbus_new_helpers.h"
+#include "dbus_new_handlers.h"
#include "dbus_dict_helpers.h"
@@ -73,46 +74,36 @@
* with properties names as keys and theirs values as values.
*/
static DBusMessage * get_all_properties(DBusMessage *message, char *interface,
- struct wpa_dbus_object_desc *obj_dsc)
+ struct wpa_dbus_object_desc *obj_dsc)
{
DBusMessage *reply;
DBusMessageIter iter, dict_iter;
DBusError error;
reply = dbus_message_new_method_return(message);
- if (reply == NULL) {
- wpa_printf(MSG_ERROR, "%s: out of memory creating dbus reply",
- __func__);
- return NULL;
- }
+ if (reply == NULL)
+ return wpas_dbus_error_no_memory(message);
dbus_message_iter_init_append(reply, &iter);
if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) {
- wpa_printf(MSG_ERROR, "%s: out of memory creating reply",
- __func__);
dbus_message_unref(reply);
- reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- "out of memory");
- return reply;
+ return wpas_dbus_error_no_memory(message);
}
dbus_error_init(&error);
if (!fill_dict_with_properties(&dict_iter, obj_dsc->properties,
- interface, obj_dsc->user_data, &error))
- {
+ interface, obj_dsc->user_data, &error)) {
dbus_message_unref(reply);
- reply = wpas_dbus_reply_new_from_error(message, &error,
- DBUS_ERROR_INVALID_ARGS,
- "No readable properties"
- " in this interface");
+ reply = wpas_dbus_reply_new_from_error(
+ message, &error, DBUS_ERROR_INVALID_ARGS,
+ "No readable properties in this interface");
dbus_error_free(&error);
return reply;
}
if (!wpa_dbus_dict_close_write(&iter, &dict_iter)) {
dbus_message_unref(reply);
- return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
- "out of memory");
+ return wpas_dbus_error_no_memory(message);
}
return reply;
@@ -135,8 +126,9 @@
for (arg = method_dsc->args; arg && arg->name; arg++) {
if (arg->dir == ARG_IN) {
size_t blen = registered_sig + MAX_SIG_LEN - pos;
+
ret = os_snprintf(pos, blen, "%s", arg->type);
- if (ret < 0 || (size_t) ret >= blen)
+ if (os_snprintf_error(blen, ret))
return 0;
pos += ret;
}
@@ -270,10 +262,13 @@
}
if (os_strncmp(WPA_DBUS_PROPERTIES_GET, method,
- WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) == 0)
+ WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) == 0) {
+ wpa_printf(MSG_MSGDUMP, "%s: Get(%s)", __func__, property);
return properties_get(message, property_dsc,
obj_dsc->user_data);
+ }
+ wpa_printf(MSG_MSGDUMP, "%s: Set(%s)", __func__, property);
return properties_set(message, property_dsc, obj_dsc->user_data);
}
@@ -295,8 +290,7 @@
!os_strncmp(WPA_DBUS_PROPERTIES_GETALL, method,
WPAS_DBUS_METHOD_SIGNAL_PROP_MAX)) {
/* First argument: interface name (DBUS_TYPE_STRING) */
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
- {
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
return dbus_message_new_error(message,
DBUS_ERROR_INVALID_ARGS,
NULL);
@@ -352,8 +346,7 @@
NULL);
}
- return method_dsc->method_handler(message,
- obj_dsc->user_data);
+ return method_dsc->method_handler(message, obj_dsc->user_data);
}
@@ -388,8 +381,9 @@
if (!method || !path || !msg_interface)
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- wpa_printf(MSG_MSGDUMP, "dbus: %s.%s (%s)",
- msg_interface, method, path);
+ wpa_printf(MSG_MSGDUMP, "dbus: %s.%s (%s) [%s]",
+ msg_interface, method, path,
+ dbus_message_get_signature(message));
/* if message is introspection method call */
if (!os_strncmp(WPA_DBUS_INTROSPECTION_METHOD, method,
@@ -401,8 +395,7 @@
#else /* CONFIG_CTRL_IFACE_DBUS_INTRO */
reply = dbus_message_new_error(
message, DBUS_ERROR_UNKNOWN_METHOD,
- "wpa_supplicant was compiled without "
- "introspection support.");
+ "wpa_supplicant was compiled without introspection support.");
#endif /* CONFIG_CTRL_IFACE_DBUS_INTRO */
} else if (!os_strncmp(WPA_DBUS_PROPERTIES_INTERFACE, msg_interface,
WPAS_DBUS_INTERFACE_MAX)) {
@@ -455,6 +448,7 @@
free_dbus_object_desc(obj_dsc);
}
+
/**
* wpa_dbus_ctrl_iface_init - Initialize dbus control interface
* @application_data: Pointer to application specific data structure
@@ -482,30 +476,28 @@
obj_desc->path = os_strdup(dbus_path);
/* Register the message handler for the global dbus interface */
- if (!dbus_connection_register_object_path(iface->con,
- dbus_path, &wpa_vtable,
- obj_desc)) {
- wpa_printf(MSG_ERROR, "dbus: Could not set up message "
- "handler");
+ if (!dbus_connection_register_object_path(iface->con, dbus_path,
+ &wpa_vtable, obj_desc)) {
+ wpa_printf(MSG_ERROR, "dbus: Could not set up message handler");
return -1;
}
/* Register our service with the message bus */
dbus_error_init(&error);
- switch (dbus_bus_request_name(iface->con, dbus_service,
- 0, &error)) {
+ switch (dbus_bus_request_name(iface->con, dbus_service, 0, &error)) {
case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
ret = 0;
break;
case DBUS_REQUEST_NAME_REPLY_EXISTS:
case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
- wpa_printf(MSG_ERROR, "dbus: Could not request service name: "
- "already registered");
+ wpa_printf(MSG_ERROR,
+ "dbus: Could not request service name: already registered");
break;
default:
- wpa_printf(MSG_ERROR, "dbus: Could not request service name: "
- "%s %s", error.name, error.message);
+ wpa_printf(MSG_ERROR,
+ "dbus: Could not request service name: %s %s",
+ error.name, error.message);
break;
}
dbus_error_free(&error);
@@ -529,14 +521,12 @@
*
* Registers a new interface with dbus and assigns it a dbus object path.
*/
-int wpa_dbus_register_object_per_iface(
- struct wpas_dbus_priv *ctrl_iface,
- const char *path, const char *ifname,
- struct wpa_dbus_object_desc *obj_desc)
+int wpa_dbus_register_object_per_iface(struct wpas_dbus_priv *ctrl_iface,
+ const char *path, const char *ifname,
+ struct wpa_dbus_object_desc *obj_desc)
{
DBusConnection *con;
DBusError error;
-
DBusObjectPathVTable vtable = {
&free_dbus_object_desc_cb, &message_handler,
NULL, NULL, NULL, NULL
@@ -554,14 +544,12 @@
/* Register the message handler for the interface functions */
if (!dbus_connection_try_register_object_path(con, path, &vtable,
obj_desc, &error)) {
- if (!os_strcmp(error.name, DBUS_ERROR_OBJECT_PATH_IN_USE)) {
+ if (os_strcmp(error.name, DBUS_ERROR_OBJECT_PATH_IN_USE) == 0) {
wpa_printf(MSG_DEBUG, "dbus: %s", error.message);
} else {
- wpa_printf(MSG_ERROR, "dbus: Could not set up message "
- "handler for interface %s object %s",
- ifname, path);
- wpa_printf(MSG_ERROR, "dbus error: %s", error.name);
- wpa_printf(MSG_ERROR, "dbus: %s", error.message);
+ wpa_printf(MSG_ERROR,
+ "dbus: Could not set up message handler for interface %s object %s (error: %s message: %s)",
+ ifname, path, error.name, error.message);
}
dbus_error_free(&error);
return -1;
@@ -591,8 +579,9 @@
dbus_connection_get_object_path_data(con, path, (void **) &obj_desc);
if (!obj_desc) {
- wpa_printf(MSG_ERROR, "dbus: %s: Could not obtain object's "
- "private data: %s", __func__, path);
+ wpa_printf(MSG_ERROR,
+ "dbus: %s: Could not obtain object's private data: %s",
+ __func__, path);
return 0;
}
@@ -626,24 +615,22 @@
if (!dbus_message_iter_open_container(dict_iter,
DBUS_TYPE_DICT_ENTRY,
- NULL, &entry_iter))
- return FALSE;
-
- if (!dbus_message_iter_append_basic(&entry_iter,
+ NULL, &entry_iter) ||
+ !dbus_message_iter_append_basic(&entry_iter,
DBUS_TYPE_STRING,
&dsc->dbus_property))
return FALSE;
dbus_error_init(&error);
if (!dsc->getter(&entry_iter, &error, obj_dsc->user_data)) {
- if (dbus_error_is_set (&error)) {
- wpa_printf(MSG_ERROR, "dbus: %s: Cannot get "
- "new value of property %s: (%s) %s",
- __func__, dsc->dbus_property,
- error.name, error.message);
+ if (dbus_error_is_set(&error)) {
+ wpa_printf(MSG_ERROR,
+ "dbus: %s: Cannot get new value of property %s: (%s) %s",
+ __func__, dsc->dbus_property,
+ error.name, error.message);
} else {
- wpa_printf(MSG_ERROR, "dbus: %s: Cannot get "
- "new value of property %s",
+ wpa_printf(MSG_ERROR,
+ "dbus: %s: Cannot get new value of property %s",
__func__, dsc->dbus_property);
}
dbus_error_free(&error);
@@ -673,38 +660,23 @@
dbus_message_iter_init_append(msg, &signal_iter);
if (!dbus_message_iter_append_basic(&signal_iter, DBUS_TYPE_STRING,
- &interface))
- goto err;
+ &interface) ||
+ /* Changed properties dict */
+ !dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
+ "{sv}", &dict_iter) ||
+ !put_changed_properties(obj_dsc, interface, &dict_iter, 0) ||
+ !dbus_message_iter_close_container(&signal_iter, &dict_iter) ||
+ /* Invalidated properties array (empty) */
+ !dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
+ "s", &dict_iter) ||
+ !dbus_message_iter_close_container(&signal_iter, &dict_iter)) {
+ wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal",
+ __func__);
+ } else {
+ dbus_connection_send(con, msg, NULL);
+ }
- /* Changed properties dict */
- if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
- "{sv}", &dict_iter))
- goto err;
-
- if (!put_changed_properties(obj_dsc, interface, &dict_iter, 0))
- goto err;
-
- if (!dbus_message_iter_close_container(&signal_iter, &dict_iter))
- goto err;
-
- /* Invalidated properties array (empty) */
- if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
- "s", &dict_iter))
- goto err;
-
- if (!dbus_message_iter_close_container(&signal_iter, &dict_iter))
- goto err;
-
- dbus_connection_send(con, msg, NULL);
-
-out:
dbus_message_unref(msg);
- return;
-
-err:
- wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal",
- __func__);
- goto out;
}
@@ -722,25 +694,16 @@
dbus_message_iter_init_append(msg, &signal_iter);
if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
- "{sv}", &dict_iter))
- goto err;
+ "{sv}", &dict_iter) ||
+ !put_changed_properties(obj_dsc, interface, &dict_iter, 1) ||
+ !dbus_message_iter_close_container(&signal_iter, &dict_iter)) {
+ wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal",
+ __func__);
+ } else {
+ dbus_connection_send(con, msg, NULL);
+ }
- if (!put_changed_properties(obj_dsc, interface, &dict_iter, 1))
- goto err;
-
- if (!dbus_message_iter_close_container(&signal_iter, &dict_iter))
- goto err;
-
- dbus_connection_send(con, msg, NULL);
-
-out:
dbus_message_unref(msg);
- return;
-
-err:
- wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal",
- __func__);
- goto out;
}
@@ -772,8 +735,9 @@
DBusConnection *con = eloop_ctx;
struct wpa_dbus_object_desc *obj_desc = timeout_ctx;
- wpa_printf(MSG_DEBUG, "dbus: %s: Timeout - sending changed properties "
- "of object %s", __func__, obj_desc->path);
+ wpa_printf(MSG_DEBUG,
+ "dbus: %s: Timeout - sending changed properties of object %s",
+ __func__, obj_desc->path);
wpa_dbus_flush_object_changed_properties(con, obj_desc->path);
}
@@ -884,8 +848,9 @@
dbus_connection_get_object_path_data(iface->con, path,
(void **) &obj_desc);
if (!obj_desc) {
- wpa_printf(MSG_ERROR, "dbus: wpa_dbus_property_changed: "
- "could not obtain object's private data: %s", path);
+ wpa_printf(MSG_ERROR,
+ "dbus: wpa_dbus_property_changed: could not obtain object's private data: %s",
+ path);
return;
}
@@ -898,13 +863,14 @@
}
if (!dsc || !dsc->dbus_property) {
- wpa_printf(MSG_ERROR, "dbus: wpa_dbus_property_changed: "
- "no property %s in object %s", property, path);
+ wpa_printf(MSG_ERROR,
+ "dbus: wpa_dbus_property_changed: no property %s in object %s",
+ property, path);
return;
}
if (!eloop_is_timeout_registered(flush_object_timeout_handler,
- iface->con, obj_desc->path)) {
+ iface->con, obj_desc)) {
eloop_register_timeout(0, WPA_DBUS_SEND_PROP_CHANGED_TIMEOUT,
flush_object_timeout_handler,
iface->con, obj_desc);
@@ -936,8 +902,9 @@
dbus_connection_get_object_path_data(iface->con, path,
(void **) &obj_desc);
if (!obj_desc) {
- wpa_printf(MSG_ERROR, "dbus: %s: could not obtain object's "
- "private data: %s", __func__, path);
+ wpa_printf(MSG_ERROR,
+ "dbus: %s: could not obtain object's private data: %s",
+ __func__, path);
return FALSE;
}
@@ -951,10 +918,11 @@
if (!fill_dict_with_properties(&dict_iter, obj_desc->properties,
interface, obj_desc->user_data,
&error)) {
- wpa_printf(MSG_ERROR, "dbus: %s: failed to get object"
- " properties: (%s) %s", __func__,
- dbus_error_is_set(&error) ? error.name : "none",
- dbus_error_is_set(&error) ? error.message : "none");
+ wpa_printf(MSG_ERROR,
+ "dbus: %s: failed to get object properties: (%s) %s",
+ __func__,
+ dbus_error_is_set(&error) ? error.name : "none",
+ dbus_error_is_set(&error) ? error.message : "none");
dbus_error_free(&error);
return FALSE;
}
@@ -965,29 +933,34 @@
/**
* wpas_dbus_new_decompose_object_path - Decompose an interface object path into parts
* @path: The dbus object path
- * @p2p_persistent_group: indicates whether to parse the path as a P2P
- * persistent group object
- * @network: (out) the configured network this object path refers to, if any
- * @bssid: (out) the scanned bssid this object path refers to, if any
- * Returns: The object path of the network interface this path refers to
+ * @sep: Separating part (e.g., "Networks" or "PersistentGroups")
+ * @item: (out) The part following the specified separator, if any
+ * Returns: The object path of the interface this path refers to
*
- * For a given object path, decomposes the object path into object id, network,
- * and BSSID parts, if those parts exist.
+ * For a given object path, decomposes the object path into object id and
+ * requested part, if those parts exist. The caller is responsible for freeing
+ * the returned value. The *item pointer points to that allocated value and must
+ * not be freed separately.
+ *
+ * As an example, path = "/fi/w1/wpa_supplicant1/Interfaces/1/Networks/0" and
+ * sep = "Networks" would result in "/fi/w1/wpa_supplicant1/Interfaces/1"
+ * getting returned and *items set to point to "0".
*/
-char *wpas_dbus_new_decompose_object_path(const char *path,
- int p2p_persistent_group,
- char **network,
- char **bssid)
+char * wpas_dbus_new_decompose_object_path(const char *path, const char *sep,
+ char **item)
{
const unsigned int dev_path_prefix_len =
os_strlen(WPAS_DBUS_NEW_PATH_INTERFACES "/");
char *obj_path_only;
- char *next_sep;
+ char *pos;
+ size_t sep_len;
- /* Be a bit paranoid about path */
- if (!path || os_strncmp(path, WPAS_DBUS_NEW_PATH_INTERFACES "/",
- dev_path_prefix_len))
- return NULL;
+ *item = NULL;
+
+ /* Verify that this starts with our interface prefix */
+ if (os_strncmp(path, WPAS_DBUS_NEW_PATH_INTERFACES "/",
+ dev_path_prefix_len) != 0)
+ return NULL; /* not our path */
/* Ensure there's something at the end of the path */
if ((path + dev_path_prefix_len)[0] == '\0')
@@ -997,39 +970,20 @@
if (obj_path_only == NULL)
return NULL;
- next_sep = os_strchr(obj_path_only + dev_path_prefix_len, '/');
- if (next_sep != NULL) {
- const char *net_part = os_strstr(
- next_sep, p2p_persistent_group ?
- WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/" :
- WPAS_DBUS_NEW_NETWORKS_PART "/");
- const char *bssid_part = os_strstr(
- next_sep, WPAS_DBUS_NEW_BSSIDS_PART "/");
+ pos = obj_path_only + dev_path_prefix_len;
+ pos = os_strchr(pos, '/');
+ if (pos == NULL)
+ return obj_path_only; /* no next item on the path */
- if (network && net_part) {
- /* Deal with a request for a configured network */
- const char *net_name = net_part +
- os_strlen(p2p_persistent_group ?
- WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART
- "/" :
- WPAS_DBUS_NEW_NETWORKS_PART "/");
- *network = NULL;
- if (os_strlen(net_name))
- *network = os_strdup(net_name);
- } else if (bssid && bssid_part) {
- /* Deal with a request for a scanned BSSID */
- const char *bssid_name = bssid_part +
- os_strlen(WPAS_DBUS_NEW_BSSIDS_PART "/");
- if (os_strlen(bssid_name))
- *bssid = os_strdup(bssid_name);
- else
- *bssid = NULL;
- }
+ /* Separate network interface prefix from the path */
+ *pos++ = '\0';
- /* Cut off interface object path before "/" */
- *next_sep = '\0';
- }
+ sep_len = os_strlen(sep);
+ if (os_strncmp(pos, sep, sep_len) != 0 || pos[sep_len] != '/')
+ return obj_path_only; /* no match */
+ /* return a pointer to the requested item */
+ *item = pos + sep_len + 1;
return obj_path_only;
}
diff --git a/wpa_supplicant/dbus/dbus_new_helpers.h b/wpa_supplicant/dbus/dbus_new_helpers.h
index 6d31ad5..6e2c1f1 100644
--- a/wpa_supplicant/dbus/dbus_new_helpers.h
+++ b/wpa_supplicant/dbus/dbus_new_helpers.h
@@ -12,13 +12,13 @@
#include <dbus/dbus.h>
-typedef DBusMessage * (* WPADBusMethodHandler)(DBusMessage *message,
- void *user_data);
-typedef void (* WPADBusArgumentFreeFunction)(void *handler_arg);
+typedef DBusMessage * (*WPADBusMethodHandler)(DBusMessage *message,
+ void *user_data);
+typedef void (*WPADBusArgumentFreeFunction)(void *handler_arg);
-typedef dbus_bool_t (* WPADBusPropertyAccessor)(DBusMessageIter *iter,
- DBusError *error,
- void *user_data);
+typedef dbus_bool_t (*WPADBusPropertyAccessor)(DBusMessageIter *iter,
+ DBusError *error,
+ void *user_data);
struct wpa_dbus_object_desc {
DBusConnection *connection;
@@ -137,10 +137,8 @@
DBusMessage * wpa_dbus_introspect(DBusMessage *message,
struct wpa_dbus_object_desc *obj_dsc);
-char *wpas_dbus_new_decompose_object_path(const char *path,
- int p2p_persistent_group,
- char **network,
- char **bssid);
+char * wpas_dbus_new_decompose_object_path(const char *path, const char *sep,
+ char **item);
DBusMessage *wpas_dbus_reply_new_from_error(DBusMessage *message,
DBusError *error,
diff --git a/wpa_supplicant/dbus/dbus_new_introspect.c b/wpa_supplicant/dbus/dbus_new_introspect.c
index 3b090c0..6209c67 100644
--- a/wpa_supplicant/dbus/dbus_new_introspect.c
+++ b/wpa_supplicant/dbus/dbus_new_introspect.c
@@ -37,14 +37,16 @@
iface = os_zalloc(sizeof(struct interfaces));
if (!iface)
return NULL;
+ iface->dbus_interface = os_strdup(dbus_interface);
iface->xml = wpabuf_alloc(6000);
- if (iface->xml == NULL) {
+ if (iface->dbus_interface == NULL || iface->xml == NULL) {
+ os_free(iface->dbus_interface);
+ wpabuf_free(iface->xml);
os_free(iface);
return NULL;
}
wpabuf_printf(iface->xml, "<interface name=\"%s\">", dbus_interface);
dl_list_add_tail(list, &iface->list);
- iface->dbus_interface = os_strdup(dbus_interface);
return iface;
}
@@ -96,6 +98,7 @@
{
const struct wpa_dbus_method_desc *dsc;
struct interfaces *iface;
+
for (dsc = methods; dsc && dsc->dbus_method; dsc++) {
iface = add_interface(list, dsc->dbus_interface);
if (iface)
@@ -110,6 +113,7 @@
{
const struct wpa_dbus_signal_desc *dsc;
struct interfaces *iface;
+
for (dsc = signals; dsc && dsc->dbus_signal; dsc++) {
iface = add_interface(list, dsc->dbus_interface);
if (iface)
@@ -124,6 +128,7 @@
{
const struct wpa_dbus_property_desc *dsc;
struct interfaces *iface;
+
for (dsc = properties; dsc && dsc->dbus_property; dsc++) {
iface = add_interface(list, dsc->dbus_interface);
if (iface)
@@ -154,14 +159,14 @@
static void add_interfaces(struct dl_list *list, struct wpabuf *xml)
{
struct interfaces *iface, *n;
+
dl_list_for_each_safe(iface, n, list, struct interfaces, list) {
if (wpabuf_len(iface->xml) + 20 < wpabuf_tailroom(xml)) {
wpabuf_put_buf(xml, iface->xml);
wpabuf_put_str(xml, "</interface>");
} else {
- wpa_printf(MSG_DEBUG, "dbus: Not enough room for "
- "add_interfaces inspect data: tailroom %u, "
- "add %u",
+ wpa_printf(MSG_DEBUG,
+ "dbus: Not enough room for add_interfaces inspect data: tailroom %u, add %u",
(unsigned int) wpabuf_tailroom(xml),
(unsigned int) wpabuf_len(iface->xml));
}
@@ -229,6 +234,7 @@
struct wpa_dbus_object_desc *obj_dsc)
{
struct dl_list ifaces;
+
dl_list_init(&ifaces);
extract_interfaces(&ifaces, obj_dsc);
add_interfaces(&ifaces, xml);
@@ -270,6 +276,7 @@
reply = dbus_message_new_method_return(message);
if (reply) {
const char *intro_str = wpabuf_head(xml);
+
dbus_message_append_args(reply, DBUS_TYPE_STRING, &intro_str,
DBUS_TYPE_INVALID);
}
diff --git a/wpa_supplicant/dbus/dbus_old.c b/wpa_supplicant/dbus/dbus_old.c
index 85d8a78..45bb402 100644
--- a/wpa_supplicant/dbus/dbus_old.c
+++ b/wpa_supplicant/dbus/dbus_old.c
@@ -92,9 +92,9 @@
*/
DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message)
{
- return dbus_message_new_error(message, WPAS_ERROR_INVALID_IFACE,
- "wpa_supplicant knows nothing about "
- "this interface.");
+ return dbus_message_new_error(
+ message, WPAS_ERROR_INVALID_IFACE,
+ "wpa_supplicant knows nothing about this interface.");
}
@@ -216,8 +216,12 @@
if (!msg_interface)
goto out;
+ wpa_printf(MSG_MSGDUMP, "dbus[old/iface]: %s.%s (%s) [%s]",
+ msg_interface, method, path,
+ dbus_message_get_signature(message));
+
iface_obj_path = wpas_dbus_decompose_object_path(path, &network,
- &bssid);
+ &bssid);
if (iface_obj_path == NULL) {
reply = wpas_dbus_new_invalid_iface_error(message);
goto out;
@@ -227,7 +231,7 @@
* wpa_supplicant structure it's supposed to (which is wpa_s)
*/
if (wpa_supplicant_get_iface_by_dbus_path(wpa_s->global,
- iface_obj_path) != wpa_s) {
+ iface_obj_path) != wpa_s) {
reply = wpas_dbus_new_invalid_iface_error(message);
goto out;
}
@@ -235,6 +239,7 @@
if (network && !strcmp(msg_interface, WPAS_DBUS_IFACE_NETWORK)) {
/* A method for one of this interface's configured networks */
int nid = strtoul(network, NULL, 10);
+
if (errno != EINVAL)
reply = wpas_dispatch_network_method(message, wpa_s,
nid);
@@ -275,25 +280,25 @@
reply = wpas_dbus_iface_remove_blobs(message, wpa_s);
#endif /* CONFIG_NO_CONFIG_BLOBS */
#ifdef CONFIG_WPS
- else if (!os_strcmp(method, "wpsPbc"))
+ else if (os_strcmp(method, "wpsPbc") == 0)
reply = wpas_dbus_iface_wps_pbc(message, wpa_s);
- else if (!os_strcmp(method, "wpsPin"))
+ else if (os_strcmp(method, "wpsPin") == 0)
reply = wpas_dbus_iface_wps_pin(message, wpa_s);
- else if (!os_strcmp(method, "wpsReg"))
+ else if (os_strcmp(method, "wpsReg") == 0)
reply = wpas_dbus_iface_wps_reg(message, wpa_s);
#endif /* CONFIG_WPS */
- else if (!os_strcmp(method, "flush"))
+ else if (os_strcmp(method, "flush") == 0)
reply = wpas_dbus_iface_flush(message, wpa_s);
}
/* If the message was handled, send back the reply */
+out:
if (reply) {
if (!dbus_message_get_no_reply(message))
dbus_connection_send(connection, reply, NULL);
dbus_message_unref(reply);
}
-out:
os_free(iface_obj_path);
os_free(network);
os_free(bssid);
@@ -328,6 +333,10 @@
if (!method || !path || !ctrl_iface || !msg_interface)
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ wpa_printf(MSG_MSGDUMP, "dbus[old]: %s.%s (%s) [%s]",
+ msg_interface, method, path,
+ dbus_message_get_signature(message));
+
/* Validate the method interface */
if (strcmp(msg_interface, WPAS_DBUS_INTERFACE) != 0)
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
@@ -381,8 +390,8 @@
WPAS_DBUS_IFACE_INTERFACE,
"ScanResultsAvailable");
if (_signal == NULL) {
- wpa_printf(MSG_ERROR, "dbus: Not enough memory to send scan "
- "results signal");
+ wpa_printf(MSG_ERROR,
+ "dbus: Not enough memory to send scan results signal");
return;
}
dbus_connection_send(iface->con, _signal, NULL);
@@ -426,29 +435,21 @@
"StateChange");
if (_signal == NULL) {
wpa_printf(MSG_ERROR,
- "dbus: wpa_supplicant_dbus_notify_state_change: "
- "could not create dbus signal; likely out of "
- "memory");
+ "dbus: %s: could not create dbus signal; likely out of memory",
+ __func__);
return;
}
new_state_str = wpa_supplicant_state_txt(new_state);
old_state_str = wpa_supplicant_state_txt(old_state);
- if (new_state_str == NULL || old_state_str == NULL) {
- wpa_printf(MSG_ERROR,
- "dbus: wpa_supplicant_dbus_notify_state_change: "
- "Could not convert state strings");
- goto out;
- }
if (!dbus_message_append_args(_signal,
- DBUS_TYPE_STRING, &new_state_str,
- DBUS_TYPE_STRING, &old_state_str,
- DBUS_TYPE_INVALID)) {
+ DBUS_TYPE_STRING, &new_state_str,
+ DBUS_TYPE_STRING, &old_state_str,
+ DBUS_TYPE_INVALID)) {
wpa_printf(MSG_ERROR,
- "dbus: wpa_supplicant_dbus_notify_state_change: "
- "Not enough memory to construct state change "
- "signal");
+ "dbus: %s: Not enough memory to construct state change signal",
+ __func__);
goto out;
}
@@ -480,18 +481,18 @@
WPAS_DBUS_IFACE_INTERFACE,
"Scanning");
if (_signal == NULL) {
- wpa_printf(MSG_ERROR, "dbus: Not enough memory to send scan "
- "results signal");
+ wpa_printf(MSG_ERROR,
+ "dbus: Not enough memory to send scan results signal");
return;
}
if (dbus_message_append_args(_signal,
- DBUS_TYPE_BOOLEAN, &scanning,
- DBUS_TYPE_INVALID)) {
+ DBUS_TYPE_BOOLEAN, &scanning,
+ DBUS_TYPE_INVALID)) {
dbus_connection_send(iface->con, _signal, NULL);
} else {
- wpa_printf(MSG_ERROR, "dbus: Not enough memory to construct "
- "signal");
+ wpa_printf(MSG_ERROR,
+ "dbus: Not enough memory to construct signal");
}
dbus_message_unref(_signal);
}
@@ -516,19 +517,18 @@
"WpsCred");
if (_signal == NULL) {
wpa_printf(MSG_ERROR,
- "dbus: wpa_supplicant_dbus_notify_wps_cred: "
- "Could not create dbus signal; likely out of "
- "memory");
+ "dbus: %s: Could not create dbus signal; likely out of memory",
+ __func__);
return;
}
if (!dbus_message_append_args(_signal,
- DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
&cred->cred_attr, cred->cred_attr_len,
- DBUS_TYPE_INVALID)) {
+ DBUS_TYPE_INVALID)) {
wpa_printf(MSG_ERROR,
- "dbus: wpa_supplicant_dbus_notify_wps_cred: "
- "Not enough memory to construct signal");
+ "dbus: %s: Not enough memory to construct signal",
+ __func__);
goto out;
}
@@ -567,9 +567,8 @@
"Certification");
if (_signal == NULL) {
wpa_printf(MSG_ERROR,
- "dbus: wpa_supplicant_dbus_notify_certification: "
- "Could not create dbus signal; likely out of "
- "memory");
+ "dbus: %s: Could not create dbus signal; likely out of memory",
+ __func__);
return;
}
@@ -578,15 +577,15 @@
cert_hex_len = cert ? wpabuf_len(cert) : 0;
if (!dbus_message_append_args(_signal,
- DBUS_TYPE_INT32,&depth,
+ DBUS_TYPE_INT32, &depth,
DBUS_TYPE_STRING, &subject,
- DBUS_TYPE_STRING, &hash,
- DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+ DBUS_TYPE_STRING, &hash,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
&cert_hex, cert_hex_len,
- DBUS_TYPE_INVALID)) {
+ DBUS_TYPE_INVALID)) {
wpa_printf(MSG_ERROR,
- "dbus: wpa_supplicant_dbus_notify_certification: "
- "Not enough memory to construct signal");
+ "dbus: %s: Not enough memory to construct signal",
+ __func__);
goto out;
}
@@ -618,8 +617,7 @@
if (!dbus_connection_register_object_path(iface->con,
WPAS_DBUS_PATH, &wpas_vtable,
iface)) {
- wpa_printf(MSG_ERROR, "dbus: Could not set up message "
- "handler");
+ wpa_printf(MSG_ERROR, "dbus: Could not set up message handler");
return -1;
}
@@ -633,12 +631,13 @@
case DBUS_REQUEST_NAME_REPLY_EXISTS:
case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
- wpa_printf(MSG_ERROR, "dbus: Could not request service name: "
- "already registered");
+ wpa_printf(MSG_ERROR,
+ "dbus: Could not request service name: already registered");
break;
default:
- wpa_printf(MSG_ERROR, "dbus: Could not request service name: "
- "%s %s", error.name, error.message);
+ wpa_printf(MSG_ERROR,
+ "dbus: Could not request service name: %s %s",
+ error.name, error.message);
break;
}
dbus_error_free(&error);
@@ -687,8 +686,9 @@
/* Register the message handler for the interface functions */
if (!dbus_connection_register_fallback(con, wpa_s->dbus_path, &vtable,
wpa_s)) {
- wpa_printf(MSG_ERROR, "dbus: Could not set up message "
- "handler for interface %s", wpa_s->ifname);
+ wpa_printf(MSG_ERROR,
+ "dbus: Could not set up message handler for interface %s",
+ wpa_s->ifname);
return -1;
}
@@ -712,7 +712,7 @@
if (wpa_s == NULL || wpa_s->global == NULL)
return 0;
ctrl_iface = wpa_s->global->dbus;
- if (ctrl_iface == NULL)
+ if (ctrl_iface == NULL || wpa_s->dbus_path == NULL)
return 0;
con = ctrl_iface->con;
diff --git a/wpa_supplicant/dbus/dbus_old.h b/wpa_supplicant/dbus/dbus_old.h
index e668231..451a9f8 100644
--- a/wpa_supplicant/dbus/dbus_old.h
+++ b/wpa_supplicant/dbus/dbus_old.h
@@ -82,7 +82,7 @@
const struct wpabuf *cert);
char * wpas_dbus_decompose_object_path(const char *path, char **network,
- char **bssid);
+ char **bssid);
int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s);
int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s);
@@ -104,7 +104,12 @@
{
}
-#define wpa_supplicant_dbus_notify_state_change(w,n,o) do { } while (0)
+static inline void
+wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s,
+ enum wpa_states new_state,
+ enum wpa_states old_state)
+{
+}
static inline void
wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
diff --git a/wpa_supplicant/dbus/dbus_old_handlers.c b/wpa_supplicant/dbus/dbus_old_handlers.c
index 048158f..955ea78 100644
--- a/wpa_supplicant/dbus/dbus_old_handlers.c
+++ b/wpa_supplicant/dbus/dbus_old_handlers.c
@@ -37,9 +37,9 @@
{
DBusMessage *reply;
- reply = dbus_message_new_error(message, WPAS_ERROR_INVALID_OPTS,
- "Did not receive correct message "
- "arguments.");
+ reply = dbus_message_new_error(
+ message, WPAS_ERROR_INVALID_OPTS,
+ "Did not receive correct message arguments.");
if (arg != NULL)
dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg,
DBUS_TYPE_INVALID);
@@ -112,28 +112,28 @@
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto error;
if (!strcmp(entry.key, "driver") &&
- (entry.type == DBUS_TYPE_STRING)) {
+ entry.type == DBUS_TYPE_STRING) {
os_free(driver);
driver = os_strdup(entry.str_value);
wpa_dbus_dict_entry_clear(&entry);
if (driver == NULL)
goto error;
} else if (!strcmp(entry.key, "driver-params") &&
- (entry.type == DBUS_TYPE_STRING)) {
+ entry.type == DBUS_TYPE_STRING) {
os_free(driver_param);
driver_param = os_strdup(entry.str_value);
wpa_dbus_dict_entry_clear(&entry);
if (driver_param == NULL)
goto error;
} else if (!strcmp(entry.key, "config-file") &&
- (entry.type == DBUS_TYPE_STRING)) {
+ entry.type == DBUS_TYPE_STRING) {
os_free(confname);
confname = os_strdup(entry.str_value);
wpa_dbus_dict_entry_clear(&entry);
if (confname == NULL)
goto error;
} else if (!strcmp(entry.key, "bridge-ifname") &&
- (entry.type == DBUS_TYPE_STRING)) {
+ entry.type == DBUS_TYPE_STRING) {
os_free(bridge_ifname);
bridge_ifname = os_strdup(entry.str_value);
wpa_dbus_dict_entry_clear(&entry);
@@ -151,13 +151,13 @@
* an error if we already control it.
*/
if (wpa_supplicant_get_iface(global, ifname) != NULL) {
- reply = dbus_message_new_error(message,
- WPAS_ERROR_EXISTS_ERROR,
- "wpa_supplicant already "
- "controls this interface.");
+ reply = dbus_message_new_error(
+ message, WPAS_ERROR_EXISTS_ERROR,
+ "wpa_supplicant already controls this interface.");
} else {
struct wpa_supplicant *wpa_s;
struct wpa_interface iface;
+
os_memset(&iface, 0, sizeof(iface));
iface.ifname = ifname;
iface.driver = driver;
@@ -165,17 +165,17 @@
iface.confname = confname;
iface.bridge_ifname = bridge_ifname;
/* Otherwise, have wpa_supplicant attach to it. */
- if ((wpa_s = wpa_supplicant_add_iface(global, &iface))) {
+ wpa_s = wpa_supplicant_add_iface(global, &iface);
+ if (wpa_s) {
const char *path = wpa_s->dbus_path;
+
reply = dbus_message_new_method_return(message);
dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
- &path, DBUS_TYPE_INVALID);
+ &path, DBUS_TYPE_INVALID);
} else {
- reply = dbus_message_new_error(message,
- WPAS_ERROR_ADD_ERROR,
- "wpa_supplicant "
- "couldn't grab this "
- "interface.");
+ reply = dbus_message_new_error(
+ message, WPAS_ERROR_ADD_ERROR,
+ "wpa_supplicant couldn't grab this interface.");
}
}
@@ -226,10 +226,9 @@
if (!wpa_supplicant_remove_iface(global, wpa_s, 0)) {
reply = wpas_dbus_new_success_reply(message);
} else {
- reply = dbus_message_new_error(message,
- WPAS_ERROR_REMOVE_ERROR,
- "wpa_supplicant couldn't "
- "remove this interface.");
+ reply = dbus_message_new_error(
+ message, WPAS_ERROR_REMOVE_ERROR,
+ "wpa_supplicant couldn't remove this interface.");
}
out:
@@ -256,8 +255,8 @@
struct wpa_supplicant *wpa_s;
if (!dbus_message_get_args(message, NULL,
- DBUS_TYPE_STRING, &ifname,
- DBUS_TYPE_INVALID)) {
+ DBUS_TYPE_STRING, &ifname,
+ DBUS_TYPE_INVALID)) {
reply = wpas_dbus_new_invalid_opts_error(message, NULL);
goto out;
}
@@ -271,8 +270,8 @@
path = wpa_s->dbus_path;
reply = dbus_message_new_method_return(message);
dbus_message_append_args(reply,
- DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID);
+ DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID);
out:
return reply;
@@ -298,10 +297,10 @@
dbus_bool_t debug_show_keys;
if (!dbus_message_get_args(message, NULL,
- DBUS_TYPE_INT32, &debug_level,
- DBUS_TYPE_BOOLEAN, &debug_timestamp,
- DBUS_TYPE_BOOLEAN, &debug_show_keys,
- DBUS_TYPE_INVALID)) {
+ DBUS_TYPE_INT32, &debug_level,
+ DBUS_TYPE_BOOLEAN, &debug_timestamp,
+ DBUS_TYPE_BOOLEAN, &debug_show_keys,
+ DBUS_TYPE_INVALID)) {
return wpas_dbus_new_invalid_opts_error(message, NULL);
}
@@ -409,84 +408,56 @@
{
DBusMessage *reply;
DBusMessageIter iter, iter_dict;
- const u8 *ie;
+ const u8 *wpa_ie, *rsn_ie, *wps_ie;
/* Dump the properties into a dbus message */
reply = dbus_message_new_method_return(message);
+ wpa_ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
+ rsn_ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+ wps_ie = wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE);
+
dbus_message_iter_init_append(reply, &iter);
- if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
- goto error;
-
- if (!wpa_dbus_dict_append_byte_array(&iter_dict, "bssid",
+ if (!wpa_dbus_dict_open_write(&iter, &iter_dict) ||
+ !wpa_dbus_dict_append_byte_array(&iter_dict, "bssid",
(const char *) bss->bssid,
- ETH_ALEN))
- goto error;
-
- ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
- if (ie) {
- if (!wpa_dbus_dict_append_byte_array(&iter_dict, "ssid",
- (const char *) (ie + 2),
- ie[1]))
- goto error;
+ ETH_ALEN) ||
+ !wpa_dbus_dict_append_byte_array(&iter_dict, "ssid",
+ (const char *) bss->ssid,
+ bss->ssid_len) ||
+ (wpa_ie &&
+ !wpa_dbus_dict_append_byte_array(&iter_dict, "wpaie",
+ (const char *) wpa_ie,
+ wpa_ie[1] + 2)) ||
+ (rsn_ie &&
+ !wpa_dbus_dict_append_byte_array(&iter_dict, "rsnie",
+ (const char *) rsn_ie,
+ rsn_ie[1] + 2)) ||
+ (wps_ie &&
+ !wpa_dbus_dict_append_byte_array(&iter_dict, "wpsie",
+ (const char *) wps_ie,
+ wps_ie[1] + 2)) ||
+ (bss->freq &&
+ !wpa_dbus_dict_append_int32(&iter_dict, "frequency", bss->freq)) ||
+ !wpa_dbus_dict_append_uint16(&iter_dict, "capabilities",
+ bss->caps) ||
+ (!(bss->flags & WPA_BSS_QUAL_INVALID) &&
+ !wpa_dbus_dict_append_int32(&iter_dict, "quality", bss->qual)) ||
+ (!(bss->flags & WPA_BSS_NOISE_INVALID) &&
+ !wpa_dbus_dict_append_int32(&iter_dict, "noise", bss->noise)) ||
+ (!(bss->flags & WPA_BSS_LEVEL_INVALID) &&
+ !wpa_dbus_dict_append_int32(&iter_dict, "level", bss->level)) ||
+ !wpa_dbus_dict_append_int32(&iter_dict, "maxrate",
+ wpa_bss_get_max_rate(bss) * 500000) ||
+ !wpa_dbus_dict_close_write(&iter, &iter_dict)) {
+ if (reply)
+ dbus_message_unref(reply);
+ reply = dbus_message_new_error(
+ message, WPAS_ERROR_INTERNAL_ERROR,
+ "an internal error occurred returning BSSID properties.");
}
- ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
- if (ie) {
- if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpaie",
- (const char *) ie,
- ie[1] + 2))
- goto error;
- }
-
- ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
- if (ie) {
- if (!wpa_dbus_dict_append_byte_array(&iter_dict, "rsnie",
- (const char *) ie,
- ie[1] + 2))
- goto error;
- }
-
- ie = wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE);
- if (ie) {
- if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpsie",
- (const char *) ie,
- ie[1] + 2))
- goto error;
- }
-
- if (bss->freq) {
- if (!wpa_dbus_dict_append_int32(&iter_dict, "frequency",
- bss->freq))
- goto error;
- }
- if (!wpa_dbus_dict_append_uint16(&iter_dict, "capabilities",
- bss->caps))
- goto error;
- if (!(bss->flags & WPA_BSS_QUAL_INVALID) &&
- !wpa_dbus_dict_append_int32(&iter_dict, "quality", bss->qual))
- goto error;
- if (!(bss->flags & WPA_BSS_NOISE_INVALID) &&
- !wpa_dbus_dict_append_int32(&iter_dict, "noise", bss->noise))
- goto error;
- if (!(bss->flags & WPA_BSS_LEVEL_INVALID) &&
- !wpa_dbus_dict_append_int32(&iter_dict, "level", bss->level))
- goto error;
- if (!wpa_dbus_dict_append_int32(&iter_dict, "maxrate",
- wpa_bss_get_max_rate(bss) * 500000))
- goto error;
-
- if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
- goto error;
-
return reply;
-
-error:
- if (reply)
- dbus_message_unref(reply);
- return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR,
- "an internal error occurred returning "
- "BSSID properties.");
}
@@ -546,6 +517,7 @@
if (res < 0) {
if (!strict) {
const char *args[] = {"CCMP", "TKIP", "NONE"};
+
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "pairwise", args,
ARRAY_SIZE(args)))
@@ -555,28 +527,17 @@
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "pairwise",
&iter_dict_entry,
&iter_dict_val,
- &iter_array))
- goto error;
-
- if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "CCMP"))
- goto error;
- }
-
- if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "TKIP"))
- goto error;
- }
-
- if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "NONE"))
- goto error;
- }
-
- if (!wpa_dbus_dict_end_string_array(&iter_dict,
+ &iter_array) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "CCMP")) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "TKIP")) ||
+ ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "NONE")) ||
+ !wpa_dbus_dict_end_string_array(&iter_dict,
&iter_dict_entry,
&iter_dict_val,
&iter_array))
@@ -589,6 +550,7 @@
const char *args[] = {
"CCMP", "TKIP", "WEP104", "WEP40"
};
+
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "group", args,
ARRAY_SIZE(args)))
@@ -601,31 +563,19 @@
&iter_array))
goto error;
- if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "CCMP"))
- goto error;
- }
-
- if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "TKIP"))
- goto error;
- }
-
- if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "WEP104"))
- goto error;
- }
-
- if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "WEP40"))
- goto error;
- }
-
- if (!wpa_dbus_dict_end_string_array(&iter_dict,
+ if (((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "CCMP")) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "TKIP")) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "WEP104")) ||
+ ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "WEP40")) ||
+ !wpa_dbus_dict_end_string_array(&iter_dict,
&iter_dict_entry,
&iter_dict_val,
&iter_array))
@@ -648,38 +598,23 @@
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "key_mgmt",
&iter_dict_entry,
&iter_dict_val,
- &iter_array))
- goto error;
-
- if (!wpa_dbus_dict_string_array_add_element(&iter_array,
- "NONE"))
- goto error;
-
- if (!wpa_dbus_dict_string_array_add_element(&iter_array,
- "IEEE8021X"))
- goto error;
-
- if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "WPA-EAP"))
- goto error;
- }
-
- if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "WPA-PSK"))
- goto error;
- }
-
- if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "WPA-NONE"))
- goto error;
- }
-
- if (!wpa_dbus_dict_end_string_array(&iter_dict,
+ &iter_array) ||
+ !wpa_dbus_dict_string_array_add_element(&iter_array,
+ "NONE") ||
+ !wpa_dbus_dict_string_array_add_element(&iter_array,
+ "IEEE8021X") ||
+ ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "WPA-EAP")) ||
+ ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "WPA-PSK")) ||
+ ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "WPA-NONE")) ||
+ !wpa_dbus_dict_end_string_array(&iter_dict,
&iter_dict_entry,
&iter_dict_val,
&iter_array))
@@ -690,6 +625,7 @@
if (res < 0) {
if (!strict) {
const char *args[] = { "RSN", "WPA" };
+
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "proto", args,
ARRAY_SIZE(args)))
@@ -699,24 +635,16 @@
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "proto",
&iter_dict_entry,
&iter_dict_val,
- &iter_array))
- goto error;
-
- if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "RSN"))
- goto error;
- }
-
- if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "WPA"))
- goto error;
- }
-
- if (!wpa_dbus_dict_end_string_array(&iter_dict,
+ &iter_array) ||
+ ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "RSN")) ||
+ ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "WPA")) ||
+ !wpa_dbus_dict_end_string_array(&iter_dict,
&iter_dict_entry,
&iter_dict_val,
&iter_array))
@@ -727,6 +655,7 @@
if (res < 0) {
if (!strict) {
const char *args[] = { "OPEN", "SHARED", "LEAP" };
+
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "auth_alg", args,
ARRAY_SIZE(args)))
@@ -736,28 +665,17 @@
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "auth_alg",
&iter_dict_entry,
&iter_dict_val,
- &iter_array))
- goto error;
-
- if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "OPEN"))
- goto error;
- }
-
- if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "SHARED"))
- goto error;
- }
-
- if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) {
- if (!wpa_dbus_dict_string_array_add_element(
- &iter_array, "LEAP"))
- goto error;
- }
-
- if (!wpa_dbus_dict_end_string_array(&iter_dict,
+ &iter_array) ||
+ ((capa.auth & WPA_DRIVER_AUTH_OPEN) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "OPEN")) ||
+ ((capa.auth & WPA_DRIVER_AUTH_SHARED) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "SHARED")) ||
+ ((capa.auth & WPA_DRIVER_AUTH_LEAP) &&
+ !wpa_dbus_dict_string_array_add_element(
+ &iter_array, "LEAP")) ||
+ !wpa_dbus_dict_end_string_array(&iter_dict,
&iter_dict_entry,
&iter_dict_val,
&iter_array))
@@ -772,9 +690,9 @@
error:
if (reply)
dbus_message_unref(reply);
- return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR,
- "an internal error occurred returning "
- "interface capabilities.");
+ return dbus_message_new_error(
+ message, WPAS_ERROR_INTERNAL_ERROR,
+ "an internal error occurred returning interface capabilities.");
}
@@ -795,10 +713,9 @@
ssid = wpa_config_add_network(wpa_s->conf);
if (ssid == NULL) {
- reply = dbus_message_new_error(message,
- WPAS_ERROR_ADD_NETWORK_ERROR,
- "wpa_supplicant could not add "
- "a network on this interface.");
+ reply = dbus_message_new_error(
+ message, WPAS_ERROR_ADD_NETWORK_ERROR,
+ "wpa_supplicant could not add a network on this interface.");
goto out;
}
wpas_notify_network_added(wpa_s, ssid);
@@ -838,15 +755,15 @@
struct wpa_ssid *ssid;
if (!dbus_message_get_args(message, NULL,
- DBUS_TYPE_OBJECT_PATH, &op,
- DBUS_TYPE_INVALID)) {
+ DBUS_TYPE_OBJECT_PATH, &op,
+ DBUS_TYPE_INVALID)) {
reply = wpas_dbus_new_invalid_opts_error(message, NULL);
goto out;
}
/* Extract the network ID */
iface = wpas_dbus_decompose_object_path(op, &net_id, NULL);
- if (iface == NULL) {
+ if (iface == NULL || net_id == NULL) {
reply = wpas_dbus_new_invalid_network_error(message);
goto out;
}
@@ -866,17 +783,17 @@
wpas_notify_network_removed(wpa_s, ssid);
- if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
- reply = dbus_message_new_error(message,
- WPAS_ERROR_REMOVE_NETWORK_ERROR,
- "error removing the specified "
- "on this interface.");
- goto out;
- }
-
if (ssid == wpa_s->current_ssid)
wpa_supplicant_deauthenticate(wpa_s,
WLAN_REASON_DEAUTH_LEAVING);
+
+ if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
+ reply = dbus_message_new_error(
+ message, WPAS_ERROR_REMOVE_NETWORK_ERROR,
+ "error removing the specified on this interface.");
+ goto out;
+ }
+
reply = wpas_dbus_new_success_reply(message);
out:
@@ -886,7 +803,7 @@
}
-static const char *dont_quote[] = {
+static const char const *dont_quote[] = {
"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
"opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
"bssid", NULL
@@ -896,8 +813,9 @@
static dbus_bool_t should_quote_opt(const char *key)
{
int i = 0;
+
while (dont_quote[i] != NULL) {
- if (strcmp(key, dont_quote[i]) == 0)
+ if (os_strcmp(key, dont_quote[i]) == 0)
return FALSE;
i++;
}
@@ -968,7 +886,7 @@
goto error;
ret = os_snprintf(value, size, "\"%s\"",
entry.str_value);
- if (ret < 0 || (size_t) ret != (size - 1))
+ if (os_snprintf_error(size, ret))
goto error;
} else {
value = os_strdup(entry.str_value);
@@ -981,7 +899,7 @@
goto error;
ret = os_snprintf(value, size, "%u",
entry.uint32_value);
- if (ret <= 0)
+ if (os_snprintf_error(size, ret))
goto error;
} else if (entry.type == DBUS_TYPE_INT32) {
value = os_zalloc(size);
@@ -989,7 +907,7 @@
goto error;
ret = os_snprintf(value, size, "%d",
entry.int32_value);
- if (ret <= 0)
+ if (os_snprintf_error(size, ret))
goto error;
} else
goto error;
@@ -1102,7 +1020,8 @@
goto out;
}
/* Ensure the object path really points to this interface */
- if (os_strcmp(iface_obj_path, wpa_s->dbus_path) != 0) {
+ if (network == NULL ||
+ os_strcmp(iface_obj_path, wpa_s->dbus_path) != 0) {
reply = wpas_dbus_new_invalid_network_error(message);
goto out;
}
@@ -1212,28 +1131,30 @@
if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
goto error;
if (!strcmp(entry.key, "opensc_engine_path") &&
- (entry.type == DBUS_TYPE_STRING)) {
+ entry.type == DBUS_TYPE_STRING) {
os_free(opensc_engine_path);
opensc_engine_path = os_strdup(entry.str_value);
+ wpa_dbus_dict_entry_clear(&entry);
if (opensc_engine_path == NULL)
goto error;
} else if (!strcmp(entry.key, "pkcs11_engine_path") &&
- (entry.type == DBUS_TYPE_STRING)) {
+ entry.type == DBUS_TYPE_STRING) {
os_free(pkcs11_engine_path);
pkcs11_engine_path = os_strdup(entry.str_value);
+ wpa_dbus_dict_entry_clear(&entry);
if (pkcs11_engine_path == NULL)
goto error;
} else if (!strcmp(entry.key, "pkcs11_module_path") &&
- (entry.type == DBUS_TYPE_STRING)) {
+ entry.type == DBUS_TYPE_STRING) {
os_free(pkcs11_module_path);
pkcs11_module_path = os_strdup(entry.str_value);
+ wpa_dbus_dict_entry_clear(&entry);
if (pkcs11_module_path == NULL)
goto error;
} else {
wpa_dbus_dict_entry_clear(&entry);
goto error;
}
- wpa_dbus_dict_entry_clear(&entry);
}
os_free(wpa_s->conf->opensc_engine_path);
@@ -1304,8 +1225,8 @@
dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &scanning,
DBUS_TYPE_INVALID);
} else {
- wpa_printf(MSG_ERROR, "dbus: Not enough memory to return "
- "scanning state");
+ wpa_printf(MSG_ERROR,
+ "dbus: Not enough memory to return scanning state");
}
return reply;
@@ -1378,7 +1299,7 @@
blob->len = entry.array_len;
os_memcpy(blob->data, (u8 *) entry.bytearray_value,
entry.array_len);
- if (blob->name == NULL || blob->data == NULL) {
+ if (blob->name == NULL) {
wpa_config_free_blob(blob);
reply = dbus_message_new_error(
message, WPAS_ERROR_ADD_ERROR,
@@ -1417,8 +1338,8 @@
dbus_message_iter_init(message, &iter);
- if ((dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY) ||
- (dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_STRING))
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
+ dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
return wpas_dbus_new_invalid_opts_error(message, NULL);
dbus_message_iter_recurse(&iter, &array);
@@ -1428,8 +1349,7 @@
dbus_message_iter_get_basic(&array, &name);
if (!os_strlen(name))
err_msg = "Invalid blob name.";
-
- if (wpa_config_remove_blob(wpa_s->conf, name) != 0)
+ else if (wpa_config_remove_blob(wpa_s->conf, name) != 0)
err_msg = "Error removing blob.";
else
wpas_notify_blob_removed(wpa_s, name);
diff --git a/wpa_supplicant/dbus/dbus_old_handlers.h b/wpa_supplicant/dbus/dbus_old_handlers.h
index 825bc6d..e60ad06 100644
--- a/wpa_supplicant/dbus/dbus_old_handlers.h
+++ b/wpa_supplicant/dbus/dbus_old_handlers.h
@@ -58,13 +58,13 @@
struct wpa_ssid *ssid);
DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
+ struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message,
struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
+ struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_iface_set_smartcard_modules(
DBusMessage *message, struct wpa_supplicant *wpa_s);
@@ -76,7 +76,7 @@
struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message,
- struct wpa_supplicant *wpa_s);
+ struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message,
struct wpa_supplicant *wpa_s);
diff --git a/wpa_supplicant/dbus/dbus_old_handlers_wps.c b/wpa_supplicant/dbus/dbus_old_handlers_wps.c
index bb79382..5309a53 100644
--- a/wpa_supplicant/dbus/dbus_old_handlers_wps.c
+++ b/wpa_supplicant/dbus/dbus_old_handlers_wps.c
@@ -36,7 +36,7 @@
DBUS_TYPE_INVALID))
return wpas_dbus_new_invalid_opts_error(message, NULL);
- if (!os_strcmp(arg_bssid, "any"))
+ if (os_strcmp(arg_bssid, "any") == 0)
ret = wpas_wps_start_pbc(wpa_s, NULL, 0);
else if (!hwaddr_aton(arg_bssid, bssid))
ret = wpas_wps_start_pbc(wpa_s, bssid, 0);
@@ -46,10 +46,9 @@
}
if (ret < 0) {
- return dbus_message_new_error(message,
- WPAS_ERROR_WPS_PBC_ERROR,
- "Could not start PBC "
- "negotiation");
+ return dbus_message_new_error(
+ message, WPAS_ERROR_WPS_PBC_ERROR,
+ "Could not start PBC negotiation");
}
return wpas_dbus_new_success_reply(message);
@@ -73,12 +72,13 @@
char *pin = NULL;
u8 bssid[ETH_ALEN], *_bssid = NULL;
int ret = 0;
+ char npin[9];
if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg_bssid,
DBUS_TYPE_STRING, &pin, DBUS_TYPE_INVALID))
return wpas_dbus_new_invalid_opts_error(message, NULL);
- if (!os_strcmp(arg_bssid, "any"))
+ if (os_strcmp(arg_bssid, "any") == 0)
_bssid = NULL;
else if (!hwaddr_aton(arg_bssid, bssid))
_bssid = bssid;
@@ -104,15 +104,12 @@
if (reply == NULL)
return NULL;
- if (ret == 0) {
- dbus_message_append_args(reply, DBUS_TYPE_STRING, &pin,
- DBUS_TYPE_INVALID);
- } else {
- char npin[9];
+ if (ret > 0) {
os_snprintf(npin, sizeof(npin), "%08d", ret);
- dbus_message_append_args(reply, DBUS_TYPE_STRING, &npin,
- DBUS_TYPE_INVALID);
+ pin = npin;
}
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &pin,
+ DBUS_TYPE_INVALID);
return reply;
}
@@ -138,9 +135,7 @@
DBUS_TYPE_STRING, &pin, DBUS_TYPE_INVALID))
return wpas_dbus_new_invalid_opts_error(message, NULL);
- if (!os_strcmp(arg_bssid, "any"))
- ret = wpas_wps_start_reg(wpa_s, NULL, pin, NULL);
- else if (!hwaddr_aton(arg_bssid, bssid))
+ if (!hwaddr_aton(arg_bssid, bssid))
ret = wpas_wps_start_reg(wpa_s, bssid, pin, NULL);
else {
return wpas_dbus_new_invalid_opts_error(message,
@@ -149,7 +144,7 @@
if (ret < 0) {
return dbus_message_new_error(message,
- WPAS_ERROR_WPS_PBC_ERROR,
+ WPAS_ERROR_WPS_REG_ERROR,
"Could not request credentials");
}
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index 94c94b1..7f627fd 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -67,9 +67,6 @@
# wpa_supplicant.
# CONFIG_USE_NDISUIO=y
-# Driver interface for development testing
-#CONFIG_DRIVER_TEST=y
-
# Driver interface for wired Ethernet drivers
CONFIG_DRIVER_WIRED=y
diff --git a/wpa_supplicant/doc/docbook/eapol_test.sgml b/wpa_supplicant/doc/docbook/eapol_test.sgml
index fec174b..e9af6d9 100644
--- a/wpa_supplicant/doc/docbook/eapol_test.sgml
+++ b/wpa_supplicant/doc/docbook/eapol_test.sgml
@@ -194,7 +194,7 @@
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2014,
+ <para>wpa_supplicant is copyright (c) 2003-2015,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_background.sgml b/wpa_supplicant/doc/docbook/wpa_background.sgml
index 860b5a0..afb8c3b 100644
--- a/wpa_supplicant/doc/docbook/wpa_background.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_background.sgml
@@ -90,7 +90,7 @@
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2014,
+ <para>wpa_supplicant is copyright (c) 2003-2015,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_cli.sgml b/wpa_supplicant/doc/docbook/wpa_cli.sgml
index 142e1ab..47947c1 100644
--- a/wpa_supplicant/doc/docbook/wpa_cli.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_cli.sgml
@@ -345,7 +345,7 @@
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2014,
+ <para>wpa_supplicant is copyright (c) 2003-2015,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_gui.sgml b/wpa_supplicant/doc/docbook/wpa_gui.sgml
index f6ef8f1..84766db 100644
--- a/wpa_supplicant/doc/docbook/wpa_gui.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_gui.sgml
@@ -74,7 +74,7 @@
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2014,
+ <para>wpa_supplicant is copyright (c) 2003-2015,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_passphrase.sgml b/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
index 3b4360b..b381e40 100644
--- a/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
@@ -62,7 +62,7 @@
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2014,
+ <para>wpa_supplicant is copyright (c) 2003-2015,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_priv.sgml b/wpa_supplicant/doc/docbook/wpa_priv.sgml
index 9c114cc..d13a5db 100644
--- a/wpa_supplicant/doc/docbook/wpa_priv.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_priv.sgml
@@ -137,7 +137,7 @@
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2014,
+ <para>wpa_supplicant is copyright (c) 2003-2015,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
diff --git a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
index 182060d..46c21b5 100644
--- a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
@@ -469,7 +469,7 @@
<para>Enable DBus control interface. If enabled, interface
definitions may be omitted. (This is only available
if <command>wpa_supplicant</command> was built with
- the <literal>CONFIG_DBUS</literal> option.)</para>0
+ the <literal>CONFIG_DBUS</literal> option.)</para>
</listitem>
</varlistentry>
@@ -736,7 +736,7 @@
</refsect1>
<refsect1>
<title>Legal</title>
- <para>wpa_supplicant is copyright (c) 2003-2014,
+ <para>wpa_supplicant is copyright (c) 2003-2015,
Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 649de9b..65b430d 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -1,6 +1,6 @@
/*
* wpa_supplicant - Internal driver interface wrappers
- * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -65,9 +65,35 @@
return -1;
}
+static inline int wpa_drv_init_mesh(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->driver->init_mesh)
+ return wpa_s->driver->init_mesh(wpa_s->drv_priv);
+ return -1;
+}
+
+static inline int wpa_drv_join_mesh(struct wpa_supplicant *wpa_s,
+ struct wpa_driver_mesh_join_params *params)
+{
+ if (wpa_s->driver->join_mesh)
+ return wpa_s->driver->join_mesh(wpa_s->drv_priv, params);
+ return -1;
+}
+
+static inline int wpa_drv_leave_mesh(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->driver->leave_mesh)
+ return wpa_s->driver->leave_mesh(wpa_s->drv_priv);
+ return -1;
+}
+
static inline int wpa_drv_scan(struct wpa_supplicant *wpa_s,
struct wpa_driver_scan_params *params)
{
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->test_failure == WPAS_TEST_FAILURE_SCAN_TRIGGER)
+ return -EBUSY;
+#endif /* CONFIG_TESTING_OPTIONS */
if (wpa_s->driver->scan2)
return wpa_s->driver->scan2(wpa_s->drv_priv, params);
return -1;
@@ -222,16 +248,6 @@
return NULL;
}
-static inline int wpa_drv_send_eapol(struct wpa_supplicant *wpa_s,
- const u8 *dst, u16 proto,
- const u8 *data, size_t data_len)
-{
- if (wpa_s->driver->send_eapol)
- return wpa_s->driver->send_eapol(wpa_s->drv_priv, dst, proto,
- data, data_len);
- return -1;
-}
-
static inline int wpa_drv_set_operstate(struct wpa_supplicant *wpa_s,
int state)
{
@@ -288,16 +304,6 @@
return -1;
}
-static inline int wpa_drv_send_ft_action(struct wpa_supplicant *wpa_s,
- u8 action, const u8 *target_ap,
- const u8 *ies, size_t ies_len)
-{
- if (wpa_s->driver->send_ft_action)
- return wpa_s->driver->send_ft_action(wpa_s->drv_priv, action,
- target_ap, ies, ies_len);
- return -1;
-}
-
static inline int wpa_drv_set_ap(struct wpa_supplicant *wpa_s,
struct wpa_driver_ap_params *params)
{
@@ -563,12 +569,14 @@
#endif /* ANDROID */
static inline void wpa_drv_set_rekey_info(struct wpa_supplicant *wpa_s,
- const u8 *kek, const u8 *kck,
+ const u8 *kek, size_t kek_len,
+ const u8 *kck, size_t kck_len,
const u8 *replay_ctr)
{
if (!wpa_s->driver->set_rekey_info)
return;
- wpa_s->driver->set_rekey_info(wpa_s->drv_priv, kek, kck, replay_ctr);
+ wpa_s->driver->set_rekey_info(wpa_s->drv_priv, kek, kek_len,
+ kck, kck_len, replay_ctr);
}
static inline int wpa_drv_radio_disable(struct wpa_supplicant *wpa_s,
@@ -587,6 +595,45 @@
return wpa_s->driver->switch_channel(wpa_s->drv_priv, settings);
}
+static inline int wpa_drv_add_ts(struct wpa_supplicant *wpa_s, u8 tsid,
+ const u8 *address, u8 user_priority,
+ u16 admitted_time)
+{
+ if (!wpa_s->driver->add_tx_ts)
+ return -1;
+ return wpa_s->driver->add_tx_ts(wpa_s->drv_priv, tsid, address,
+ user_priority, admitted_time);
+}
+
+static inline int wpa_drv_del_ts(struct wpa_supplicant *wpa_s, u8 tid,
+ const u8 *address)
+{
+ if (!wpa_s->driver->del_tx_ts)
+ return -1;
+ return wpa_s->driver->del_tx_ts(wpa_s->drv_priv, tid, address);
+}
+
+static inline int wpa_drv_tdls_enable_channel_switch(
+ struct wpa_supplicant *wpa_s, const u8 *addr, u8 oper_class,
+ const struct hostapd_freq_params *freq_params)
+{
+ if (!wpa_s->driver->tdls_enable_channel_switch)
+ return -1;
+ return wpa_s->driver->tdls_enable_channel_switch(wpa_s->drv_priv, addr,
+ oper_class,
+ freq_params);
+}
+
+static inline int
+wpa_drv_tdls_disable_channel_switch(struct wpa_supplicant *wpa_s,
+ const u8 *addr)
+{
+ if (!wpa_s->driver->tdls_disable_channel_switch)
+ return -1;
+ return wpa_s->driver->tdls_disable_channel_switch(wpa_s->drv_priv,
+ addr);
+}
+
static inline int wpa_drv_wnm_oper(struct wpa_supplicant *wpa_s,
enum wnm_oper oper, const u8 *peer,
u8 *buf, u16 *buf_len)
diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c
index e19782f..9b7af30 100644
--- a/wpa_supplicant/eapol_test.c
+++ b/wpa_supplicant/eapol_test.c
@@ -461,7 +461,7 @@
len = os_snprintf(buf, buflen,
WPA_CTRL_REQ "%s-%d:%s needed for SSID ",
field_name, ssid->id, txt);
- if (len < 0 || (size_t) len >= buflen) {
+ if (os_snprintf_error(buflen, len)) {
os_free(buf);
return;
}
@@ -480,6 +480,7 @@
static void eapol_test_cert_cb(void *ctx, int depth, const char *subject,
+ const char *altsubject[], int num_altsubject,
const char *cert_hash,
const struct wpabuf *cert)
{
@@ -509,6 +510,14 @@
eapol_test_write_cert(e->server_cert_file,
subject, cert);
}
+
+ if (altsubject) {
+ int i;
+
+ for (i = 0; i < num_altsubject; i++)
+ wpa_msg(e->wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_ALT
+ "depth=%d %s", depth, altsubject[i]);
+ }
}
@@ -568,6 +577,7 @@
ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path;
ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
+ ctx->openssl_ciphers = wpa_s->conf->openssl_ciphers;
ctx->eap_param_needed = eapol_test_eap_param_needed;
ctx->cert_cb = eapol_test_cert_cb;
ctx->cert_in_cb = 1;
@@ -928,7 +938,11 @@
*pos++ = a[3];
}
#else /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
- inet_aton(authsrv, &as->addr.u.v4);
+ if (inet_aton(authsrv, &as->addr.u.v4) < 0) {
+ wpa_printf(MSG_ERROR, "Invalid IP address '%s'",
+ authsrv);
+ assert(0);
+ }
#endif /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
as->addr.af = AF_INET;
as->port = port;
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 985fa6e..f1f8864 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - Driver event processing
- * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -42,6 +42,9 @@
#include "scan.h"
#include "offchannel.h"
#include "interworking.h"
+#include "mesh.h"
+#include "mesh_mpm.h"
+#include "wmm_ac.h"
#ifndef CONFIG_NO_SCAN_PROCESSING
@@ -199,20 +202,12 @@
bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
os_memset(wpa_s->bssid, 0, ETH_ALEN);
os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
-#ifdef CONFIG_SME
- wpa_s->sme.prev_bssid_set = 0;
-#endif /* CONFIG_SME */
+ sme_clear_on_disassoc(wpa_s);
#ifdef CONFIG_P2P
os_memset(wpa_s->go_dev_addr, 0, ETH_ALEN);
#endif /* CONFIG_P2P */
wpa_s->current_bss = NULL;
wpa_s->assoc_freq = 0;
-#ifdef CONFIG_IEEE80211R
-#ifdef CONFIG_SME
- if (wpa_s->sme.ft_ies)
- sme_update_ft_ies(wpa_s, NULL, NULL, 0);
-#endif /* CONFIG_SME */
-#endif /* CONFIG_IEEE80211R */
if (bssid_changed)
wpas_notify_bssid_changed(wpa_s);
@@ -225,6 +220,8 @@
wpa_s->current_ssid = NULL;
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
wpa_s->key_mgmt = 0;
+
+ wpas_rrm_reset(wpa_s);
}
@@ -479,8 +476,7 @@
#ifdef CONFIG_IEEE80211W
if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
- (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
- wpa_s->conf->pmf : ssid->ieee80211w) ==
+ wpas_get_ssid_pmf(wpa_s, ssid) ==
MGMT_FRAME_PROTECTION_REQUIRED) {
wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - no mgmt "
"frame protection");
@@ -582,42 +578,6 @@
}
-int ht_supported(const struct hostapd_hw_modes *mode)
-{
- if (!(mode->flags & HOSTAPD_MODE_FLAG_HT_INFO_KNOWN)) {
- /*
- * The driver did not indicate whether it supports HT. Assume
- * it does to avoid connection issues.
- */
- return 1;
- }
-
- /*
- * IEEE Std 802.11n-2009 20.1.1:
- * An HT non-AP STA shall support all EQM rates for one spatial stream.
- */
- return mode->mcs_set[0] == 0xff;
-}
-
-
-int vht_supported(const struct hostapd_hw_modes *mode)
-{
- if (!(mode->flags & HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN)) {
- /*
- * The driver did not indicate whether it supports VHT. Assume
- * it does to avoid connection issues.
- */
- return 1;
- }
-
- /*
- * A VHT non-AP STA shall support MCS 0-7 for one spatial stream.
- * TODO: Verify if this complies with the standard
- */
- return (mode->vht_mcs_set[0] & 0x3) != 3;
-}
-
-
static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
{
const struct hostapd_hw_modes *mode = NULL, *modes;
@@ -737,6 +697,33 @@
}
+static int match_mac_mask(const u8 *addr_a, const u8 *addr_b, const u8 *mask)
+{
+ size_t i;
+
+ for (i = 0; i < ETH_ALEN; i++) {
+ if ((addr_a[i] & mask[i]) != (addr_b[i] & mask[i]))
+ return 0;
+ }
+ return 1;
+}
+
+
+static int addr_in_list(const u8 *addr, const u8 *list, size_t num)
+{
+ size_t i;
+
+ for (i = 0; i < num; i++) {
+ const u8 *a = list + i * ETH_ALEN * 2;
+ const u8 *m = a + ETH_ALEN;
+
+ if (match_mac_mask(a, addr, m))
+ return 1;
+ }
+ return 0;
+}
+
+
static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
int i, struct wpa_bss *bss,
struct wpa_ssid *group,
@@ -861,6 +848,24 @@
continue;
}
+ /* check blacklist */
+ if (ssid->num_bssid_blacklist &&
+ addr_in_list(bss->bssid, ssid->bssid_blacklist,
+ ssid->num_bssid_blacklist)) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - BSSID blacklisted");
+ continue;
+ }
+
+ /* if there is a whitelist, only accept those APs */
+ if (ssid->num_bssid_whitelist &&
+ !addr_in_list(bss->bssid, ssid->bssid_whitelist,
+ ssid->num_bssid_whitelist)) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - BSSID not in whitelist");
+ continue;
+ }
+
if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss))
continue;
@@ -1136,7 +1141,8 @@
if (wpas_network_disabled(wpa_s, ssid))
continue;
if (ssid->mode == IEEE80211_MODE_IBSS ||
- ssid->mode == IEEE80211_MODE_AP)
+ ssid->mode == IEEE80211_MODE_AP ||
+ ssid->mode == IEEE80211_MODE_MESH)
return ssid;
}
}
@@ -1306,7 +1312,7 @@
#endif /* CONFIG_NO_RANDOM_POOL */
if (own_request && wpa_s->scan_res_handler &&
- (wpa_s->own_scan_running || !wpa_s->external_scan_running)) {
+ (wpa_s->own_scan_running || !wpa_s->radio->external_scan_running)) {
void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res);
@@ -1327,7 +1333,7 @@
}
wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available (own=%u ext=%u)",
- wpa_s->own_scan_running, wpa_s->external_scan_running);
+ wpa_s->own_scan_running, wpa_s->radio->external_scan_running);
if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
wpa_s->manual_scan_use_id && wpa_s->own_scan_running) {
wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS "id=%u",
@@ -1340,12 +1346,15 @@
wpas_notify_scan_done(wpa_s, 1);
- if (!wpa_s->own_scan_running && wpa_s->external_scan_running) {
+ if (!wpa_s->own_scan_running && wpa_s->radio->external_scan_running) {
wpa_dbg(wpa_s, MSG_DEBUG, "Do not use results from externally requested scan operation for network selection");
wpa_scan_results_free(scan_res);
return 0;
}
+ if (wnm_scan_process(wpa_s, 1) > 0)
+ goto scan_work_done;
+
if (sme_proc_obss_scan(wpa_s) > 0)
goto scan_work_done;
@@ -1416,6 +1425,13 @@
*/
return 1;
} else {
+#ifdef CONFIG_MESH
+ if (wpa_s->ifmsh) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Avoiding join because we already joined a mesh group");
+ return 0;
+ }
+#endif /* CONFIG_MESH */
wpa_dbg(wpa_s, MSG_DEBUG, "No suitable network found");
ssid = wpa_supplicant_pick_new_network(wpa_s);
if (ssid) {
@@ -2067,6 +2083,15 @@
#endif /* CONFIG_IBSS_RSN */
wpas_wps_notify_assoc(wpa_s, bssid);
+
+ if (data) {
+ wmm_ac_notify_assoc(wpa_s, data->assoc_info.resp_ies,
+ data->assoc_info.resp_ies_len,
+ &data->assoc_info.wmm_params);
+
+ if (wpa_s->reassoc_same_bss)
+ wmm_ac_restore_tspecs(wpa_s);
+ }
}
@@ -2801,7 +2826,8 @@
static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s,
- const u8 *frame, size_t len, int freq)
+ const u8 *frame, size_t len, int freq,
+ int rssi)
{
const struct ieee80211_mgmt *mgmt;
const u8 *payload;
@@ -2820,6 +2846,11 @@
" Category=%u DataLen=%d freq=%d MHz",
MAC2STR(mgmt->sa), category, (int) plen, freq);
+ if (category == WLAN_ACTION_WMM) {
+ wmm_ac_rx_action(wpa_s, mgmt->da, mgmt->sa, payload, plen);
+ return;
+ }
+
#ifdef CONFIG_IEEE80211R
if (category == WLAN_ACTION_FT) {
ft_rx_action(wpa_s, payload, plen);
@@ -2877,8 +2908,24 @@
}
#endif /* CONFIG_INTERWORKING */
+ if (category == WLAN_ACTION_RADIO_MEASUREMENT &&
+ payload[0] == WLAN_RRM_NEIGHBOR_REPORT_RESPONSE) {
+ wpas_rrm_process_neighbor_rep(wpa_s, payload + 1, plen - 1);
+ return;
+ }
+
+ if (category == WLAN_ACTION_RADIO_MEASUREMENT &&
+ payload[0] == WLAN_RRM_LINK_MEASUREMENT_REQUEST) {
+ wpas_rrm_handle_link_measurement_request(wpa_s, mgmt->sa,
+ payload + 1, plen - 1,
+ rssi);
+ return;
+ }
+
wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid,
category, payload, plen, freq);
+ if (wpa_s->ifmsh)
+ mesh_mpm_action_rx(wpa_s, mgmt, len);
}
@@ -2934,6 +2981,26 @@
}
+static void wpa_supplicant_event_assoc_auth(struct wpa_supplicant *wpa_s,
+ union wpa_event_data *data)
+{
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Connection authorized by device, previous state %d",
+ wpa_s->wpa_state);
+ if (wpa_s->wpa_state == WPA_ASSOCIATED) {
+ wpa_supplicant_cancel_auth_timeout(wpa_s);
+ wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+ eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
+ eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
+ }
+ wpa_sm_set_rx_replay_ctr(wpa_s->wpa, data->assoc_info.key_replay_ctr);
+ wpa_sm_set_ptk_kck_kek(wpa_s->wpa, data->assoc_info.ptk_kck,
+ data->assoc_info.ptk_kck_len,
+ data->assoc_info.ptk_kek,
+ data->assoc_info.ptk_kek_len);
+}
+
+
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data)
{
@@ -2974,6 +3041,8 @@
break;
case EVENT_ASSOC:
wpa_supplicant_event_assoc(wpa_s, data);
+ if (data && data->assoc_info.authorized)
+ wpa_supplicant_event_assoc_auth(wpa_s, data);
break;
case EVENT_DISASSOC:
wpas_event_disassoc(wpa_s,
@@ -3009,7 +3078,7 @@
}
} else {
wpa_dbg(wpa_s, MSG_DEBUG, "External program started a scan");
- wpa_s->external_scan_running = 1;
+ wpa_s->radio->external_scan_running = 1;
wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_STARTED);
}
break;
@@ -3025,7 +3094,7 @@
}
wpa_supplicant_event_scan_results(wpa_s, data);
wpa_s->own_scan_running = 0;
- wpa_s->external_scan_running = 0;
+ wpa_s->radio->external_scan_running = 0;
radio_work_check_next(wpa_s);
break;
#endif /* CONFIG_NO_SCAN_PROCESSING */
@@ -3084,10 +3153,24 @@
}
break;
case EVENT_AUTH_TIMED_OUT:
+ /* It is possible to get this event from earlier connection */
+ if (wpa_s->current_ssid &&
+ wpa_s->current_ssid->mode == WPAS_MODE_MESH) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Ignore AUTH_TIMED_OUT in mesh configuration");
+ break;
+ }
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
sme_event_auth_timed_out(wpa_s, data);
break;
case EVENT_ASSOC_TIMED_OUT:
+ /* It is possible to get this event from earlier connection */
+ if (wpa_s->current_ssid &&
+ wpa_s->current_ssid->mode == WPAS_MODE_MESH) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Ignore ASSOC_TIMED_OUT in mesh configuration");
+ break;
+ }
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
sme_event_assoc_timed_out(wpa_s, data);
break;
@@ -3228,7 +3311,9 @@
}
#endif /* CONFIG_P2P */
#ifdef CONFIG_IBSS_RSN
- if (stype == WLAN_FC_STYPE_AUTH &&
+ if (wpa_s->current_ssid &&
+ wpa_s->current_ssid->mode == WPAS_MODE_IBSS &&
+ stype == WLAN_FC_STYPE_AUTH &&
data->rx_mgmt.frame_len >= 30) {
wpa_supplicant_event_ibss_auth(wpa_s, data);
break;
@@ -3239,7 +3324,13 @@
wpas_event_rx_mgmt_action(
wpa_s, data->rx_mgmt.frame,
data->rx_mgmt.frame_len,
- data->rx_mgmt.freq);
+ data->rx_mgmt.freq,
+ data->rx_mgmt.ssi_signal);
+ break;
+ }
+
+ if (wpa_s->ifmsh) {
+ mesh_mpm_mgmt_rx(wpa_s, &data->rx_mgmt);
break;
}
@@ -3338,6 +3429,7 @@
if (!wpa_s->ap_iface) {
wpa_supplicant_set_state(wpa_s,
WPA_DISCONNECTED);
+ wpa_s->scan_req = NORMAL_SCAN_REQ;
wpa_supplicant_req_scan(wpa_s, 0, 0);
} else
wpa_supplicant_set_state(wpa_s,
@@ -3355,11 +3447,24 @@
(wpa_s->current_ssid && wpa_s->current_ssid->p2p_group &&
wpa_s->current_ssid->mode == WPAS_MODE_P2P_GO)) {
/*
+ * Mark interface disabled if this happens to end up not
+ * being removed as a separate P2P group interface.
+ */
+ wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED);
+ /*
* The interface was externally disabled. Remove
* it assuming an external entity will start a
* new session if needed.
*/
- wpas_p2p_disconnect(wpa_s);
+ if (wpa_s->current_ssid &&
+ wpa_s->current_ssid->p2p_group)
+ wpas_p2p_interface_unavailable(wpa_s);
+ else
+ wpas_p2p_disconnect(wpa_s);
+ /*
+ * wpa_s instance may have been freed, so must not use
+ * it here anymore.
+ */
break;
}
if (wpa_s->p2p_scan_work && wpa_s->global->p2p &&
@@ -3475,6 +3580,15 @@
data->connect_failed_reason.code);
#endif /* CONFIG_AP */
break;
+ case EVENT_NEW_PEER_CANDIDATE:
+#ifdef CONFIG_MESH
+ if (!wpa_s->ifmsh || !data)
+ break;
+ wpa_mesh_notify_peer(wpa_s, data->mesh_peer.peer,
+ data->mesh_peer.ies,
+ data->mesh_peer.ie_len);
+#endif /* CONFIG_MESH */
+ break;
default:
wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event);
break;
diff --git a/wpa_supplicant/examples/wps-ap-cli b/wpa_supplicant/examples/wps-ap-cli
index 7c6b0aa..cc2cff2 100755
--- a/wpa_supplicant/examples/wps-ap-cli
+++ b/wpa_supplicant/examples/wps-ap-cli
@@ -14,11 +14,13 @@
enter_pin()
{
echo "Enter a PIN from a station to be enrolled to the network."
- read -p "Enrollee PIN: " pin
+ echo -n "Enrollee PIN: "
+ read pin
cpin=`$CLI wps_check_pin "$pin" | tail -1`
if [ "$cpin" = "FAIL-CHECKSUM" ]; then
echo "Checksum digit is not valid"
- read -p "Do you want to use this PIN (y/n)? " resp
+ echo -n "Do you want to use this PIN (y/n)? "
+ read resp
case "$resp" in
y*)
cpin=`echo "$pin" | sed "s/[^1234567890]//g"`
@@ -50,7 +52,8 @@
echo "3: Show current configuration"
echo "0: Exit wps-ap-cli"
- read -p "Command: " cmd
+ echo -n "Command: "
+ read cmd
case "$cmd" in
1)
diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c
index 3a89674..10ecce7 100644
--- a/wpa_supplicant/gas_query.c
+++ b/wpa_supplicant/gas_query.c
@@ -442,6 +442,7 @@
u16 comeback_delay, resp_len;
const u8 *pos, *adv_proto;
int prot, pmf;
+ unsigned int left;
if (gas == NULL || len < 4)
return -1;
@@ -543,17 +544,17 @@
resp_len = WPA_GET_LE16(pos);
pos += 2;
- if (pos + resp_len > data + len) {
+ left = data + len - pos;
+ if (resp_len > left) {
wpa_printf(MSG_DEBUG, "GAS: Truncated Query Response in "
"response from " MACSTR, MAC2STR(sa));
return 0;
}
- if (pos + resp_len < data + len) {
+ if (resp_len < left) {
wpa_printf(MSG_DEBUG, "GAS: Ignore %u octets of extra data "
"after Query Response from " MACSTR,
- (unsigned int) (data + len - pos - resp_len),
- MAC2STR(sa));
+ left - resp_len, MAC2STR(sa));
}
if (action == WLAN_PA_GAS_COMEBACK_RESP)
diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c
index 257aa6d..eb18ed2 100644
--- a/wpa_supplicant/hs20_supplicant.c
+++ b/wpa_supplicant/hs20_supplicant.c
@@ -7,6 +7,7 @@
*/
#include "includes.h"
+#include <sys/stat.h>
#include "common.h"
#include "eloop.h"
@@ -216,6 +217,30 @@
}
+static void hs20_set_osu_access_permission(const char *osu_dir,
+ const char *fname)
+{
+ struct stat statbuf;
+
+ /* Get OSU directory information */
+ if (stat(osu_dir, &statbuf) < 0) {
+ wpa_printf(MSG_WARNING, "Cannot stat the OSU directory %s",
+ osu_dir);
+ return;
+ }
+
+ if (chmod(fname, statbuf.st_mode) < 0) {
+ wpa_printf(MSG_WARNING,
+ "Cannot change the permissions for %s", fname);
+ return;
+ }
+
+ if (chown(fname, statbuf.st_uid, statbuf.st_gid) < 0) {
+ wpa_printf(MSG_WARNING, "Cannot change the ownership for %s",
+ fname);
+ }
+}
+
static int hs20_process_icon_binary_file(struct wpa_supplicant *wpa_s,
const u8 *sa, const u8 *pos,
size_t slen)
@@ -278,6 +303,9 @@
f = fopen(fname, "wb");
if (f == NULL)
return -1;
+
+ hs20_set_osu_access_permission(wpa_s->conf->osu_dir, fname);
+
if (fwrite(pos, slen, 1, f) != 1) {
fclose(f);
unlink(fname);
@@ -327,11 +355,11 @@
void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
- const u8 *sa, const u8 *data, size_t slen)
+ struct wpa_bss *bss, const u8 *sa,
+ const u8 *data, size_t slen)
{
const u8 *pos = data;
u8 subtype;
- struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa);
struct wpa_bss_anqp *anqp = NULL;
int ret;
@@ -479,6 +507,9 @@
hs20_free_osu_prov(wpa_s);
return;
}
+
+ hs20_set_osu_access_permission(wpa_s->conf->osu_dir, fname);
+
for (i = 0; i < wpa_s->osu_prov_count; i++) {
struct osu_provider *osu = &wpa_s->osu_prov[i];
if (i > 0)
@@ -562,6 +593,7 @@
const u8 *end = pos + len;
u16 len2;
const u8 *pos2;
+ u8 uri_len, osu_method_len, osu_nai_len;
wpa_hexdump(MSG_DEBUG, "HS 2.0: Parsing OSU Provider", pos, len);
prov = os_realloc_array(wpa_s->osu_prov,
@@ -585,7 +617,7 @@
}
len2 = WPA_GET_LE16(pos);
pos += 2;
- if (pos + len2 > end) {
+ if (len2 > end - pos) {
wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU "
"Friendly Name Duples");
return;
@@ -607,22 +639,34 @@
}
/* OSU Server URI */
- if (pos + 1 > end || pos + 1 + pos[0] > end) {
+ if (pos + 1 > end) {
+ wpa_printf(MSG_DEBUG,
+ "HS 2.0: Not enough room for OSU Server URI length");
+ return;
+ }
+ uri_len = *pos++;
+ if (uri_len > end - pos) {
wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU Server "
"URI");
return;
}
- os_memcpy(prov->server_uri, pos + 1, pos[0]);
- pos += 1 + pos[0];
+ os_memcpy(prov->server_uri, pos, uri_len);
+ pos += uri_len;
/* OSU Method list */
- if (pos + 1 > end || pos + 1 + pos[0] > end) {
+ if (pos + 1 > end) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU Method "
+ "list length");
+ return;
+ }
+ osu_method_len = pos[0];
+ if (osu_method_len > end - pos - 1) {
wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU Method "
"list");
return;
}
pos2 = pos + 1;
- pos += 1 + pos[0];
+ pos += 1 + osu_method_len;
while (pos2 < pos) {
if (*pos2 < 32)
prov->osu_methods |= BIT(*pos2);
@@ -637,7 +681,7 @@
}
len2 = WPA_GET_LE16(pos);
pos += 2;
- if (pos + len2 > end) {
+ if (len2 > end - pos) {
wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for Icons "
"Available");
return;
@@ -648,6 +692,8 @@
/* Icons Available */
while (pos2 < pos) {
struct osu_icon *icon = &prov->icon[prov->icon_count];
+ u8 flen;
+
if (pos2 + 2 + 2 + 3 + 1 + 1 > pos) {
wpa_printf(MSG_DEBUG, "HS 2.0: Invalid Icon Metadata");
break;
@@ -660,31 +706,43 @@
os_memcpy(icon->lang, pos2, 3);
pos2 += 3;
- if (pos2 + 1 + pos2[0] > pos) {
+ flen = pos2[0];
+ if (flen > pos - pos2 - 1) {
wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon Type");
break;
}
- os_memcpy(icon->icon_type, pos2 + 1, pos2[0]);
- pos2 += 1 + pos2[0];
+ os_memcpy(icon->icon_type, pos2 + 1, flen);
+ pos2 += 1 + flen;
- if (pos2 + 1 + pos2[0] > pos) {
+ if (pos2 + 1 > pos) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon "
+ "Filename length");
+ break;
+ }
+ flen = pos2[0];
+ if (flen > pos - pos2 - 1) {
wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon "
"Filename");
break;
}
- os_memcpy(icon->filename, pos2 + 1, pos2[0]);
- pos2 += 1 + pos2[0];
+ os_memcpy(icon->filename, pos2 + 1, flen);
+ pos2 += 1 + flen;
prov->icon_count++;
}
/* OSU_NAI */
- if (pos + 1 > end || pos + 1 + pos[0] > end) {
+ if (pos + 1 > end) {
wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU_NAI");
return;
}
- os_memcpy(prov->osu_nai, pos + 1, pos[0]);
- pos += 1 + pos[0];
+ osu_nai_len = pos[0];
+ if (osu_nai_len > end - pos - 1) {
+ wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU_NAI");
+ return;
+ }
+ os_memcpy(prov->osu_nai, pos + 1, osu_nai_len);
+ pos += 1 + osu_nai_len;
/* OSU Service Description Length */
if (pos + 2 > end) {
@@ -694,7 +752,7 @@
}
len2 = WPA_GET_LE16(pos);
pos += 2;
- if (pos + len2 > end) {
+ if (len2 > end - pos) {
wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU "
"Service Description Duples");
return;
@@ -705,15 +763,18 @@
/* OSU Service Description Duples */
while (pos2 + 4 <= pos && prov->serv_desc_count < OSU_MAX_ITEMS) {
struct osu_lang_string *f;
- if (pos2 + 1 + pos2[0] > pos || pos2[0] < 3) {
+ u8 descr_len;
+
+ descr_len = pos2[0];
+ if (descr_len > pos - pos2 - 1 || descr_len < 3) {
wpa_printf(MSG_DEBUG, "Invalid OSU Service "
"Description");
break;
}
f = &prov->serv_desc[prov->serv_desc_count++];
os_memcpy(f->lang, pos2 + 1, 3);
- os_memcpy(f->text, pos2 + 1 + 3, pos2[0] - 3);
- pos2 += 1 + pos2[0];
+ os_memcpy(f->text, pos2 + 1 + 3, descr_len - 3);
+ pos2 += 1 + descr_len;
}
wpa_printf(MSG_DEBUG, "HS 2.0: Added OSU Provider through " MACSTR,
@@ -778,7 +839,7 @@
num_providers--;
len = WPA_GET_LE16(pos);
pos += 2;
- if (pos + len > end)
+ if (len > (unsigned int) (end - pos))
break;
hs20_osu_add_prov(wpa_s, bss, osu_ssid,
osu_ssid_len, pos, len);
@@ -801,6 +862,10 @@
struct wpa_scan_results *scan_res)
{
wpa_printf(MSG_DEBUG, "OSU provisioning fetch scan completed");
+ if (!wpa_s->fetch_osu_waiting_scan) {
+ wpa_printf(MSG_DEBUG, "OSU fetch have been canceled");
+ return;
+ }
wpa_s->network_select = 0;
wpa_s->fetch_all_anqp = 1;
wpa_s->fetch_osu_info = 1;
@@ -849,6 +914,7 @@
void hs20_start_osu_scan(struct wpa_supplicant *wpa_s)
{
+ wpa_s->fetch_osu_waiting_scan = 1;
wpa_s->num_osu_scans++;
wpa_s->scan_req = MANUAL_SCAN_REQ;
wpa_s->scan_res_handler = hs20_osu_scan_res_handler;
@@ -860,6 +926,7 @@
{
wpa_printf(MSG_DEBUG, "Cancel OSU fetch");
interworking_stop_fetch_anqp(wpa_s);
+ wpa_s->fetch_osu_waiting_scan = 0;
wpa_s->network_select = 0;
wpa_s->fetch_osu_info = 0;
wpa_s->fetch_osu_icon_in_progress = 0;
diff --git a/wpa_supplicant/hs20_supplicant.h b/wpa_supplicant/hs20_supplicant.h
index 06739f5..85b5120 100644
--- a/wpa_supplicant/hs20_supplicant.h
+++ b/wpa_supplicant/hs20_supplicant.h
@@ -17,7 +17,8 @@
void hs20_put_anqp_req(u32 stypes, const u8 *payload, size_t payload_len,
struct wpabuf *buf);
void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
- const u8 *sa, const u8 *data, size_t slen);
+ struct wpa_bss *bss, const u8 *sa,
+ const u8 *data, size_t slen);
int is_hs20_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
struct wpa_bss *bss);
int hs20_get_pps_mo_id(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c
index 3083dd8..d0ae135 100644
--- a/wpa_supplicant/ibss_rsn.c
+++ b/wpa_supplicant/ibss_rsn.c
@@ -72,7 +72,7 @@
if (wpa_s->l2)
return l2_packet_send(wpa_s->l2, dest, proto, buf, len);
- return wpa_drv_send_eapol(wpa_s, dest, proto, buf, len);
+ return -1;
}
@@ -230,7 +230,7 @@
wpa_sm_set_param(peer->supp, WPA_PARAM_PAIRWISE, WPA_CIPHER_CCMP);
wpa_sm_set_param(peer->supp, WPA_PARAM_GROUP, WPA_CIPHER_CCMP);
wpa_sm_set_param(peer->supp, WPA_PARAM_KEY_MGMT, WPA_KEY_MGMT_PSK);
- wpa_sm_set_pmk(peer->supp, psk, PMK_LEN);
+ wpa_sm_set_pmk(peer->supp, psk, PMK_LEN, NULL);
peer->supp_ie_len = sizeof(peer->supp_ie);
if (wpa_sm_set_assoc_wpa_ie_default(peer->supp, peer->supp_ie,
@@ -283,7 +283,7 @@
return l2_packet_send(wpa_s->l2, addr, ETH_P_EAPOL, data,
data_len);
- return wpa_drv_send_eapol(wpa_s, addr, ETH_P_EAPOL, data, data_len);
+ return -1;
}
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index 19b6e38..5ea046f 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -73,6 +73,8 @@
static void interworking_reconnect(struct wpa_supplicant *wpa_s)
{
+ unsigned int tried;
+
if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
wpa_supplicant_cancel_sched_scan(wpa_s);
wpa_supplicant_deauthenticate(wpa_s,
@@ -80,10 +82,13 @@
}
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
+ tried = wpa_s->interworking_fast_assoc_tried;
+ wpa_s->interworking_fast_assoc_tried = 1;
- if (wpa_supplicant_fast_associate(wpa_s) >= 0)
+ if (!tried && wpa_supplicant_fast_associate(wpa_s) >= 0)
return;
+ wpa_s->interworking_fast_assoc_tried = 0;
wpa_supplicant_req_scan(wpa_s, 0, 0);
}
@@ -508,20 +513,25 @@
struct nai_realm *realm;
const u8 *pos, *end;
u16 i, num;
+ size_t left;
- if (anqp == NULL || wpabuf_len(anqp) < 2)
+ if (anqp == NULL)
+ return NULL;
+ left = wpabuf_len(anqp);
+ if (left < 2)
return NULL;
pos = wpabuf_head_u8(anqp);
- end = pos + wpabuf_len(anqp);
+ end = pos + left;
num = WPA_GET_LE16(pos);
wpa_printf(MSG_DEBUG, "NAI Realm Count: %u", num);
pos += 2;
+ left -= 2;
- if (num * 5 > end - pos) {
+ if (num > left / 5) {
wpa_printf(MSG_DEBUG, "Invalid NAI Realm Count %u - not "
"enough data (%u octets) for that many realms",
- num, (unsigned int) (end - pos));
+ num, (unsigned int) left);
return NULL;
}
@@ -577,56 +587,69 @@
}
-static int nai_realm_cred_username(struct nai_realm_eap *eap)
+static int nai_realm_cred_username(struct wpa_supplicant *wpa_s,
+ struct nai_realm_eap *eap)
{
- if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL)
+ if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "nai-realm-cred-username: EAP method not supported: %d",
+ eap->method);
return 0; /* method not supported */
+ }
if (eap->method != EAP_TYPE_TTLS && eap->method != EAP_TYPE_PEAP &&
eap->method != EAP_TYPE_FAST) {
/* Only tunneled methods with username/password supported */
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "nai-realm-cred-username: Method: %d is not TTLS, PEAP, or FAST",
+ eap->method);
return 0;
}
if (eap->method == EAP_TYPE_PEAP || eap->method == EAP_TYPE_FAST) {
if (eap->inner_method &&
- eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL)
+ eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "nai-realm-cred-username: PEAP/FAST: Inner method not supported: %d",
+ eap->inner_method);
return 0;
+ }
if (!eap->inner_method &&
- eap_get_name(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2) == NULL)
+ eap_get_name(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2) == NULL) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "nai-realm-cred-username: MSCHAPv2 not supported");
return 0;
+ }
}
if (eap->method == EAP_TYPE_TTLS) {
if (eap->inner_method == 0 && eap->inner_non_eap == 0)
return 1; /* Assume TTLS/MSCHAPv2 is used */
if (eap->inner_method &&
- eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL)
+ eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "nai-realm-cred-username: TTLS, but inner not supported: %d",
+ eap->inner_method);
return 0;
+ }
if (eap->inner_non_eap &&
eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_PAP &&
eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_CHAP &&
eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAP &&
- eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAPV2)
+ eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAPV2) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "nai-realm-cred-username: TTLS, inner-non-eap not supported: %d",
+ eap->inner_non_eap);
return 0;
+ }
}
if (eap->inner_method &&
eap->inner_method != EAP_TYPE_GTC &&
- eap->inner_method != EAP_TYPE_MSCHAPV2)
- return 0;
-
- return 1;
-}
-
-
-static int nai_realm_cred_cert(struct nai_realm_eap *eap)
-{
- if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL)
- return 0; /* method not supported */
-
- if (eap->method != EAP_TYPE_TLS) {
- /* Only EAP-TLS supported for credential authentication */
+ eap->inner_method != EAP_TYPE_MSCHAPV2) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "nai-realm-cred-username: inner-method not GTC or MSCHAPv2: %d",
+ eap->inner_method);
return 0;
}
@@ -634,27 +657,55 @@
}
-static struct nai_realm_eap * nai_realm_find_eap(struct wpa_cred *cred,
+static int nai_realm_cred_cert(struct wpa_supplicant *wpa_s,
+ struct nai_realm_eap *eap)
+{
+ if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "nai-realm-cred-cert: Method not supported: %d",
+ eap->method);
+ return 0; /* method not supported */
+ }
+
+ if (eap->method != EAP_TYPE_TLS) {
+ /* Only EAP-TLS supported for credential authentication */
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "nai-realm-cred-cert: Method not TLS: %d",
+ eap->method);
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static struct nai_realm_eap * nai_realm_find_eap(struct wpa_supplicant *wpa_s,
+ struct wpa_cred *cred,
struct nai_realm *realm)
{
u8 e;
- if (cred == NULL ||
- cred->username == NULL ||
+ if (cred->username == NULL ||
cred->username[0] == '\0' ||
((cred->password == NULL ||
cred->password[0] == '\0') &&
(cred->private_key == NULL ||
- cred->private_key[0] == '\0')))
+ cred->private_key[0] == '\0'))) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "nai-realm-find-eap: incomplete cred info: username: %s password: %s private_key: %s",
+ cred->username ? cred->username : "NULL",
+ cred->password ? cred->password : "NULL",
+ cred->private_key ? cred->private_key : "NULL");
return NULL;
+ }
for (e = 0; e < realm->eap_count; e++) {
struct nai_realm_eap *eap = &realm->eap[e];
if (cred->password && cred->password[0] &&
- nai_realm_cred_username(eap))
+ nai_realm_cred_username(wpa_s, eap))
return eap;
if (cred->private_key && cred->private_key[0] &&
- nai_realm_cred_cert(eap))
+ nai_realm_cred_cert(wpa_s, eap))
return eap;
}
@@ -1634,7 +1685,7 @@
for (i = 0; i < count; i++) {
if (!nai_realm_match(&realm[i], cred->realm))
continue;
- eap = nai_realm_find_eap(cred, &realm[i]);
+ eap = nai_realm_find_eap(wpa_s, cred, &realm[i]);
if (eap)
break;
}
@@ -1803,22 +1854,29 @@
int ret;
int is_excluded = 0;
- if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL)
+ if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "interworking-avail-3gpp: not avail, anqp: %p anqp_3gpp: %p",
+ bss->anqp, bss->anqp ? bss->anqp->anqp_3gpp : NULL);
return NULL;
+ }
#ifdef CONFIG_EAP_PROXY
if (!wpa_s->imsi[0]) {
size_t len;
- wpa_printf(MSG_DEBUG, "Interworking: IMSI not available - try to read again through eap_proxy");
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: IMSI not available - try to read again through eap_proxy");
wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol,
wpa_s->imsi,
&len);
if (wpa_s->mnc_len > 0) {
wpa_s->imsi[len] = '\0';
- wpa_printf(MSG_DEBUG, "eap_proxy: IMSI %s (MNC length %d)",
- wpa_s->imsi, wpa_s->mnc_len);
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "eap_proxy: IMSI %s (MNC length %d)",
+ wpa_s->imsi, wpa_s->mnc_len);
} else {
- wpa_printf(MSG_DEBUG, "eap_proxy: IMSI not available");
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "eap_proxy: IMSI not available");
}
}
#endif /* CONFIG_EAP_PROXY */
@@ -1940,7 +1998,7 @@
for (i = 0; i < count; i++) {
if (!nai_realm_match(&realm[i], cred->realm))
continue;
- if (nai_realm_find_eap(cred, &realm[i])) {
+ if (nai_realm_find_eap(wpa_s, cred, &realm[i])) {
if (cred_no_required_oi_match(cred, bss))
continue;
if (!ignore_bw &&
@@ -2525,6 +2583,7 @@
if (found == 0) {
if (wpa_s->fetch_osu_info) {
if (wpa_s->num_prov_found == 0 &&
+ wpa_s->fetch_osu_waiting_scan &&
wpa_s->num_osu_scans < 3) {
wpa_printf(MSG_DEBUG, "HS 2.0: No OSU providers seen - try to scan again");
hs20_start_osu_scan(wpa_s);
@@ -2550,7 +2609,12 @@
bss->flags &= ~WPA_BSS_ANQP_FETCH_TRIED;
wpa_s->fetch_anqp_in_progress = 1;
- interworking_next_anqp_fetch(wpa_s);
+
+ /*
+ * Start actual ANQP operation from eloop call to make sure the loop
+ * does not end up using excessive recursion.
+ */
+ eloop_register_timeout(0, 0, interworking_continue_anqp, wpa_s, NULL);
}
@@ -2733,8 +2797,8 @@
switch (type) {
case HS20_ANQP_OUI_TYPE:
- hs20_parse_rx_hs20_anqp_resp(wpa_s, sa, pos,
- slen);
+ hs20_parse_rx_hs20_anqp_resp(wpa_s, bss, sa,
+ pos, slen);
break;
default:
wpa_printf(MSG_DEBUG, "HS20: Unsupported ANQP "
@@ -2769,6 +2833,7 @@
u16 info_id;
u16 slen;
struct wpa_bss *bss = NULL, *tmp;
+ const char *anqp_result = "SUCCESS";
wpa_printf(MSG_DEBUG, "Interworking: anqp_resp_cb dst=" MACSTR
" dialog_token=%u result=%d status_code=%u",
@@ -2776,7 +2841,8 @@
if (result != GAS_QUERY_SUCCESS) {
if (wpa_s->fetch_osu_icon_in_progress)
hs20_icon_fetch_failed(wpa_s);
- return;
+ anqp_result = "FAILURE";
+ goto out;
}
pos = wpabuf_head(adv_proto);
@@ -2786,7 +2852,8 @@
"Protocol in response");
if (wpa_s->fetch_osu_icon_in_progress)
hs20_icon_fetch_failed(wpa_s);
- return;
+ anqp_result = "INVALID_FRAME";
+ goto out;
}
/*
@@ -2808,25 +2875,34 @@
end = pos + wpabuf_len(resp);
while (pos < end) {
- if (pos + 4 > end) {
+ unsigned int left = end - pos;
+
+ if (left < 4) {
wpa_printf(MSG_DEBUG, "ANQP: Invalid element");
- break;
+ anqp_result = "INVALID_FRAME";
+ goto out_parse_done;
}
info_id = WPA_GET_LE16(pos);
pos += 2;
slen = WPA_GET_LE16(pos);
pos += 2;
- if (pos + slen > end) {
+ left -= 4;
+ if (left < slen) {
wpa_printf(MSG_DEBUG, "ANQP: Invalid element length "
"for Info ID %u", info_id);
- break;
+ anqp_result = "INVALID_FRAME";
+ goto out_parse_done;
}
interworking_parse_rx_anqp_resp(wpa_s, bss, dst, info_id, pos,
slen);
pos += slen;
}
+out_parse_done:
hs20_notify_parse_done(wpa_s);
+out:
+ wpa_msg(wpa_s, MSG_INFO, ANQP_QUERY_DONE "addr=" MACSTR " result=%s",
+ MAC2STR(dst), anqp_result);
}
diff --git a/wpa_supplicant/main.c b/wpa_supplicant/main.c
index e596468..13e9769 100644
--- a/wpa_supplicant/main.c
+++ b/wpa_supplicant/main.c
@@ -327,14 +327,6 @@
exitcode = -1;
break;
}
-#ifdef CONFIG_P2P
- if (wpa_s->global->p2p == NULL &&
- (wpa_s->drv_flags &
- WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
- wpas_p2p_add_p2pdev_interface(wpa_s, iface->conf_p2p_dev) <
- 0)
- exitcode = -1;
-#endif /* CONFIG_P2P */
}
if (exitcode == 0)
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
new file mode 100644
index 0000000..32506b6
--- /dev/null
+++ b/wpa_supplicant/mesh.c
@@ -0,0 +1,540 @@
+/*
+ * WPA Supplicant - Basic mesh mode routines
+ * Copyright (c) 2013-2014, cozybit, Inc. 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 "utils/eloop.h"
+#include "utils/uuid.h"
+#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
+#include "ap/sta_info.h"
+#include "ap/hostapd.h"
+#include "ap/ieee802_11.h"
+#include "config_ssid.h"
+#include "config.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "notify.h"
+#include "ap.h"
+#include "mesh_mpm.h"
+#include "mesh_rsn.h"
+#include "mesh.h"
+
+
+static void wpa_supplicant_mesh_deinit(struct wpa_supplicant *wpa_s)
+{
+ wpa_supplicant_mesh_iface_deinit(wpa_s, wpa_s->ifmsh);
+ wpa_s->ifmsh = NULL;
+ wpa_s->current_ssid = NULL;
+ os_free(wpa_s->mesh_rsn);
+ wpa_s->mesh_rsn = NULL;
+ /* TODO: leave mesh (stop beacon). This will happen on link down
+ * anyway, so it's not urgent */
+}
+
+
+void wpa_supplicant_mesh_iface_deinit(struct wpa_supplicant *wpa_s,
+ struct hostapd_iface *ifmsh)
+{
+ if (!ifmsh)
+ return;
+
+ if (ifmsh->mconf) {
+ mesh_mpm_deinit(wpa_s, ifmsh);
+ if (ifmsh->mconf->ies) {
+ ifmsh->mconf->ies = NULL;
+ /* We cannot free this struct
+ * because wpa_authenticator on
+ * hostapd side is also using it
+ * for now just set to NULL and
+ * let hostapd code free it.
+ */
+ }
+ os_free(ifmsh->mconf);
+ ifmsh->mconf = NULL;
+ }
+
+ /* take care of shared data */
+ hostapd_interface_deinit(ifmsh);
+ hostapd_interface_free(ifmsh);
+}
+
+
+static struct mesh_conf * mesh_config_create(struct wpa_ssid *ssid)
+{
+ struct mesh_conf *conf;
+
+ conf = os_zalloc(sizeof(struct mesh_conf));
+ if (!conf)
+ return NULL;
+
+ os_memcpy(conf->meshid, ssid->ssid, ssid->ssid_len);
+ conf->meshid_len = ssid->ssid_len;
+
+ if (ssid->key_mgmt & WPA_KEY_MGMT_SAE)
+ conf->security |= MESH_CONF_SEC_AUTH |
+ MESH_CONF_SEC_AMPE;
+ else
+ conf->security |= MESH_CONF_SEC_NONE;
+
+ /* defaults */
+ conf->mesh_pp_id = MESH_PATH_PROTOCOL_HWMP;
+ conf->mesh_pm_id = MESH_PATH_METRIC_AIRTIME;
+ conf->mesh_cc_id = 0;
+ conf->mesh_sp_id = MESH_SYNC_METHOD_NEIGHBOR_OFFSET;
+ conf->mesh_auth_id = (conf->security & MESH_CONF_SEC_AUTH) ? 1 : 0;
+ conf->dot11MeshMaxRetries = ssid->dot11MeshMaxRetries;
+ conf->dot11MeshRetryTimeout = ssid->dot11MeshRetryTimeout;
+ conf->dot11MeshConfirmTimeout = ssid->dot11MeshConfirmTimeout;
+ conf->dot11MeshHoldingTimeout = ssid->dot11MeshHoldingTimeout;
+
+ return conf;
+}
+
+
+static void wpas_mesh_copy_groups(struct hostapd_data *bss,
+ struct wpa_supplicant *wpa_s)
+{
+ int num_groups;
+ size_t groups_size;
+
+ for (num_groups = 0; wpa_s->conf->sae_groups[num_groups] > 0;
+ num_groups++)
+ ;
+
+ groups_size = (num_groups + 1) * sizeof(wpa_s->conf->sae_groups[0]);
+ bss->conf->sae_groups = os_malloc(groups_size);
+ if (bss->conf->sae_groups)
+ os_memcpy(bss->conf->sae_groups, wpa_s->conf->sae_groups,
+ groups_size);
+}
+
+
+static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ struct hostapd_iface *ifmsh;
+ struct hostapd_data *bss;
+ struct hostapd_config *conf;
+ struct mesh_conf *mconf;
+ int basic_rates_erp[] = { 10, 20, 55, 60, 110, 120, 240, -1 };
+ static int default_groups[] = { 19, 20, 21, 25, 26, -1 };
+ size_t len;
+ int rate_len;
+
+ if (!wpa_s->conf->user_mpm) {
+ /* not much for us to do here */
+ wpa_msg(wpa_s, MSG_WARNING,
+ "user_mpm is not enabled in configuration");
+ return 0;
+ }
+
+ wpa_s->ifmsh = ifmsh = os_zalloc(sizeof(*wpa_s->ifmsh));
+ if (!ifmsh)
+ return -ENOMEM;
+
+ ifmsh->drv_flags = wpa_s->drv_flags;
+ ifmsh->num_bss = 1;
+ ifmsh->bss = os_calloc(wpa_s->ifmsh->num_bss,
+ sizeof(struct hostapd_data *));
+ if (!ifmsh->bss)
+ goto out_free;
+
+ ifmsh->bss[0] = bss = os_zalloc(sizeof(struct hostapd_data));
+ if (!bss)
+ goto out_free;
+
+ os_memcpy(bss->own_addr, wpa_s->own_addr, ETH_ALEN);
+ bss->driver = wpa_s->driver;
+ bss->drv_priv = wpa_s->drv_priv;
+ bss->iface = ifmsh;
+ bss->mesh_sta_free_cb = mesh_mpm_free_sta;
+ wpa_s->assoc_freq = ssid->frequency;
+ wpa_s->current_ssid = ssid;
+
+ /* setup an AP config for auth processing */
+ conf = hostapd_config_defaults();
+ if (!conf)
+ goto out_free;
+
+ bss->conf = *conf->bss;
+ bss->conf->start_disabled = 1;
+ bss->conf->mesh = MESH_ENABLED;
+ bss->conf->ap_max_inactivity = wpa_s->conf->mesh_max_inactivity;
+ bss->iconf = conf;
+ ifmsh->conf = conf;
+
+ ifmsh->bss[0]->max_plinks = wpa_s->conf->max_peer_links;
+ os_strlcpy(bss->conf->iface, wpa_s->ifname, sizeof(bss->conf->iface));
+
+ mconf = mesh_config_create(ssid);
+ if (!mconf)
+ goto out_free;
+ ifmsh->mconf = mconf;
+
+ /* need conf->hw_mode for supported rates. */
+ if (ssid->frequency == 0) {
+ conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
+ conf->channel = 1;
+ } else {
+ conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency,
+ &conf->channel);
+ }
+ if (conf->hw_mode == NUM_HOSTAPD_MODES) {
+ wpa_printf(MSG_ERROR, "Unsupported mesh mode frequency: %d MHz",
+ ssid->frequency);
+ goto out_free;
+ }
+
+ if (ssid->mesh_basic_rates == NULL) {
+ /*
+ * XXX: Hack! This is so an MPM which correctly sets the ERP
+ * mandatory rates as BSSBasicRateSet doesn't reject us. We
+ * could add a new hw_mode HOSTAPD_MODE_IEEE80211G_ERP, but
+ * this is way easier. This also makes our BSSBasicRateSet
+ * advertised in beacons match the one in peering frames, sigh.
+ */
+ if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G) {
+ conf->basic_rates = os_malloc(sizeof(basic_rates_erp));
+ if (!conf->basic_rates)
+ goto out_free;
+ os_memcpy(conf->basic_rates, basic_rates_erp,
+ sizeof(basic_rates_erp));
+ }
+ } else {
+ rate_len = 0;
+ while (1) {
+ if (ssid->mesh_basic_rates[rate_len] < 1)
+ break;
+ rate_len++;
+ }
+ conf->basic_rates = os_calloc(rate_len + 1, sizeof(int));
+ if (conf->basic_rates == NULL)
+ goto out_free;
+ os_memcpy(conf->basic_rates, ssid->mesh_basic_rates,
+ rate_len * sizeof(int));
+ conf->basic_rates[rate_len] = -1;
+ }
+
+ if (hostapd_setup_interface(ifmsh)) {
+ wpa_printf(MSG_ERROR,
+ "Failed to initialize hostapd interface for mesh");
+ return -1;
+ }
+
+ if (wpa_drv_init_mesh(wpa_s)) {
+ wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh in driver");
+ return -1;
+ }
+
+ if (mconf->security != MESH_CONF_SEC_NONE) {
+ if (ssid->passphrase == NULL) {
+ wpa_printf(MSG_ERROR,
+ "mesh: Passphrase for SAE not configured");
+ goto out_free;
+ }
+
+ bss->conf->wpa = ssid->proto;
+ bss->conf->wpa_key_mgmt = ssid->key_mgmt;
+
+ if (wpa_s->conf->sae_groups &&
+ wpa_s->conf->sae_groups[0] > 0) {
+ wpas_mesh_copy_groups(bss, wpa_s);
+ } else {
+ bss->conf->sae_groups =
+ os_malloc(sizeof(default_groups));
+ if (!bss->conf->sae_groups)
+ goto out_free;
+ os_memcpy(bss->conf->sae_groups, default_groups,
+ sizeof(default_groups));
+ }
+
+ len = os_strlen(ssid->passphrase);
+ bss->conf->ssid.wpa_passphrase =
+ dup_binstr(ssid->passphrase, len);
+
+ wpa_s->mesh_rsn = mesh_rsn_auth_init(wpa_s, mconf);
+ if (!wpa_s->mesh_rsn)
+ goto out_free;
+ }
+
+ wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf);
+
+ return 0;
+out_free:
+ wpa_supplicant_mesh_deinit(wpa_s);
+ return -ENOMEM;
+}
+
+
+void wpa_mesh_notify_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
+ const u8 *ies, size_t ie_len)
+{
+ struct ieee802_11_elems elems;
+
+ wpa_msg(wpa_s, MSG_INFO,
+ "new peer notification for " MACSTR, MAC2STR(addr));
+
+ if (ieee802_11_parse_elems(ies, ie_len, &elems, 0) == ParseFailed) {
+ wpa_msg(wpa_s, MSG_INFO, "Could not parse beacon from " MACSTR,
+ MAC2STR(addr));
+ return;
+ }
+ wpa_mesh_new_mesh_peer(wpa_s, addr, &elems);
+}
+
+
+void wpa_supplicant_mesh_add_scan_ie(struct wpa_supplicant *wpa_s,
+ struct wpabuf **extra_ie)
+{
+ /* EID + 0-length (wildcard) mesh-id */
+ size_t ielen = 2;
+
+ if (wpabuf_resize(extra_ie, ielen) == 0) {
+ wpabuf_put_u8(*extra_ie, WLAN_EID_MESH_ID);
+ wpabuf_put_u8(*extra_ie, 0);
+ }
+}
+
+
+int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ struct wpa_driver_mesh_join_params params;
+ int ret = 0;
+
+ if (!ssid || !ssid->ssid || !ssid->ssid_len || !ssid->frequency) {
+ ret = -ENOENT;
+ goto out;
+ }
+
+ wpa_supplicant_mesh_deinit(wpa_s);
+
+ os_memset(¶ms, 0, sizeof(params));
+ params.meshid = ssid->ssid;
+ params.meshid_len = ssid->ssid_len;
+ ibss_mesh_setup_freq(wpa_s, ssid, ¶ms.freq);
+ wpa_s->mesh_ht_enabled = !!params.freq.ht_enabled;
+ if (ssid->beacon_int > 0)
+ params.beacon_int = ssid->beacon_int;
+ else if (wpa_s->conf->beacon_int > 0)
+ params.beacon_int = wpa_s->conf->beacon_int;
+ params.max_peer_links = wpa_s->conf->max_peer_links;
+
+ if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
+ params.flags |= WPA_DRIVER_MESH_FLAG_SAE_AUTH;
+ params.flags |= WPA_DRIVER_MESH_FLAG_AMPE;
+ wpa_s->conf->user_mpm = 1;
+ }
+
+ if (wpa_s->conf->user_mpm) {
+ params.flags |= WPA_DRIVER_MESH_FLAG_USER_MPM;
+ params.conf.flags &= ~WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS;
+ } else {
+ params.flags |= WPA_DRIVER_MESH_FLAG_DRIVER_MPM;
+ params.conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS;
+ }
+ params.conf.peer_link_timeout = wpa_s->conf->mesh_max_inactivity;
+
+ if (wpa_supplicant_mesh_init(wpa_s, ssid)) {
+ wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh");
+ ret = -1;
+ goto out;
+ }
+
+ if (wpa_s->ifmsh) {
+ params.ies = wpa_s->ifmsh->mconf->ies;
+ params.ie_len = wpa_s->ifmsh->mconf->ie_len;
+ params.basic_rates = wpa_s->ifmsh->basic_rates;
+ }
+
+ wpa_msg(wpa_s, MSG_INFO, "joining mesh %s",
+ wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+ ret = wpa_drv_join_mesh(wpa_s, ¶ms);
+ if (ret)
+ wpa_msg(wpa_s, MSG_ERROR, "mesh join error=%d\n", ret);
+
+ /* hostapd sets the interface down until we associate */
+ wpa_drv_set_operstate(wpa_s, 1);
+
+out:
+ return ret;
+}
+
+
+int wpa_supplicant_leave_mesh(struct wpa_supplicant *wpa_s)
+{
+ int ret = 0;
+
+ wpa_msg(wpa_s, MSG_INFO, "leaving mesh");
+
+ /* Need to send peering close messages first */
+ wpa_supplicant_mesh_deinit(wpa_s);
+
+ ret = wpa_drv_leave_mesh(wpa_s);
+ if (ret)
+ wpa_msg(wpa_s, MSG_ERROR, "mesh leave error=%d", ret);
+
+ wpa_drv_set_operstate(wpa_s, 1);
+
+ return ret;
+}
+
+
+static int mesh_attr_text(const u8 *ies, size_t ies_len, char *buf, char *end)
+{
+ struct ieee802_11_elems elems;
+ char *mesh_id, *pos = buf;
+ u8 *bss_basic_rate_set;
+ int bss_basic_rate_set_len, ret, i;
+
+ if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) == ParseFailed)
+ return -1;
+
+ if (elems.mesh_id_len < 1)
+ return 0;
+
+ mesh_id = os_malloc(elems.mesh_id_len + 1);
+ if (mesh_id == NULL)
+ return -1;
+
+ os_memcpy(mesh_id, elems.mesh_id, elems.mesh_id_len);
+ mesh_id[elems.mesh_id_len] = '\0';
+ ret = os_snprintf(pos, end - pos, "mesh_id=%s\n", mesh_id);
+ os_free(mesh_id);
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ if (elems.mesh_config_len > 6) {
+ ret = os_snprintf(pos, end - pos,
+ "active_path_selection_protocol_id=0x%02x\n"
+ "active_path_selection_metric_id=0x%02x\n"
+ "congestion_control_mode_id=0x%02x\n"
+ "synchronization_method_id=0x%02x\n"
+ "authentication_protocol_id=0x%02x\n"
+ "mesh_formation_info=0x%02x\n"
+ "mesh_capability=0x%02x\n",
+ elems.mesh_config[0], elems.mesh_config[1],
+ elems.mesh_config[2], elems.mesh_config[3],
+ elems.mesh_config[4], elems.mesh_config[5],
+ elems.mesh_config[6]);
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+ bss_basic_rate_set = os_malloc(elems.supp_rates_len +
+ elems.ext_supp_rates_len);
+ if (bss_basic_rate_set == NULL)
+ return -1;
+
+ bss_basic_rate_set_len = 0;
+ for (i = 0; i < elems.supp_rates_len; i++) {
+ if (elems.supp_rates[i] & 0x80) {
+ bss_basic_rate_set[bss_basic_rate_set_len++] =
+ (elems.supp_rates[i] & 0x7f) * 5;
+ }
+ }
+ for (i = 0; i < elems.ext_supp_rates_len; i++) {
+ if (elems.ext_supp_rates[i] & 0x80) {
+ bss_basic_rate_set[bss_basic_rate_set_len++] =
+ (elems.ext_supp_rates[i] & 0x7f) * 5;
+ }
+ }
+ if (bss_basic_rate_set_len > 0) {
+ ret = os_snprintf(pos, end - pos, "bss_basic_rate_set=%d",
+ bss_basic_rate_set[0]);
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ for (i = 1; i < bss_basic_rate_set_len; i++) {
+ ret = os_snprintf(pos, end - pos, " %d",
+ bss_basic_rate_set[i]);
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+ ret = os_snprintf(pos, end - pos, "\n");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+ os_free(bss_basic_rate_set);
+
+ return pos - buf;
+}
+
+
+int wpas_mesh_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
+ char *end)
+{
+ return mesh_attr_text(ies, ies_len, buf, end);
+}
+
+
+static int wpas_mesh_get_ifname(struct wpa_supplicant *wpa_s, char *ifname,
+ size_t len)
+{
+ char *ifname_ptr = wpa_s->ifname;
+ int res;
+
+ res = os_snprintf(ifname, len, "mesh-%s-%d", ifname_ptr,
+ wpa_s->mesh_if_idx);
+ if (os_snprintf_error(len, res) ||
+ (os_strlen(ifname) >= IFNAMSIZ &&
+ os_strlen(wpa_s->ifname) < IFNAMSIZ)) {
+ /* Try to avoid going over the IFNAMSIZ length limit */
+ res = os_snprintf(ifname, len, "mesh-%d", wpa_s->mesh_if_idx);
+ if (os_snprintf_error(len, res))
+ return -1;
+ }
+ wpa_s->mesh_if_idx++;
+ return 0;
+}
+
+
+int wpas_mesh_add_interface(struct wpa_supplicant *wpa_s, char *ifname,
+ size_t len)
+{
+ struct wpa_interface iface;
+ struct wpa_supplicant *mesh_wpa_s;
+ u8 addr[ETH_ALEN];
+
+ if (ifname[0] == '\0' && wpas_mesh_get_ifname(wpa_s, ifname, len) < 0)
+ return -1;
+
+ if (wpa_drv_if_add(wpa_s, WPA_IF_MESH, ifname, NULL, NULL, NULL, addr,
+ NULL) < 0) {
+ wpa_printf(MSG_ERROR,
+ "mesh: Failed to create new mesh interface");
+ return -1;
+ }
+ wpa_printf(MSG_INFO, "mesh: Created virtual interface %s addr "
+ MACSTR, ifname, MAC2STR(addr));
+
+ os_memset(&iface, 0, sizeof(iface));
+ iface.ifname = ifname;
+ iface.driver = wpa_s->driver->name;
+ iface.driver_param = wpa_s->conf->driver_param;
+ iface.ctrl_interface = wpa_s->conf->ctrl_interface;
+
+ mesh_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface);
+ if (!mesh_wpa_s) {
+ wpa_printf(MSG_ERROR,
+ "mesh: Failed to create new wpa_supplicant interface");
+ wpa_supplicant_remove_iface(wpa_s->global, wpa_s, 0);
+ return -1;
+ }
+ mesh_wpa_s->mesh_if_created = 1;
+ mesh_wpa_s->parent = wpa_s;
+ return 0;
+}
diff --git a/wpa_supplicant/mesh.h b/wpa_supplicant/mesh.h
new file mode 100644
index 0000000..3cb7f1b
--- /dev/null
+++ b/wpa_supplicant/mesh.h
@@ -0,0 +1,44 @@
+/*
+ * WPA Supplicant - Basic mesh mode routines
+ * Copyright (c) 2013-2014, cozybit, Inc. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MESH_H
+#define MESH_H
+
+int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid);
+int wpa_supplicant_leave_mesh(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_mesh_iface_deinit(struct wpa_supplicant *wpa_s,
+ struct hostapd_iface *ifmsh);
+int wpas_mesh_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
+ char *end);
+int wpas_mesh_add_interface(struct wpa_supplicant *wpa_s, char *ifname,
+ size_t len);
+
+#ifdef CONFIG_MESH
+
+void wpa_mesh_notify_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
+ const u8 *ies, size_t ie_len);
+void wpa_supplicant_mesh_add_scan_ie(struct wpa_supplicant *wpa_s,
+ struct wpabuf **extra_ie);
+
+#else /* CONFIG_MESH */
+
+static inline void wpa_mesh_notify_peer(struct wpa_supplicant *wpa_s,
+ const u8 *addr,
+ const u8 *ies, size_t ie_len)
+{
+}
+
+static inline void wpa_supplicant_mesh_add_scan_ie(struct wpa_supplicant *wpa_s,
+ struct wpabuf **extra_ie)
+{
+}
+
+#endif /* CONFIG_MESH */
+
+#endif /* MESH_H */
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
new file mode 100644
index 0000000..4a259ff
--- /dev/null
+++ b/wpa_supplicant/mesh_mpm.c
@@ -0,0 +1,1028 @@
+/*
+ * WPA Supplicant - Basic mesh peer management
+ * Copyright (c) 2013-2014, cozybit, Inc. 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 "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "ap/hostapd.h"
+#include "ap/sta_info.h"
+#include "ap/ieee802_11.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "mesh_mpm.h"
+#include "mesh_rsn.h"
+
+struct mesh_peer_mgmt_ie {
+ const u8 *proto_id;
+ const u8 *llid;
+ const u8 *plid;
+ const u8 *reason;
+ const u8 *pmk;
+};
+
+static void plink_timer(void *eloop_ctx, void *user_data);
+
+
+enum plink_event {
+ PLINK_UNDEFINED,
+ OPN_ACPT,
+ OPN_RJCT,
+ OPN_IGNR,
+ CNF_ACPT,
+ CNF_RJCT,
+ CNF_IGNR,
+ CLS_ACPT,
+ CLS_IGNR
+};
+
+static const char * const mplstate[] = {
+ [PLINK_LISTEN] = "LISTEN",
+ [PLINK_OPEN_SENT] = "OPEN_SENT",
+ [PLINK_OPEN_RCVD] = "OPEN_RCVD",
+ [PLINK_CNF_RCVD] = "CNF_RCVD",
+ [PLINK_ESTAB] = "ESTAB",
+ [PLINK_HOLDING] = "HOLDING",
+ [PLINK_BLOCKED] = "BLOCKED"
+};
+
+static const char * const mplevent[] = {
+ [PLINK_UNDEFINED] = "UNDEFINED",
+ [OPN_ACPT] = "OPN_ACPT",
+ [OPN_RJCT] = "OPN_RJCT",
+ [OPN_IGNR] = "OPN_IGNR",
+ [CNF_ACPT] = "CNF_ACPT",
+ [CNF_RJCT] = "CNF_RJCT",
+ [CNF_IGNR] = "CNF_IGNR",
+ [CLS_ACPT] = "CLS_ACPT",
+ [CLS_IGNR] = "CLS_IGNR"
+};
+
+
+static int mesh_mpm_parse_peer_mgmt(struct wpa_supplicant *wpa_s,
+ u8 action_field,
+ const u8 *ie, size_t len,
+ struct mesh_peer_mgmt_ie *mpm_ie)
+{
+ os_memset(mpm_ie, 0, sizeof(*mpm_ie));
+
+ /* remove optional PMK at end */
+ if (len >= 16) {
+ len -= 16;
+ mpm_ie->pmk = ie + len - 16;
+ }
+
+ if ((action_field == PLINK_OPEN && len != 4) ||
+ (action_field == PLINK_CONFIRM && len != 6) ||
+ (action_field == PLINK_CLOSE && len != 6 && len != 8)) {
+ wpa_msg(wpa_s, MSG_DEBUG, "MPM: Invalid peer mgmt ie");
+ return -1;
+ }
+
+ /* required fields */
+ if (len < 4)
+ return -1;
+ mpm_ie->proto_id = ie;
+ mpm_ie->llid = ie + 2;
+ ie += 4;
+ len -= 4;
+
+ /* close reason is always present at end for close */
+ if (action_field == PLINK_CLOSE) {
+ if (len < 2)
+ return -1;
+ mpm_ie->reason = ie + len - 2;
+ len -= 2;
+ }
+
+ /* plid, present for confirm, and possibly close */
+ if (len)
+ mpm_ie->plid = ie;
+
+ return 0;
+}
+
+
+static int plink_free_count(struct hostapd_data *hapd)
+{
+ if (hapd->max_plinks > hapd->num_plinks)
+ return hapd->max_plinks - hapd->num_plinks;
+ return 0;
+}
+
+
+static u16 copy_supp_rates(struct wpa_supplicant *wpa_s,
+ struct sta_info *sta,
+ struct ieee802_11_elems *elems)
+{
+ if (!elems->supp_rates) {
+ wpa_msg(wpa_s, MSG_ERROR, "no supported rates from " MACSTR,
+ MAC2STR(sta->addr));
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ if (elems->supp_rates_len + elems->ext_supp_rates_len >
+ sizeof(sta->supported_rates)) {
+ wpa_msg(wpa_s, MSG_ERROR,
+ "Invalid supported rates element length " MACSTR
+ " %d+%d", MAC2STR(sta->addr), elems->supp_rates_len,
+ elems->ext_supp_rates_len);
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ sta->supported_rates_len = merge_byte_arrays(
+ sta->supported_rates, sizeof(sta->supported_rates),
+ elems->supp_rates, elems->supp_rates_len,
+ elems->ext_supp_rates, elems->ext_supp_rates_len);
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+/* return true if elems from a neighbor match this MBSS */
+static Boolean matches_local(struct wpa_supplicant *wpa_s,
+ struct ieee802_11_elems *elems)
+{
+ struct mesh_conf *mconf = wpa_s->ifmsh->mconf;
+
+ if (elems->mesh_config_len < 5)
+ return FALSE;
+
+ return (mconf->meshid_len == elems->mesh_id_len &&
+ os_memcmp(mconf->meshid, elems->mesh_id,
+ elems->mesh_id_len) == 0 &&
+ mconf->mesh_pp_id == elems->mesh_config[0] &&
+ mconf->mesh_pm_id == elems->mesh_config[1] &&
+ mconf->mesh_cc_id == elems->mesh_config[2] &&
+ mconf->mesh_sp_id == elems->mesh_config[3] &&
+ mconf->mesh_auth_id == elems->mesh_config[4]);
+}
+
+
+/* check if local link id is already used with another peer */
+static Boolean llid_in_use(struct wpa_supplicant *wpa_s, u16 llid)
+{
+ struct sta_info *sta;
+ struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (sta->my_lid == llid)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/* generate an llid for a link and set to initial state */
+static void mesh_mpm_init_link(struct wpa_supplicant *wpa_s,
+ struct sta_info *sta)
+{
+ u16 llid;
+
+ do {
+ if (os_get_random((u8 *) &llid, sizeof(llid)) < 0)
+ continue;
+ } while (!llid || llid_in_use(wpa_s, llid));
+
+ sta->my_lid = llid;
+ sta->peer_lid = 0;
+ sta->plink_state = PLINK_LISTEN;
+}
+
+
+static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
+ struct sta_info *sta,
+ enum plink_action_field type,
+ u16 close_reason)
+{
+ struct wpabuf *buf;
+ struct hostapd_iface *ifmsh = wpa_s->ifmsh;
+ struct hostapd_data *bss = ifmsh->bss[0];
+ struct mesh_conf *conf = ifmsh->mconf;
+ u8 supp_rates[2 + 2 + 32];
+#ifdef CONFIG_IEEE80211N
+ u8 ht_capa_oper[2 + 26 + 2 + 22];
+#endif /* CONFIG_IEEE80211N */
+ u8 *pos, *cat;
+ u8 ie_len, add_plid = 0;
+ int ret;
+ int ampe = conf->security & MESH_CONF_SEC_AMPE;
+ size_t buf_len;
+
+ if (!sta)
+ return;
+
+ buf_len = 2 + /* capability info */
+ 2 + /* AID */
+ 2 + 8 + /* supported rates */
+ 2 + (32 - 8) +
+ 2 + 32 + /* mesh ID */
+ 2 + 7 + /* mesh config */
+ 2 + 23 + /* peering management */
+ 2 + 96 + /* AMPE */
+ 2 + 16; /* MIC */
+#ifdef CONFIG_IEEE80211N
+ if (type != PLINK_CLOSE && wpa_s->mesh_ht_enabled) {
+ buf_len += 2 + 26 + /* HT capabilities */
+ 2 + 22; /* HT operation */
+ }
+#endif /* CONFIG_IEEE80211N */
+ buf = wpabuf_alloc(buf_len);
+ if (!buf)
+ return;
+
+ cat = wpabuf_mhead_u8(buf);
+ wpabuf_put_u8(buf, WLAN_ACTION_SELF_PROTECTED);
+ wpabuf_put_u8(buf, type);
+
+ if (type != PLINK_CLOSE) {
+ u8 info;
+
+ /* capability info */
+ wpabuf_put_le16(buf, ampe ? IEEE80211_CAP_PRIVACY : 0);
+
+ /* aid */
+ if (type == PLINK_CONFIRM)
+ wpabuf_put_le16(buf, sta->peer_lid);
+
+ /* IE: supp + ext. supp rates */
+ pos = hostapd_eid_supp_rates(bss, supp_rates);
+ pos = hostapd_eid_ext_supp_rates(bss, pos);
+ wpabuf_put_data(buf, supp_rates, pos - supp_rates);
+
+ /* IE: Mesh ID */
+ wpabuf_put_u8(buf, WLAN_EID_MESH_ID);
+ wpabuf_put_u8(buf, conf->meshid_len);
+ wpabuf_put_data(buf, conf->meshid, conf->meshid_len);
+
+ /* IE: mesh conf */
+ wpabuf_put_u8(buf, WLAN_EID_MESH_CONFIG);
+ wpabuf_put_u8(buf, 7);
+ wpabuf_put_u8(buf, conf->mesh_pp_id);
+ wpabuf_put_u8(buf, conf->mesh_pm_id);
+ wpabuf_put_u8(buf, conf->mesh_cc_id);
+ wpabuf_put_u8(buf, conf->mesh_sp_id);
+ wpabuf_put_u8(buf, conf->mesh_auth_id);
+ info = (bss->num_plinks > 63 ? 63 : bss->num_plinks) << 1;
+ /* TODO: Add Connected to Mesh Gate/AS subfields */
+ wpabuf_put_u8(buf, info);
+ /* always forwarding & accepting plinks for now */
+ wpabuf_put_u8(buf, 0x1 | 0x8);
+ } else { /* Peer closing frame */
+ /* IE: Mesh ID */
+ wpabuf_put_u8(buf, WLAN_EID_MESH_ID);
+ wpabuf_put_u8(buf, conf->meshid_len);
+ wpabuf_put_data(buf, conf->meshid, conf->meshid_len);
+ }
+
+ /* IE: Mesh Peering Management element */
+ ie_len = 4;
+ if (ampe)
+ ie_len += PMKID_LEN;
+ switch (type) {
+ case PLINK_OPEN:
+ break;
+ case PLINK_CONFIRM:
+ ie_len += 2;
+ add_plid = 1;
+ break;
+ case PLINK_CLOSE:
+ ie_len += 2;
+ add_plid = 1;
+ ie_len += 2; /* reason code */
+ break;
+ }
+
+ wpabuf_put_u8(buf, WLAN_EID_PEER_MGMT);
+ wpabuf_put_u8(buf, ie_len);
+ /* peering protocol */
+ if (ampe)
+ wpabuf_put_le16(buf, 1);
+ else
+ wpabuf_put_le16(buf, 0);
+ wpabuf_put_le16(buf, sta->my_lid);
+ if (add_plid)
+ wpabuf_put_le16(buf, sta->peer_lid);
+ if (type == PLINK_CLOSE)
+ wpabuf_put_le16(buf, close_reason);
+ if (ampe) {
+ if (sta->sae == NULL) {
+ wpa_msg(wpa_s, MSG_INFO, "Mesh MPM: no SAE session");
+ goto fail;
+ }
+ mesh_rsn_get_pmkid(wpa_s->mesh_rsn, sta,
+ wpabuf_put(buf, PMKID_LEN));
+ }
+
+#ifdef CONFIG_IEEE80211N
+ if (type != PLINK_CLOSE && wpa_s->mesh_ht_enabled) {
+ pos = hostapd_eid_ht_capabilities(bss, ht_capa_oper);
+ pos = hostapd_eid_ht_operation(bss, pos);
+ wpabuf_put_data(buf, ht_capa_oper, pos - ht_capa_oper);
+ }
+#endif /* CONFIG_IEEE80211N */
+
+ if (ampe && mesh_rsn_protect_frame(wpa_s->mesh_rsn, sta, cat, buf)) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Mesh MPM: failed to add AMPE and MIC IE");
+ goto fail;
+ }
+
+ ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0,
+ sta->addr, wpa_s->own_addr, wpa_s->own_addr,
+ wpabuf_head(buf), wpabuf_len(buf), 0);
+ if (ret < 0)
+ wpa_msg(wpa_s, MSG_INFO,
+ "Mesh MPM: failed to send peering frame");
+
+fail:
+ wpabuf_free(buf);
+}
+
+
+/* configure peering state in ours and driver's station entry */
+static void
+wpa_mesh_set_plink_state(struct wpa_supplicant *wpa_s, struct sta_info *sta,
+ enum mesh_plink_state state)
+{
+ struct hostapd_sta_add_params params;
+ int ret;
+
+ sta->plink_state = state;
+
+ os_memset(¶ms, 0, sizeof(params));
+ params.addr = sta->addr;
+ params.plink_state = state;
+ params.set = 1;
+
+ wpa_msg(wpa_s, MSG_DEBUG, "MPM set " MACSTR " into %s",
+ MAC2STR(sta->addr), mplstate[state]);
+ ret = wpa_drv_sta_add(wpa_s, ¶ms);
+ if (ret) {
+ wpa_msg(wpa_s, MSG_ERROR, "Driver failed to set " MACSTR
+ ": %d", MAC2STR(sta->addr), ret);
+ }
+}
+
+
+static void mesh_mpm_fsm_restart(struct wpa_supplicant *wpa_s,
+ struct sta_info *sta)
+{
+ struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+
+ eloop_cancel_timeout(plink_timer, wpa_s, sta);
+
+ if (sta->mpm_close_reason == WLAN_REASON_MESH_CLOSE_RCVD) {
+ ap_free_sta(hapd, sta);
+ return;
+ }
+
+ wpa_mesh_set_plink_state(wpa_s, sta, PLINK_LISTEN);
+ sta->my_lid = sta->peer_lid = sta->mpm_close_reason = 0;
+ sta->mpm_retries = 0;
+}
+
+
+static void plink_timer(void *eloop_ctx, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct sta_info *sta = user_data;
+ u16 reason = 0;
+ struct mesh_conf *conf = wpa_s->ifmsh->mconf;
+
+ switch (sta->plink_state) {
+ case PLINK_OPEN_RCVD:
+ case PLINK_OPEN_SENT:
+ /* retry timer */
+ if (sta->mpm_retries < conf->dot11MeshMaxRetries) {
+ eloop_register_timeout(
+ conf->dot11MeshRetryTimeout / 1000,
+ (conf->dot11MeshRetryTimeout % 1000) * 1000,
+ plink_timer, wpa_s, sta);
+ mesh_mpm_send_plink_action(wpa_s, sta, PLINK_OPEN, 0);
+ sta->mpm_retries++;
+ break;
+ }
+ reason = WLAN_REASON_MESH_MAX_RETRIES;
+ /* fall through on else */
+
+ case PLINK_CNF_RCVD:
+ /* confirm timer */
+ if (!reason)
+ reason = WLAN_REASON_MESH_CONFIRM_TIMEOUT;
+ sta->plink_state = PLINK_HOLDING;
+ eloop_register_timeout(conf->dot11MeshHoldingTimeout / 1000,
+ (conf->dot11MeshHoldingTimeout % 1000) * 1000,
+ plink_timer, wpa_s, sta);
+ mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CLOSE, reason);
+ break;
+ case PLINK_HOLDING:
+ /* holding timer */
+ mesh_mpm_fsm_restart(wpa_s, sta);
+ break;
+ default:
+ break;
+ }
+}
+
+
+/* initiate peering with station */
+static void
+mesh_mpm_plink_open(struct wpa_supplicant *wpa_s, struct sta_info *sta,
+ enum mesh_plink_state next_state)
+{
+ struct mesh_conf *conf = wpa_s->ifmsh->mconf;
+
+ eloop_cancel_timeout(plink_timer, wpa_s, sta);
+ eloop_register_timeout(conf->dot11MeshRetryTimeout / 1000,
+ (conf->dot11MeshRetryTimeout % 1000) * 1000,
+ plink_timer, wpa_s, sta);
+ mesh_mpm_send_plink_action(wpa_s, sta, PLINK_OPEN, 0);
+ wpa_mesh_set_plink_state(wpa_s, sta, next_state);
+}
+
+
+int mesh_mpm_plink_close(struct hostapd_data *hapd,
+ struct sta_info *sta, void *ctx)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ int reason = WLAN_REASON_MESH_PEERING_CANCELLED;
+
+ if (sta) {
+ wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
+ mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CLOSE, reason);
+ wpa_printf(MSG_DEBUG, "MPM closing plink sta=" MACSTR,
+ MAC2STR(sta->addr));
+ eloop_cancel_timeout(plink_timer, wpa_s, sta);
+ return 0;
+ }
+
+ return 1;
+}
+
+
+void mesh_mpm_deinit(struct wpa_supplicant *wpa_s, struct hostapd_iface *ifmsh)
+{
+ struct hostapd_data *hapd = ifmsh->bss[0];
+
+ /* notify peers we're leaving */
+ ap_for_each_sta(hapd, mesh_mpm_plink_close, wpa_s);
+
+ hapd->num_plinks = 0;
+ hostapd_free_stas(hapd);
+}
+
+
+/* for mesh_rsn to indicate this peer has completed authentication, and we're
+ * ready to start AMPE */
+void mesh_mpm_auth_peer(struct wpa_supplicant *wpa_s, const u8 *addr)
+{
+ struct hostapd_data *data = wpa_s->ifmsh->bss[0];
+ struct hostapd_sta_add_params params;
+ struct sta_info *sta;
+ int ret;
+
+ sta = ap_get_sta(data, addr);
+ if (!sta) {
+ wpa_msg(wpa_s, MSG_DEBUG, "no such mesh peer");
+ return;
+ }
+
+ /* TODO: Should do nothing if this STA is already authenticated, but
+ * the AP code already sets this flag. */
+ sta->flags |= WLAN_STA_AUTH;
+
+ mesh_rsn_init_ampe_sta(wpa_s, sta);
+
+ os_memset(¶ms, 0, sizeof(params));
+ params.addr = sta->addr;
+ params.flags = WPA_STA_AUTHENTICATED | WPA_STA_AUTHORIZED;
+ params.set = 1;
+
+ wpa_msg(wpa_s, MSG_DEBUG, "MPM authenticating " MACSTR,
+ MAC2STR(sta->addr));
+ ret = wpa_drv_sta_add(wpa_s, ¶ms);
+ if (ret) {
+ wpa_msg(wpa_s, MSG_ERROR,
+ "Driver failed to set " MACSTR ": %d",
+ MAC2STR(sta->addr), ret);
+ }
+
+ if (!sta->my_lid)
+ mesh_mpm_init_link(wpa_s, sta);
+
+ mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
+}
+
+
+void wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
+ struct ieee802_11_elems *elems)
+{
+ struct hostapd_sta_add_params params;
+ struct mesh_conf *conf = wpa_s->ifmsh->mconf;
+ struct hostapd_data *data = wpa_s->ifmsh->bss[0];
+ struct sta_info *sta;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ int ret = 0;
+
+ sta = ap_get_sta(data, addr);
+ if (!sta) {
+ sta = ap_sta_add(data, addr);
+ if (!sta)
+ return;
+ }
+
+ /* initialize sta */
+ if (copy_supp_rates(wpa_s, sta, elems))
+ return;
+
+ mesh_mpm_init_link(wpa_s, sta);
+
+#ifdef CONFIG_IEEE80211N
+ copy_sta_ht_capab(data, sta, elems->ht_capabilities,
+ elems->ht_capabilities_len);
+ update_ht_state(data, sta);
+#endif /* CONFIG_IEEE80211N */
+
+ /* insert into driver */
+ os_memset(¶ms, 0, sizeof(params));
+ params.supp_rates = sta->supported_rates;
+ params.supp_rates_len = sta->supported_rates_len;
+ params.addr = addr;
+ params.plink_state = sta->plink_state;
+ params.aid = sta->peer_lid;
+ params.listen_interval = 100;
+ params.ht_capabilities = sta->ht_capabilities;
+ params.flags |= WPA_STA_WMM;
+ params.flags_mask |= WPA_STA_AUTHENTICATED;
+ if (conf->security == MESH_CONF_SEC_NONE) {
+ params.flags |= WPA_STA_AUTHORIZED;
+ params.flags |= WPA_STA_AUTHENTICATED;
+ } else {
+ sta->flags |= WLAN_STA_MFP;
+ params.flags |= WPA_STA_MFP;
+ }
+
+ ret = wpa_drv_sta_add(wpa_s, ¶ms);
+ if (ret) {
+ wpa_msg(wpa_s, MSG_ERROR,
+ "Driver failed to insert " MACSTR ": %d",
+ MAC2STR(addr), ret);
+ return;
+ }
+
+ if (ssid && ssid->no_auto_peer) {
+ wpa_msg(wpa_s, MSG_INFO, "will not initiate new peer link with "
+ MACSTR " because of no_auto_peer", MAC2STR(addr));
+ if (data->mesh_pending_auth) {
+ struct os_reltime age;
+ const struct ieee80211_mgmt *mgmt;
+ struct hostapd_frame_info fi;
+
+ mgmt = wpabuf_head(data->mesh_pending_auth);
+ os_reltime_age(&data->mesh_pending_auth_time, &age);
+ if (age.sec < 2 &&
+ os_memcmp(mgmt->sa, addr, ETH_ALEN) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "mesh: Process pending Authentication frame from %u.%06u seconds ago",
+ (unsigned int) age.sec,
+ (unsigned int) age.usec);
+ os_memset(&fi, 0, sizeof(fi));
+ ieee802_11_mgmt(
+ data,
+ wpabuf_head(data->mesh_pending_auth),
+ wpabuf_len(data->mesh_pending_auth),
+ &fi);
+ }
+ wpabuf_free(data->mesh_pending_auth);
+ data->mesh_pending_auth = NULL;
+ }
+ return;
+ }
+
+ if (conf->security == MESH_CONF_SEC_NONE)
+ mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
+ else
+ mesh_rsn_auth_sae_sta(wpa_s, sta);
+}
+
+
+void mesh_mpm_mgmt_rx(struct wpa_supplicant *wpa_s, struct rx_mgmt *rx_mgmt)
+{
+ struct hostapd_frame_info fi;
+
+ os_memset(&fi, 0, sizeof(fi));
+ fi.datarate = rx_mgmt->datarate;
+ fi.ssi_signal = rx_mgmt->ssi_signal;
+ ieee802_11_mgmt(wpa_s->ifmsh->bss[0], rx_mgmt->frame,
+ rx_mgmt->frame_len, &fi);
+}
+
+
+static void mesh_mpm_plink_estab(struct wpa_supplicant *wpa_s,
+ struct sta_info *sta)
+{
+ struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+ struct mesh_conf *conf = wpa_s->ifmsh->mconf;
+ u8 seq[6] = {};
+
+ wpa_msg(wpa_s, MSG_INFO, "mesh plink with " MACSTR " established",
+ MAC2STR(sta->addr));
+
+ if (conf->security & MESH_CONF_SEC_AMPE) {
+ wpa_drv_set_key(wpa_s, WPA_ALG_CCMP, sta->addr, 0, 0,
+ seq, sizeof(seq), sta->mtk, sizeof(sta->mtk));
+ wpa_drv_set_key(wpa_s, WPA_ALG_CCMP, sta->addr, 1, 0,
+ seq, sizeof(seq),
+ sta->mgtk, sizeof(sta->mgtk));
+ wpa_drv_set_key(wpa_s, WPA_ALG_IGTK, sta->addr, 4, 0,
+ seq, sizeof(seq),
+ sta->mgtk, sizeof(sta->mgtk));
+
+ wpa_hexdump_key(MSG_DEBUG, "mtk:", sta->mtk, sizeof(sta->mtk));
+ wpa_hexdump_key(MSG_DEBUG, "mgtk:",
+ sta->mgtk, sizeof(sta->mgtk));
+ }
+
+ wpa_mesh_set_plink_state(wpa_s, sta, PLINK_ESTAB);
+ hapd->num_plinks++;
+
+ sta->flags |= WLAN_STA_ASSOC;
+
+ eloop_cancel_timeout(plink_timer, wpa_s, sta);
+
+ /* Send ctrl event */
+ wpa_msg_ctrl(wpa_s, MSG_INFO, MESH_PEER_CONNECTED MACSTR,
+ MAC2STR(sta->addr));
+}
+
+
+static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta,
+ enum plink_event event)
+{
+ struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+ struct mesh_conf *conf = wpa_s->ifmsh->mconf;
+ u16 reason = 0;
+
+ wpa_msg(wpa_s, MSG_DEBUG, "MPM " MACSTR " state %s event %s",
+ MAC2STR(sta->addr), mplstate[sta->plink_state],
+ mplevent[event]);
+
+ switch (sta->plink_state) {
+ case PLINK_LISTEN:
+ switch (event) {
+ case CLS_ACPT:
+ mesh_mpm_fsm_restart(wpa_s, sta);
+ break;
+ case OPN_ACPT:
+ mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_RCVD);
+ mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CONFIRM,
+ 0);
+ break;
+ default:
+ break;
+ }
+ break;
+ case PLINK_OPEN_SENT:
+ switch (event) {
+ case OPN_RJCT:
+ case CNF_RJCT:
+ reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
+ /* fall-through */
+ case CLS_ACPT:
+ wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
+ if (!reason)
+ reason = WLAN_REASON_MESH_CLOSE_RCVD;
+ eloop_register_timeout(
+ conf->dot11MeshHoldingTimeout / 1000,
+ (conf->dot11MeshHoldingTimeout % 1000) * 1000,
+ plink_timer, wpa_s, sta);
+ mesh_mpm_send_plink_action(wpa_s, sta,
+ PLINK_CLOSE, reason);
+ break;
+ case OPN_ACPT:
+ /* retry timer is left untouched */
+ wpa_mesh_set_plink_state(wpa_s, sta, PLINK_OPEN_RCVD);
+ mesh_mpm_send_plink_action(wpa_s, sta,
+ PLINK_CONFIRM, 0);
+ break;
+ case CNF_ACPT:
+ wpa_mesh_set_plink_state(wpa_s, sta, PLINK_CNF_RCVD);
+ eloop_register_timeout(
+ conf->dot11MeshConfirmTimeout / 1000,
+ (conf->dot11MeshConfirmTimeout % 1000) * 1000,
+ plink_timer, wpa_s, sta);
+ break;
+ default:
+ break;
+ }
+ break;
+ case PLINK_OPEN_RCVD:
+ switch (event) {
+ case OPN_RJCT:
+ case CNF_RJCT:
+ reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
+ /* fall-through */
+ case CLS_ACPT:
+ wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
+ if (!reason)
+ reason = WLAN_REASON_MESH_CLOSE_RCVD;
+ eloop_register_timeout(
+ conf->dot11MeshHoldingTimeout / 1000,
+ (conf->dot11MeshHoldingTimeout % 1000) * 1000,
+ plink_timer, wpa_s, sta);
+ sta->mpm_close_reason = reason;
+ mesh_mpm_send_plink_action(wpa_s, sta,
+ PLINK_CLOSE, reason);
+ break;
+ case OPN_ACPT:
+ mesh_mpm_send_plink_action(wpa_s, sta,
+ PLINK_CONFIRM, 0);
+ break;
+ case CNF_ACPT:
+ if (conf->security & MESH_CONF_SEC_AMPE)
+ mesh_rsn_derive_mtk(wpa_s, sta);
+ mesh_mpm_plink_estab(wpa_s, sta);
+ break;
+ default:
+ break;
+ }
+ break;
+ case PLINK_CNF_RCVD:
+ switch (event) {
+ case OPN_RJCT:
+ case CNF_RJCT:
+ reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
+ /* fall-through */
+ case CLS_ACPT:
+ wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
+ if (!reason)
+ reason = WLAN_REASON_MESH_CLOSE_RCVD;
+ eloop_register_timeout(
+ conf->dot11MeshHoldingTimeout / 1000,
+ (conf->dot11MeshHoldingTimeout % 1000) * 1000,
+ plink_timer, wpa_s, sta);
+ sta->mpm_close_reason = reason;
+ mesh_mpm_send_plink_action(wpa_s, sta,
+ PLINK_CLOSE, reason);
+ break;
+ case OPN_ACPT:
+ mesh_mpm_plink_estab(wpa_s, sta);
+ mesh_mpm_send_plink_action(wpa_s, sta,
+ PLINK_CONFIRM, 0);
+ break;
+ default:
+ break;
+ }
+ break;
+ case PLINK_ESTAB:
+ switch (event) {
+ case CLS_ACPT:
+ wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
+ reason = WLAN_REASON_MESH_CLOSE_RCVD;
+
+ eloop_register_timeout(
+ conf->dot11MeshHoldingTimeout / 1000,
+ (conf->dot11MeshHoldingTimeout % 1000) * 1000,
+ plink_timer, wpa_s, sta);
+ sta->mpm_close_reason = reason;
+
+ wpa_msg(wpa_s, MSG_INFO, "mesh plink with " MACSTR
+ " closed with reason %d",
+ MAC2STR(sta->addr), reason);
+
+ wpa_msg_ctrl(wpa_s, MSG_INFO,
+ MESH_PEER_DISCONNECTED MACSTR,
+ MAC2STR(sta->addr));
+
+ hapd->num_plinks--;
+
+ mesh_mpm_send_plink_action(wpa_s, sta,
+ PLINK_CLOSE, reason);
+ break;
+ case OPN_ACPT:
+ mesh_mpm_send_plink_action(wpa_s, sta,
+ PLINK_CONFIRM, 0);
+ break;
+ default:
+ break;
+ }
+ break;
+ case PLINK_HOLDING:
+ switch (event) {
+ case CLS_ACPT:
+ mesh_mpm_fsm_restart(wpa_s, sta);
+ break;
+ case OPN_ACPT:
+ case CNF_ACPT:
+ case OPN_RJCT:
+ case CNF_RJCT:
+ reason = sta->mpm_close_reason;
+ mesh_mpm_send_plink_action(wpa_s, sta,
+ PLINK_CLOSE, reason);
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Unsupported MPM event %s for state %s",
+ mplevent[event], mplstate[sta->plink_state]);
+ break;
+ }
+}
+
+
+void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
+ const struct ieee80211_mgmt *mgmt, size_t len)
+{
+ u8 action_field;
+ struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+ struct mesh_conf *mconf = wpa_s->ifmsh->mconf;
+ struct sta_info *sta;
+ u16 plid = 0, llid = 0;
+ enum plink_event event;
+ struct ieee802_11_elems elems;
+ struct mesh_peer_mgmt_ie peer_mgmt_ie;
+ const u8 *ies;
+ size_t ie_len;
+ int ret;
+
+ if (mgmt->u.action.category != WLAN_ACTION_SELF_PROTECTED)
+ return;
+
+ action_field = mgmt->u.action.u.slf_prot_action.action;
+ if (action_field != PLINK_OPEN &&
+ action_field != PLINK_CONFIRM &&
+ action_field != PLINK_CLOSE)
+ return;
+
+ ies = mgmt->u.action.u.slf_prot_action.variable;
+ ie_len = (const u8 *) mgmt + len -
+ mgmt->u.action.u.slf_prot_action.variable;
+
+ /* at least expect mesh id and peering mgmt */
+ if (ie_len < 2 + 2) {
+ wpa_printf(MSG_DEBUG,
+ "MPM: Ignore too short action frame %u ie_len %u",
+ action_field, (unsigned int) ie_len);
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "MPM: Received PLINK action %u", action_field);
+
+ if (action_field == PLINK_OPEN || action_field == PLINK_CONFIRM) {
+ wpa_printf(MSG_DEBUG, "MPM: Capability 0x%x",
+ WPA_GET_LE16(ies));
+ ies += 2; /* capability */
+ ie_len -= 2;
+ }
+ if (action_field == PLINK_CONFIRM) {
+ wpa_printf(MSG_DEBUG, "MPM: AID 0x%x", WPA_GET_LE16(ies));
+ ies += 2; /* aid */
+ ie_len -= 2;
+ }
+
+ /* check for mesh peering, mesh id and mesh config IEs */
+ if (ieee802_11_parse_elems(ies, ie_len, &elems, 0) == ParseFailed) {
+ wpa_printf(MSG_DEBUG, "MPM: Failed to parse PLINK IEs");
+ return;
+ }
+ if (!elems.peer_mgmt) {
+ wpa_printf(MSG_DEBUG,
+ "MPM: No Mesh Peering Management element");
+ return;
+ }
+ if (action_field != PLINK_CLOSE) {
+ if (!elems.mesh_id || !elems.mesh_config) {
+ wpa_printf(MSG_DEBUG,
+ "MPM: No Mesh ID or Mesh Configuration element");
+ return;
+ }
+
+ if (!matches_local(wpa_s, &elems)) {
+ wpa_printf(MSG_DEBUG,
+ "MPM: Mesh ID or Mesh Configuration element do not match local MBSS");
+ return;
+ }
+ }
+
+ ret = mesh_mpm_parse_peer_mgmt(wpa_s, action_field,
+ elems.peer_mgmt,
+ elems.peer_mgmt_len,
+ &peer_mgmt_ie);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "MPM: Mesh parsing rejected frame");
+ return;
+ }
+
+ /* the sender's llid is our plid and vice-versa */
+ plid = WPA_GET_LE16(peer_mgmt_ie.llid);
+ if (peer_mgmt_ie.plid)
+ llid = WPA_GET_LE16(peer_mgmt_ie.plid);
+ wpa_printf(MSG_DEBUG, "MPM: plid=0x%x llid=0x%x", plid, llid);
+
+ sta = ap_get_sta(hapd, mgmt->sa);
+ if (!sta) {
+ wpa_printf(MSG_DEBUG, "MPM: No STA entry for peer");
+ return;
+ }
+
+#ifdef CONFIG_SAE
+ /* peer is in sae_accepted? */
+ if (sta->sae && sta->sae->state != SAE_ACCEPTED) {
+ wpa_printf(MSG_DEBUG, "MPM: SAE not yet accepted for peer");
+ return;
+ }
+#endif /* CONFIG_SAE */
+
+ if (!sta->my_lid)
+ mesh_mpm_init_link(wpa_s, sta);
+
+ if ((mconf->security & MESH_CONF_SEC_AMPE) &&
+ mesh_rsn_process_ampe(wpa_s, sta, &elems,
+ &mgmt->u.action.category,
+ ies, ie_len)) {
+ wpa_printf(MSG_DEBUG, "MPM: RSN process rejected frame");
+ return;
+ }
+
+ if (sta->plink_state == PLINK_BLOCKED) {
+ wpa_printf(MSG_DEBUG, "MPM: PLINK_BLOCKED");
+ return;
+ }
+
+ /* Now we will figure out the appropriate event... */
+ switch (action_field) {
+ case PLINK_OPEN:
+ if (plink_free_count(hapd) == 0) {
+ event = OPN_IGNR;
+ wpa_printf(MSG_INFO,
+ "MPM: Peer link num over quota(%d)",
+ hapd->max_plinks);
+ } else if (sta->peer_lid && sta->peer_lid != plid) {
+ event = OPN_IGNR;
+ } else {
+ sta->peer_lid = plid;
+ event = OPN_ACPT;
+ }
+ break;
+ case PLINK_CONFIRM:
+ if (plink_free_count(hapd) == 0) {
+ event = CNF_IGNR;
+ wpa_printf(MSG_INFO,
+ "MPM: Peer link num over quota(%d)",
+ hapd->max_plinks);
+ } else if (sta->my_lid != llid ||
+ (sta->peer_lid && sta->peer_lid != plid)) {
+ event = CNF_IGNR;
+ } else {
+ if (!sta->peer_lid)
+ sta->peer_lid = plid;
+ event = CNF_ACPT;
+ }
+ break;
+ case PLINK_CLOSE:
+ if (sta->plink_state == PLINK_ESTAB)
+ /* Do not check for llid or plid. This does not
+ * follow the standard but since multiple plinks
+ * per cand are not supported, it is necessary in
+ * order to avoid a livelock when MP A sees an
+ * establish peer link to MP B but MP B does not
+ * see it. This can be caused by a timeout in
+ * B's peer link establishment or B being
+ * restarted.
+ */
+ event = CLS_ACPT;
+ else if (sta->peer_lid != plid)
+ event = CLS_IGNR;
+ else if (peer_mgmt_ie.plid && sta->my_lid != llid)
+ event = CLS_IGNR;
+ else
+ event = CLS_ACPT;
+ break;
+ default:
+ /*
+ * This cannot be hit due to the action_field check above, but
+ * compilers may not be able to figure that out and can warn
+ * about uninitialized event below.
+ */
+ return;
+ }
+ mesh_mpm_fsm(wpa_s, sta, event);
+}
+
+
+/* called by ap_free_sta */
+void mesh_mpm_free_sta(struct sta_info *sta)
+{
+ eloop_cancel_timeout(plink_timer, ELOOP_ALL_CTX, sta);
+ eloop_cancel_timeout(mesh_auth_timer, ELOOP_ALL_CTX, sta);
+}
diff --git a/wpa_supplicant/mesh_mpm.h b/wpa_supplicant/mesh_mpm.h
new file mode 100644
index 0000000..2f7f6a7
--- /dev/null
+++ b/wpa_supplicant/mesh_mpm.h
@@ -0,0 +1,40 @@
+/*
+ * WPA Supplicant - Basic mesh peer management
+ * Copyright (c) 2013-2014, cozybit, Inc. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MESH_MPM_H
+#define MESH_MPM_H
+
+/* notify MPM of new mesh peer to be inserted in MPM and driver */
+void wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
+ struct ieee802_11_elems *elems);
+void mesh_mpm_deinit(struct wpa_supplicant *wpa_s, struct hostapd_iface *ifmsh);
+void mesh_mpm_auth_peer(struct wpa_supplicant *wpa_s, const u8 *addr);
+void mesh_mpm_free_sta(struct sta_info *sta);
+
+#ifdef CONFIG_MESH
+
+void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
+ const struct ieee80211_mgmt *mgmt, size_t len);
+void mesh_mpm_mgmt_rx(struct wpa_supplicant *wpa_s, struct rx_mgmt *rx_mgmt);
+
+#else /* CONFIG_MESH */
+
+static inline void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
+ const struct ieee80211_mgmt *mgmt,
+ size_t len)
+{
+}
+
+static inline void mesh_mpm_mgmt_rx(struct wpa_supplicant *wpa_s,
+ struct rx_mgmt *rx_mgmt)
+{
+}
+
+#endif /* CONFIG_MESH */
+
+#endif /* MESH_MPM_H */
diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c
new file mode 100644
index 0000000..aee325a
--- /dev/null
+++ b/wpa_supplicant/mesh_rsn.c
@@ -0,0 +1,556 @@
+/*
+ * WPA Supplicant - Mesh RSN routines
+ * Copyright (c) 2013-2014, cozybit, Inc. 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 "utils/eloop.h"
+#include "crypto/sha256.h"
+#include "crypto/random.h"
+#include "crypto/aes.h"
+#include "crypto/aes_siv.h"
+#include "rsn_supp/wpa.h"
+#include "ap/hostapd.h"
+#include "ap/wpa_auth.h"
+#include "ap/sta_info.h"
+#include "ap/ieee802_11.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "wpas_glue.h"
+#include "mesh_mpm.h"
+#include "mesh_rsn.h"
+
+#define MESH_AUTH_TIMEOUT 10
+#define MESH_AUTH_RETRY 3
+
+void mesh_auth_timer(void *eloop_ctx, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct sta_info *sta = user_data;
+
+ if (sta->sae->state != SAE_ACCEPTED) {
+ wpa_printf(MSG_DEBUG, "AUTH: Re-authenticate with " MACSTR
+ " (attempt %d) ",
+ MAC2STR(sta->addr), sta->sae_auth_retry);
+ if (sta->sae_auth_retry < MESH_AUTH_RETRY) {
+ mesh_rsn_auth_sae_sta(wpa_s, sta);
+ } else {
+ /* block the STA if exceeded the number of attempts */
+ sta->plink_state = PLINK_BLOCKED;
+ sta->sae->state = SAE_NOTHING;
+ }
+ sta->sae_auth_retry++;
+ }
+}
+
+
+static void auth_logger(void *ctx, const u8 *addr, logger_level level,
+ const char *txt)
+{
+ if (addr)
+ wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " - %s",
+ MAC2STR(addr), txt);
+ else
+ wpa_printf(MSG_DEBUG, "AUTH: %s", txt);
+}
+
+
+static const u8 *auth_get_psk(void *ctx, const u8 *addr,
+ const u8 *p2p_dev_addr, const u8 *prev_psk)
+{
+ struct mesh_rsn *mesh_rsn = ctx;
+ struct hostapd_data *hapd = mesh_rsn->wpa_s->ifmsh->bss[0];
+ struct sta_info *sta = ap_get_sta(hapd, addr);
+
+ wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)",
+ __func__, MAC2STR(addr), prev_psk);
+
+ if (sta && sta->auth_alg == WLAN_AUTH_SAE) {
+ if (!sta->sae || prev_psk)
+ return NULL;
+ return sta->sae->pmk;
+ }
+
+ return NULL;
+}
+
+
+static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
+ const u8 *addr, int idx, u8 *key, size_t key_len)
+{
+ struct mesh_rsn *mesh_rsn = ctx;
+ u8 seq[6];
+
+ os_memset(seq, 0, sizeof(seq));
+
+ if (addr) {
+ wpa_printf(MSG_DEBUG, "AUTH: %s(alg=%d addr=" MACSTR
+ " key_idx=%d)",
+ __func__, alg, MAC2STR(addr), idx);
+ } else {
+ wpa_printf(MSG_DEBUG, "AUTH: %s(alg=%d key_idx=%d)",
+ __func__, alg, idx);
+ }
+ wpa_hexdump_key(MSG_DEBUG, "AUTH: set_key - key", key, key_len);
+
+ return wpa_drv_set_key(mesh_rsn->wpa_s, alg, addr, idx,
+ 1, seq, 6, key, key_len);
+}
+
+
+static int auth_start_ampe(void *ctx, const u8 *addr)
+{
+ struct mesh_rsn *mesh_rsn = ctx;
+ struct hostapd_data *hapd;
+ struct sta_info *sta;
+
+ if (mesh_rsn->wpa_s->current_ssid->mode != WPAS_MODE_MESH)
+ return -1;
+
+ hapd = mesh_rsn->wpa_s->ifmsh->bss[0];
+ sta = ap_get_sta(hapd, addr);
+ if (sta)
+ eloop_cancel_timeout(mesh_auth_timer, mesh_rsn->wpa_s, sta);
+
+ mesh_mpm_auth_peer(mesh_rsn->wpa_s, addr);
+ return 0;
+}
+
+
+static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr)
+{
+ struct wpa_auth_config conf;
+ struct wpa_auth_callbacks cb;
+ u8 seq[6] = {};
+
+ wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine");
+
+ os_memset(&conf, 0, sizeof(conf));
+ conf.wpa = 2;
+ conf.wpa_key_mgmt = WPA_KEY_MGMT_SAE;
+ conf.wpa_pairwise = WPA_CIPHER_CCMP;
+ conf.rsn_pairwise = WPA_CIPHER_CCMP;
+ conf.wpa_group = WPA_CIPHER_CCMP;
+ conf.eapol_version = 0;
+ conf.wpa_group_rekey = -1;
+
+ os_memset(&cb, 0, sizeof(cb));
+ cb.ctx = rsn;
+ cb.logger = auth_logger;
+ cb.get_psk = auth_get_psk;
+ cb.set_key = auth_set_key;
+ cb.start_ampe = auth_start_ampe;
+
+ rsn->auth = wpa_init(addr, &conf, &cb);
+ if (rsn->auth == NULL) {
+ wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed");
+ return -1;
+ }
+
+ /* TODO: support rekeying */
+ if (random_get_bytes(rsn->mgtk, 16) < 0) {
+ wpa_deinit(rsn->auth);
+ return -1;
+ }
+
+ /* group mgmt */
+ wpa_drv_set_key(rsn->wpa_s, WPA_ALG_IGTK, NULL, 4, 1,
+ seq, sizeof(seq), rsn->mgtk, sizeof(rsn->mgtk));
+
+ /* group privacy / data frames */
+ wpa_drv_set_key(rsn->wpa_s, WPA_ALG_CCMP, NULL, 1, 1,
+ seq, sizeof(seq), rsn->mgtk, sizeof(rsn->mgtk));
+
+ return 0;
+}
+
+
+static void mesh_rsn_deinit(struct mesh_rsn *rsn)
+{
+ os_memset(rsn->mgtk, 0, sizeof(rsn->mgtk));
+ wpa_deinit(rsn->auth);
+}
+
+
+struct mesh_rsn *mesh_rsn_auth_init(struct wpa_supplicant *wpa_s,
+ struct mesh_conf *conf)
+{
+ struct mesh_rsn *mesh_rsn;
+ struct hostapd_data *bss = wpa_s->ifmsh->bss[0];
+ const u8 *ie;
+ size_t ie_len;
+
+ mesh_rsn = os_zalloc(sizeof(*mesh_rsn));
+ if (mesh_rsn == NULL)
+ return NULL;
+ mesh_rsn->wpa_s = wpa_s;
+
+ if (__mesh_rsn_auth_init(mesh_rsn, wpa_s->own_addr) < 0) {
+ mesh_rsn_deinit(mesh_rsn);
+ return NULL;
+ }
+
+ bss->wpa_auth = mesh_rsn->auth;
+
+ ie = wpa_auth_get_wpa_ie(mesh_rsn->auth, &ie_len);
+ conf->ies = (u8 *) ie;
+ conf->ie_len = ie_len;
+
+ wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
+
+ return mesh_rsn;
+}
+
+
+static int index_within_array(const int *array, int idx)
+{
+ int i;
+
+ for (i = 0; i < idx; i++) {
+ if (array[i] == -1)
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static int mesh_rsn_sae_group(struct wpa_supplicant *wpa_s,
+ struct sae_data *sae)
+{
+ int *groups = wpa_s->ifmsh->bss[0]->conf->sae_groups;
+
+ /* Configuration may have changed, so validate current index */
+ if (!index_within_array(groups, wpa_s->mesh_rsn->sae_group_index))
+ return -1;
+
+ for (;;) {
+ int group = groups[wpa_s->mesh_rsn->sae_group_index];
+
+ if (group <= 0)
+ break;
+ if (sae_set_group(sae, group) == 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "SME: Selected SAE group %d",
+ sae->group);
+ return 0;
+ }
+ wpa_s->mesh_rsn->sae_group_index++;
+ }
+
+ return -1;
+}
+
+
+static int mesh_rsn_build_sae_commit(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ struct sta_info *sta)
+{
+ if (ssid->passphrase == NULL) {
+ wpa_msg(wpa_s, MSG_DEBUG, "SAE: No password available");
+ return -1;
+ }
+
+ if (mesh_rsn_sae_group(wpa_s, sta->sae) < 0) {
+ wpa_msg(wpa_s, MSG_DEBUG, "SAE: Failed to select group");
+ return -1;
+ }
+
+ return sae_prepare_commit(wpa_s->own_addr, sta->addr,
+ (u8 *) ssid->passphrase,
+ os_strlen(ssid->passphrase), sta->sae);
+}
+
+
+/* initiate new SAE authentication with sta */
+int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s,
+ struct sta_info *sta)
+{
+ struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ unsigned int rnd;
+ int ret;
+
+ if (!ssid) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "AUTH: No current_ssid known to initiate new SAE");
+ return -1;
+ }
+
+ if (!sta->sae) {
+ sta->sae = os_zalloc(sizeof(*sta->sae));
+ if (sta->sae == NULL)
+ return -1;
+ }
+
+ if (mesh_rsn_build_sae_commit(wpa_s, ssid, sta))
+ return -1;
+
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "AUTH: started authentication with SAE peer: " MACSTR,
+ MAC2STR(sta->addr));
+
+ wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING);
+ ret = auth_sae_init_committed(hapd, sta);
+ if (ret)
+ return ret;
+
+ rnd = rand() % MESH_AUTH_TIMEOUT;
+ eloop_register_timeout(MESH_AUTH_TIMEOUT + rnd, 0, mesh_auth_timer,
+ wpa_s, sta);
+ return 0;
+}
+
+
+void mesh_rsn_get_pmkid(struct mesh_rsn *rsn, struct sta_info *sta, u8 *pmkid)
+{
+ /* don't expect wpa auth to cache the pmkid for now */
+ rsn_pmkid(sta->sae->pmk, PMK_LEN, rsn->wpa_s->own_addr,
+ sta->addr, pmkid,
+ wpa_key_mgmt_sha256(wpa_auth_sta_key_mgmt(sta->wpa_sm)));
+}
+
+
+static void
+mesh_rsn_derive_aek(struct mesh_rsn *rsn, struct sta_info *sta)
+{
+ u8 *myaddr = rsn->wpa_s->own_addr;
+ u8 *peer = sta->addr;
+ u8 *addr1 = peer, *addr2 = myaddr;
+ u8 context[AES_BLOCK_SIZE];
+
+ /* SAE */
+ RSN_SELECTOR_PUT(context, wpa_cipher_to_suite(0, WPA_CIPHER_GCMP));
+
+ if (os_memcmp(myaddr, peer, ETH_ALEN) < 0) {
+ addr1 = myaddr;
+ addr2 = peer;
+ }
+ os_memcpy(context + 4, addr1, ETH_ALEN);
+ os_memcpy(context + 10, addr2, ETH_ALEN);
+
+ sha256_prf(sta->sae->pmk, sizeof(sta->sae->pmk), "AEK Derivation",
+ context, sizeof(context), sta->aek, sizeof(sta->aek));
+}
+
+
+/* derive mesh temporal key from pmk */
+int mesh_rsn_derive_mtk(struct wpa_supplicant *wpa_s, struct sta_info *sta)
+{
+ u8 *ptr;
+ u8 *min, *max;
+ u16 min_lid, max_lid;
+ size_t nonce_len = sizeof(sta->my_nonce);
+ size_t lid_len = sizeof(sta->my_lid);
+ u8 *myaddr = wpa_s->own_addr;
+ u8 *peer = sta->addr;
+ /* 2 nonces, 2 linkids, akm suite, 2 mac addrs */
+ u8 context[64 + 4 + 4 + 12];
+
+ ptr = context;
+ if (os_memcmp(sta->my_nonce, sta->peer_nonce, nonce_len) < 0) {
+ min = sta->my_nonce;
+ max = sta->peer_nonce;
+ } else {
+ min = sta->peer_nonce;
+ max = sta->my_nonce;
+ }
+ os_memcpy(ptr, min, nonce_len);
+ os_memcpy(ptr + nonce_len, max, nonce_len);
+ ptr += 2 * nonce_len;
+
+ if (sta->my_lid < sta->peer_lid) {
+ min_lid = host_to_le16(sta->my_lid);
+ max_lid = host_to_le16(sta->peer_lid);
+ } else {
+ min_lid = host_to_le16(sta->peer_lid);
+ max_lid = host_to_le16(sta->my_lid);
+ }
+ os_memcpy(ptr, &min_lid, lid_len);
+ os_memcpy(ptr + lid_len, &max_lid, lid_len);
+ ptr += 2 * lid_len;
+
+ /* SAE */
+ RSN_SELECTOR_PUT(ptr, wpa_cipher_to_suite(0, WPA_CIPHER_GCMP));
+ ptr += 4;
+
+ if (os_memcmp(myaddr, peer, ETH_ALEN) < 0) {
+ min = myaddr;
+ max = peer;
+ } else {
+ min = peer;
+ max = myaddr;
+ }
+ os_memcpy(ptr, min, ETH_ALEN);
+ os_memcpy(ptr + ETH_ALEN, max, ETH_ALEN);
+
+ sha256_prf(sta->sae->pmk, sizeof(sta->sae->pmk),
+ "Temporal Key Derivation", context, sizeof(context),
+ sta->mtk, sizeof(sta->mtk));
+ return 0;
+}
+
+
+void mesh_rsn_init_ampe_sta(struct wpa_supplicant *wpa_s, struct sta_info *sta)
+{
+ if (random_get_bytes(sta->my_nonce, 32) < 0) {
+ wpa_printf(MSG_INFO, "mesh: Failed to derive random nonce");
+ /* TODO: How to handle this more cleanly? */
+ }
+ os_memset(sta->peer_nonce, 0, 32);
+ mesh_rsn_derive_aek(wpa_s->mesh_rsn, sta);
+}
+
+
+/* insert AMPE and encrypted MIC at @ie.
+ * @mesh_rsn: mesh RSN context
+ * @sta: STA we're sending to
+ * @cat: pointer to category code in frame header.
+ * @buf: wpabuf to add encrypted AMPE and MIC to.
+ * */
+int mesh_rsn_protect_frame(struct mesh_rsn *rsn, struct sta_info *sta,
+ const u8 *cat, struct wpabuf *buf)
+{
+ struct ieee80211_ampe_ie *ampe;
+ u8 const *ie = wpabuf_head_u8(buf) + wpabuf_len(buf);
+ u8 *ampe_ie = NULL, *mic_ie = NULL, *mic_payload;
+ const u8 *aad[] = { rsn->wpa_s->own_addr, sta->addr, cat };
+ const size_t aad_len[] = { ETH_ALEN, ETH_ALEN, ie - cat };
+ int ret = 0;
+
+ if (AES_BLOCK_SIZE + 2 + sizeof(*ampe) + 2 > wpabuf_tailroom(buf)) {
+ wpa_printf(MSG_ERROR, "protect frame: buffer too small");
+ return -EINVAL;
+ }
+
+ ampe_ie = os_zalloc(2 + sizeof(*ampe));
+ if (!ampe_ie) {
+ wpa_printf(MSG_ERROR, "protect frame: out of memory");
+ return -ENOMEM;
+ }
+
+ mic_ie = os_zalloc(2 + AES_BLOCK_SIZE);
+ if (!mic_ie) {
+ wpa_printf(MSG_ERROR, "protect frame: out of memory");
+ ret = -ENOMEM;
+ goto free;
+ }
+
+ /* IE: AMPE */
+ ampe_ie[0] = WLAN_EID_AMPE;
+ ampe_ie[1] = sizeof(*ampe);
+ ampe = (struct ieee80211_ampe_ie *) (ampe_ie + 2);
+
+ RSN_SELECTOR_PUT(ampe->selected_pairwise_suite,
+ wpa_cipher_to_suite(WPA_PROTO_RSN, WPA_CIPHER_CCMP));
+ os_memcpy(ampe->local_nonce, sta->my_nonce, 32);
+ os_memcpy(ampe->peer_nonce, sta->peer_nonce, 32);
+ /* incomplete: see 13.5.4 */
+ /* TODO: static mgtk for now since we don't support rekeying! */
+ os_memcpy(ampe->mgtk, rsn->mgtk, 16);
+ /* TODO: Populate Key RSC */
+ /* expire in 13 decades or so */
+ os_memset(ampe->key_expiration, 0xff, 4);
+
+ /* IE: MIC */
+ mic_ie[0] = WLAN_EID_MIC;
+ mic_ie[1] = AES_BLOCK_SIZE;
+ wpabuf_put_data(buf, mic_ie, 2);
+ /* MIC field is output ciphertext */
+
+ /* encrypt after MIC */
+ mic_payload = (u8 *) wpabuf_put(buf, 2 + sizeof(*ampe) +
+ AES_BLOCK_SIZE);
+
+ if (aes_siv_encrypt(sta->aek, ampe_ie, 2 + sizeof(*ampe), 3,
+ aad, aad_len, mic_payload)) {
+ wpa_printf(MSG_ERROR, "protect frame: failed to encrypt");
+ ret = -ENOMEM;
+ goto free;
+ }
+
+free:
+ os_free(ampe_ie);
+ os_free(mic_ie);
+
+ return ret;
+}
+
+
+int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta,
+ struct ieee802_11_elems *elems, const u8 *cat,
+ const u8 *start, size_t elems_len)
+{
+ int ret = 0;
+ struct ieee80211_ampe_ie *ampe;
+ u8 null_nonce[32] = {};
+ u8 ampe_eid;
+ u8 ampe_ie_len;
+ u8 *ampe_buf, *crypt = NULL;
+ size_t crypt_len;
+ const u8 *aad[] = { sta->addr, wpa_s->own_addr, cat };
+ const size_t aad_len[] = { ETH_ALEN, ETH_ALEN,
+ (elems->mic - 2) - cat };
+
+ if (!elems->mic || elems->mic_len < AES_BLOCK_SIZE) {
+ wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: missing mic ie");
+ return -1;
+ }
+
+ ampe_buf = (u8 *) elems->mic + elems->mic_len;
+ if ((int) elems_len < ampe_buf - start)
+ return -1;
+
+ crypt_len = elems_len - (elems->mic - start);
+ if (crypt_len < 2) {
+ wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: missing ampe ie");
+ return -1;
+ }
+
+ /* crypt is modified by siv_decrypt */
+ crypt = os_zalloc(crypt_len);
+ if (!crypt) {
+ wpa_printf(MSG_ERROR, "Mesh RSN: out of memory");
+ ret = -ENOMEM;
+ goto free;
+ }
+
+ os_memcpy(crypt, elems->mic, crypt_len);
+
+ if (aes_siv_decrypt(sta->aek, crypt, crypt_len, 3,
+ aad, aad_len, ampe_buf)) {
+ wpa_printf(MSG_ERROR, "Mesh RSN: frame verification failed!");
+ ret = -1;
+ goto free;
+ }
+
+ ampe_eid = *ampe_buf++;
+ ampe_ie_len = *ampe_buf++;
+
+ if (ampe_eid != WLAN_EID_AMPE ||
+ ampe_ie_len < sizeof(struct ieee80211_ampe_ie)) {
+ wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: invalid ampe ie");
+ ret = -1;
+ goto free;
+ }
+
+ ampe = (struct ieee80211_ampe_ie *) ampe_buf;
+ if (os_memcmp(ampe->peer_nonce, null_nonce, 32) != 0 &&
+ os_memcmp(ampe->peer_nonce, sta->my_nonce, 32) != 0) {
+ wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: invalid peer nonce");
+ ret = -1;
+ goto free;
+ }
+ os_memcpy(sta->peer_nonce, ampe->local_nonce,
+ sizeof(ampe->local_nonce));
+ os_memcpy(sta->mgtk, ampe->mgtk, sizeof(ampe->mgtk));
+
+ /* todo parse mgtk expiration */
+free:
+ os_free(crypt);
+ return ret;
+}
diff --git a/wpa_supplicant/mesh_rsn.h b/wpa_supplicant/mesh_rsn.h
new file mode 100644
index 0000000..b1471b2
--- /dev/null
+++ b/wpa_supplicant/mesh_rsn.h
@@ -0,0 +1,36 @@
+/*
+ * WPA Supplicant - Mesh RSN routines
+ * Copyright (c) 2013-2014, cozybit, Inc. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MESH_RSN_H
+#define MESH_RSN_H
+
+struct mesh_rsn {
+ struct wpa_supplicant *wpa_s;
+ struct wpa_authenticator *auth;
+ u8 mgtk[16];
+#ifdef CONFIG_SAE
+ struct wpabuf *sae_token;
+ int sae_group_index;
+#endif /* CONFIG_SAE */
+};
+
+struct mesh_rsn * mesh_rsn_auth_init(struct wpa_supplicant *wpa_s,
+ struct mesh_conf *conf);
+int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s, struct sta_info *sta);
+int mesh_rsn_derive_mtk(struct wpa_supplicant *wpa_s, struct sta_info *sta);
+void mesh_rsn_get_pmkid(struct mesh_rsn *rsn, struct sta_info *sta, u8 *pmkid);
+void mesh_rsn_init_ampe_sta(struct wpa_supplicant *wpa_s,
+ struct sta_info *sta);
+int mesh_rsn_protect_frame(struct mesh_rsn *rsn, struct sta_info *sta,
+ const u8 *cat, struct wpabuf *buf);
+int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta,
+ struct ieee802_11_elems *elems, const u8 *cat,
+ const u8 *start, size_t elems_len);
+void mesh_auth_timer(void *eloop_ctx, void *user_data);
+
+#endif /* MESH_RSN_H */
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index 617ce84..bf1836a 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -48,6 +48,9 @@
int wpas_notify_iface_added(struct wpa_supplicant *wpa_s)
{
+ if (wpa_s->p2p_mgmt)
+ return 0;
+
if (wpas_dbus_register_iface(wpa_s))
return -1;
@@ -60,6 +63,9 @@
void wpas_notify_iface_removed(struct wpa_supplicant *wpa_s)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
/* unregister interface in old DBus ctrl iface */
wpas_dbus_unregister_iface(wpa_s);
@@ -72,6 +78,9 @@
enum wpa_states new_state,
enum wpa_states old_state)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
/* notify the old DBus API */
wpa_supplicant_dbus_notify_state_change(wpa_s, new_state,
old_state);
@@ -101,30 +110,45 @@
void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_DISCONNECT_REASON);
}
void wpas_notify_network_changed(struct wpa_supplicant *wpa_s)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_CURRENT_NETWORK);
}
void wpas_notify_ap_scan_changed(struct wpa_supplicant *wpa_s)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_AP_SCAN);
}
void wpas_notify_bssid_changed(struct wpa_supplicant *wpa_s)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_CURRENT_BSS);
}
void wpas_notify_auth_changed(struct wpa_supplicant *wpa_s)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_CURRENT_AUTH_MODE);
}
@@ -132,6 +156,9 @@
void wpas_notify_network_enabled_changed(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_signal_network_enabled_changed(wpa_s, ssid);
}
@@ -139,6 +166,9 @@
void wpas_notify_network_selected(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_signal_network_selected(wpa_s, ssid->id);
}
@@ -148,12 +178,18 @@
enum wpa_ctrl_req_type rtype,
const char *default_txt)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_signal_network_request(wpa_s, ssid, rtype, default_txt);
}
void wpas_notify_scanning(struct wpa_supplicant *wpa_s)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
/* notify the old DBus API */
wpa_supplicant_dbus_notify_scanning(wpa_s);
@@ -164,12 +200,18 @@
void wpas_notify_scan_done(struct wpa_supplicant *wpa_s, int success)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_signal_scan_done(wpa_s, success);
}
void wpas_notify_scan_results(struct wpa_supplicant *wpa_s)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
/* notify the old DBus API */
wpa_supplicant_dbus_notify_scan_results(wpa_s);
@@ -180,6 +222,9 @@
void wpas_notify_wps_credential(struct wpa_supplicant *wpa_s,
const struct wps_credential *cred)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
#ifdef CONFIG_WPS
/* notify the old DBus API */
wpa_supplicant_dbus_notify_wps_cred(wpa_s, cred);
@@ -192,6 +237,9 @@
void wpas_notify_wps_event_m2d(struct wpa_supplicant *wpa_s,
struct wps_event_m2d *m2d)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
#ifdef CONFIG_WPS
wpas_dbus_signal_wps_event_m2d(wpa_s, m2d);
#endif /* CONFIG_WPS */
@@ -201,6 +249,9 @@
void wpas_notify_wps_event_fail(struct wpa_supplicant *wpa_s,
struct wps_event_fail *fail)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
#ifdef CONFIG_WPS
wpas_dbus_signal_wps_event_fail(wpa_s, fail);
#endif /* CONFIG_WPS */
@@ -209,6 +260,9 @@
void wpas_notify_wps_event_success(struct wpa_supplicant *wpa_s)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
#ifdef CONFIG_WPS
wpas_dbus_signal_wps_event_success(wpa_s);
#endif /* CONFIG_WPS */
@@ -218,6 +272,9 @@
void wpas_notify_network_added(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
/*
* Networks objects created during any P2P activities should not be
* exposed out. They might/will confuse certain non-P2P aware
@@ -250,12 +307,18 @@
void wpas_notify_network_removed(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
if (wpa_s->next_ssid == ssid)
wpa_s->next_ssid = NULL;
if (wpa_s->wpa)
wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
if (!ssid->p2p_group && wpa_s->global->p2p_group_formation != wpa_s)
wpas_dbus_unregister_network(wpa_s, ssid->id);
+ if (network_is_persistent_group(ssid))
+ wpas_notify_persistent_group_removed(wpa_s, ssid);
+
wpas_p2p_network_removed(wpa_s, ssid);
}
@@ -263,6 +326,9 @@
void wpas_notify_bss_added(struct wpa_supplicant *wpa_s,
u8 bssid[], unsigned int id)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_register_bss(wpa_s, bssid, id);
wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_BSS_ADDED "%u " MACSTR,
id, MAC2STR(bssid));
@@ -272,6 +338,9 @@
void wpas_notify_bss_removed(struct wpa_supplicant *wpa_s,
u8 bssid[], unsigned int id)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_unregister_bss(wpa_s, bssid, id);
wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_BSS_REMOVED "%u " MACSTR,
id, MAC2STR(bssid));
@@ -281,6 +350,9 @@
void wpas_notify_bss_freq_changed(struct wpa_supplicant *wpa_s,
unsigned int id)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_FREQ, id);
}
@@ -288,6 +360,9 @@
void wpas_notify_bss_signal_changed(struct wpa_supplicant *wpa_s,
unsigned int id)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_SIGNAL,
id);
}
@@ -296,6 +371,9 @@
void wpas_notify_bss_privacy_changed(struct wpa_supplicant *wpa_s,
unsigned int id)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_PRIVACY,
id);
}
@@ -304,6 +382,9 @@
void wpas_notify_bss_mode_changed(struct wpa_supplicant *wpa_s,
unsigned int id)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_MODE, id);
}
@@ -311,6 +392,9 @@
void wpas_notify_bss_wpaie_changed(struct wpa_supplicant *wpa_s,
unsigned int id)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_WPA, id);
}
@@ -318,6 +402,9 @@
void wpas_notify_bss_rsnie_changed(struct wpa_supplicant *wpa_s,
unsigned int id)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_RSN, id);
}
@@ -325,6 +412,9 @@
void wpas_notify_bss_wps_changed(struct wpa_supplicant *wpa_s,
unsigned int id)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
#ifdef CONFIG_WPS
wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_WPS, id);
#endif /* CONFIG_WPS */
@@ -334,6 +424,9 @@
void wpas_notify_bss_ies_changed(struct wpa_supplicant *wpa_s,
unsigned int id)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_IES, id);
}
@@ -341,24 +434,36 @@
void wpas_notify_bss_rates_changed(struct wpa_supplicant *wpa_s,
unsigned int id)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_RATES, id);
}
void wpas_notify_bss_seen(struct wpa_supplicant *wpa_s, unsigned int id)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_AGE, id);
}
void wpas_notify_blob_added(struct wpa_supplicant *wpa_s, const char *name)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_signal_blob_added(wpa_s, name);
}
void wpas_notify_blob_removed(struct wpa_supplicant *wpa_s, const char *name)
{
+ if (wpa_s->p2p_mgmt)
+ return;
+
wpas_dbus_signal_blob_removed(wpa_s, name);
}
@@ -546,7 +651,8 @@
* Create 'peer-joined' signal on group object -- will also
* check P2P itself.
*/
- wpas_dbus_signal_p2p_peer_joined(wpa_s, p2p_dev_addr);
+ if (p2p_dev_addr)
+ wpas_dbus_signal_p2p_peer_joined(wpa_s, p2p_dev_addr);
#endif /* CONFIG_P2P */
/* Notify listeners a new station has been authorized */
@@ -563,7 +669,8 @@
* Create 'peer-disconnected' signal on group object if this
* is a P2P group.
*/
- wpas_dbus_signal_p2p_peer_disconnected(wpa_s, p2p_dev_addr);
+ if (p2p_dev_addr)
+ wpas_dbus_signal_p2p_peer_disconnected(wpa_s, p2p_dev_addr);
#endif /* CONFIG_P2P */
/* Notify listeners a station has been deauthorized */
@@ -583,13 +690,13 @@
void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth,
- const char *subject, const char *cert_hash,
+ const char *subject, const char *altsubject[],
+ int num_altsubject, const char *cert_hash,
const struct wpabuf *cert)
{
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_CERT
"depth=%d subject='%s'%s%s",
- depth, subject,
- cert_hash ? " hash=" : "",
+ depth, subject, cert_hash ? " hash=" : "",
cert_hash ? cert_hash : "");
if (cert) {
@@ -607,11 +714,20 @@
}
}
+ if (altsubject) {
+ int i;
+
+ for (i = 0; i < num_altsubject; i++)
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_ALT
+ "depth=%d %s", depth, altsubject[i]);
+ }
+
/* notify the old DBus API */
wpa_supplicant_dbus_notify_certification(wpa_s, depth, subject,
cert_hash, cert);
/* notify the new DBus API */
- wpas_dbus_signal_certification(wpa_s, depth, subject, cert_hash, cert);
+ wpas_dbus_signal_certification(wpa_s, depth, subject, altsubject,
+ num_altsubject, cert_hash, cert);
}
diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index 7feb530..7fb1f58 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -121,7 +121,8 @@
struct wps_event_fail *fail);
void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth,
- const char *subject, const char *cert_hash,
+ const char *subject, const char *altsubject[],
+ int num_altsubject, const char *cert_hash,
const struct wpabuf *cert);
void wpas_notify_preq(struct wpa_supplicant *wpa_s,
const u8 *addr, const u8 *dst, const u8 *bssid,
diff --git a/wpa_supplicant/offchannel.c b/wpa_supplicant/offchannel.c
index 17689c5..7a86347 100644
--- a/wpa_supplicant/offchannel.c
+++ b/wpa_supplicant/offchannel.c
@@ -31,8 +31,7 @@
*/
iface = wpa_s->global->ifaces;
while (iface) {
- if (os_memcmp(wpa_s->pending_action_src,
- iface->own_addr, ETH_ALEN) == 0)
+ if (os_memcmp(src, iface->own_addr, ETH_ALEN) == 0)
break;
iface = iface->next;
}
@@ -85,6 +84,7 @@
wpa_s->off_channel_freq,
iface->assoc_freq);
if (without_roc && wpa_s->off_channel_freq == 0) {
+ unsigned int duration = 200;
/*
* We may get here if wpas_send_action() found us to be
* on the correct channel, but remain-on-channel cancel
@@ -92,9 +92,18 @@
*/
wpa_printf(MSG_DEBUG, "Off-channel: Schedule "
"remain-on-channel to send Action frame");
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->extra_roc_dur) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: Increase ROC duration %u -> %u",
+ duration,
+ duration + wpa_s->extra_roc_dur);
+ duration += wpa_s->extra_roc_dur;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
if (wpa_drv_remain_on_channel(
- wpa_s, wpa_s->pending_action_freq, 200) <
- 0) {
+ wpa_s, wpa_s->pending_action_freq,
+ duration) < 0) {
wpa_printf(MSG_DEBUG, "Off-channel: Failed to "
"request driver to remain on "
"channel (%u MHz) for Action Frame "
@@ -190,11 +199,13 @@
data, data_len, result);
}
+#ifdef CONFIG_P2P
if (wpa_s->p2p_long_listen > 0) {
/* Continue the listen */
wpa_printf(MSG_DEBUG, "P2P: Continuing long Listen state");
wpas_p2p_listen_start(wpa_s, wpa_s->p2p_long_listen);
}
+#endif /* CONFIG_P2P */
}
@@ -262,8 +273,7 @@
struct wpa_supplicant *iface;
int ret;
- iface = wpas_get_tx_interface(wpa_s,
- wpa_s->pending_action_src);
+ iface = wpas_get_tx_interface(wpa_s, src);
wpa_s->action_tx_wait_time = wait_time;
ret = wpa_drv_send_action(
@@ -315,6 +325,13 @@
wait_time = wpa_s->max_remain_on_chan;
else if (wait_time == 0)
wait_time = 20;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->extra_roc_dur) {
+ wpa_printf(MSG_DEBUG, "TESTING: Increase ROC duration %u -> %u",
+ wait_time, wait_time + wpa_s->extra_roc_dur);
+ wait_time += wpa_s->extra_roc_dur;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
if (wpa_drv_remain_on_channel(wpa_s, freq, wait_time) < 0) {
wpa_printf(MSG_DEBUG, "Off-channel: Failed to request driver "
"to remain on channel (%u MHz) for Action "
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 640154c..65c1b48 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -119,7 +119,7 @@
static void wpas_p2p_group_freq_conflict(void *eloop_ctx, void *timeout_ctx);
static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
int group_added);
-static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s);
+static void wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s);
static void wpas_stop_listen(void *ctx);
static void wpas_p2p_psk_failure_removal(void *eloop_ctx, void *timeout_ctx);
static void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s);
@@ -269,9 +269,11 @@
work->ctx = NULL;
if (ret) {
radio_work_done(work);
+ p2p_notify_scan_trigger_status(wpa_s->global->p2p, ret);
return;
}
+ p2p_notify_scan_trigger_status(wpa_s->global->p2p, ret);
os_get_reltime(&wpa_s->scan_trigger_time);
wpa_s->scan_res_handler = wpas_p2p_scan_res_handler;
wpa_s->own_scan_requested = 1;
@@ -279,6 +281,22 @@
}
+static int wpas_p2p_search_social_channel(struct wpa_supplicant *wpa_s,
+ int freq)
+{
+ if (wpa_s->global->p2p_24ghz_social_channels &&
+ (freq == 2412 || freq == 2437 || freq == 2462)) {
+ /*
+ * Search all social channels regardless of whether these have
+ * been disabled for P2P operating channel use to avoid missing
+ * peers.
+ */
+ return 1;
+ }
+ return p2p_supported_freq(wpa_s->global->p2p, freq);
+}
+
+
static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
unsigned int num_req_dev_types,
const u8 *req_dev_types, const u8 *dev_id, u16 pw_id)
@@ -348,8 +366,8 @@
if (params->freqs == NULL)
goto fail;
for (i = 0; i < ARRAY_SIZE(social_channels_freq); i++) {
- if (p2p_supported_freq(wpa_s->global->p2p,
- social_channels_freq[i]))
+ if (wpas_p2p_search_social_channel(
+ wpa_s, social_channels_freq[i]))
params->freqs[num_channels++] =
social_channels_freq[i];
}
@@ -363,8 +381,8 @@
if (params->freqs == NULL)
goto fail;
for (i = 0; i < ARRAY_SIZE(social_channels_freq); i++) {
- if (p2p_supported_freq(wpa_s->global->p2p,
- social_channels_freq[i]))
+ if (wpas_p2p_search_social_channel(
+ wpa_s, social_channels_freq[i]))
params->freqs[num_channels++] =
social_channels_freq[i];
}
@@ -426,6 +444,37 @@
}
+static void run_wpas_p2p_disconnect(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ wpa_printf(MSG_DEBUG,
+ "P2P: Complete previously requested removal of %s",
+ wpa_s->ifname);
+ wpas_p2p_disconnect(wpa_s);
+}
+
+
+static int wpas_p2p_disconnect_safely(struct wpa_supplicant *wpa_s,
+ struct wpa_supplicant *calling_wpa_s)
+{
+ if (calling_wpa_s == wpa_s && wpa_s &&
+ wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
+ /*
+ * The calling wpa_s instance is going to be removed. Do that
+ * from an eloop callback to keep the instance available until
+ * the caller has returned. This my be needed, e.g., to provide
+ * control interface responses on the per-interface socket.
+ */
+ if (eloop_register_timeout(0, 0, run_wpas_p2p_disconnect,
+ wpa_s, NULL) < 0)
+ return -1;
+ return 0;
+ }
+
+ return wpas_p2p_disconnect(wpa_s);
+}
+
+
static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
enum p2p_group_removal_reason removal_reason)
{
@@ -467,8 +516,17 @@
if (removal_reason != P2P_GROUP_REMOVAL_SILENT && ssid)
wpas_notify_p2p_group_removed(wpa_s, ssid, gtype);
- if (os_strcmp(gtype, "client") == 0)
+ if (os_strcmp(gtype, "client") == 0) {
wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ if (eloop_is_timeout_registered(wpas_p2p_psk_failure_removal,
+ wpa_s, NULL)) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: PSK failure removal was scheduled, so use PSK failure as reason for group removal");
+ removal_reason = P2P_GROUP_REMOVAL_PSK_FAILURE;
+ eloop_cancel_timeout(wpas_p2p_psk_failure_removal,
+ wpa_s, NULL);
+ }
+ }
if (wpa_s->cross_connect_in_use) {
wpa_s->cross_connect_in_use = 0;
@@ -536,6 +594,7 @@
global = wpa_s->global;
ifname = os_strdup(wpa_s->ifname);
type = wpas_p2p_if_type(wpa_s->p2p_group_interface);
+ eloop_cancel_timeout(run_wpas_p2p_disconnect, wpa_s, NULL);
wpa_supplicant_remove_iface(wpa_s->global, wpa_s, 0);
wpa_s = global->ifaces;
if (wpa_s && ifname)
@@ -553,6 +612,10 @@
os_free(wpa_s->go_params);
wpa_s->go_params = NULL;
+ os_free(wpa_s->p2p_group_common_freqs);
+ wpa_s->p2p_group_common_freqs = NULL;
+ wpa_s->p2p_group_common_freqs_num = 0;
+
wpa_s->waiting_presence_resp = 0;
wpa_printf(MSG_DEBUG, "P2P: Remove temporary group network");
@@ -774,7 +837,7 @@
return;
for (i = 0; s->p2p_client_list && i < s->num_p2p_clients; i++) {
- if (os_memcmp(s->p2p_client_list + i * ETH_ALEN, addr,
+ if (os_memcmp(s->p2p_client_list + i * 2 * ETH_ALEN, addr,
ETH_ALEN) != 0)
continue;
@@ -782,32 +845,42 @@
return; /* already the most recent entry */
/* move the entry to mark it most recent */
- os_memmove(s->p2p_client_list + i * ETH_ALEN,
- s->p2p_client_list + (i + 1) * ETH_ALEN,
- (s->num_p2p_clients - i - 1) * ETH_ALEN);
+ os_memmove(s->p2p_client_list + i * 2 * ETH_ALEN,
+ s->p2p_client_list + (i + 1) * 2 * ETH_ALEN,
+ (s->num_p2p_clients - i - 1) * 2 * ETH_ALEN);
os_memcpy(s->p2p_client_list +
- (s->num_p2p_clients - 1) * ETH_ALEN, addr, ETH_ALEN);
+ (s->num_p2p_clients - 1) * 2 * ETH_ALEN, addr,
+ ETH_ALEN);
+ os_memset(s->p2p_client_list +
+ (s->num_p2p_clients - 1) * 2 * ETH_ALEN + ETH_ALEN,
+ 0xff, ETH_ALEN);
found = 1;
break;
}
if (!found && s->num_p2p_clients < P2P_MAX_STORED_CLIENTS) {
n = os_realloc_array(s->p2p_client_list,
- s->num_p2p_clients + 1, ETH_ALEN);
+ s->num_p2p_clients + 1, 2 * ETH_ALEN);
if (n == NULL)
return;
- os_memcpy(n + s->num_p2p_clients * ETH_ALEN, addr, ETH_ALEN);
+ os_memcpy(n + s->num_p2p_clients * 2 * ETH_ALEN, addr,
+ ETH_ALEN);
+ os_memset(n + s->num_p2p_clients * 2 * ETH_ALEN + ETH_ALEN,
+ 0xff, ETH_ALEN);
s->p2p_client_list = n;
s->num_p2p_clients++;
} else if (!found && s->p2p_client_list) {
/* Not enough room for an additional entry - drop the oldest
* entry */
os_memmove(s->p2p_client_list,
- s->p2p_client_list + ETH_ALEN,
- (s->num_p2p_clients - 1) * ETH_ALEN);
+ s->p2p_client_list + 2 * ETH_ALEN,
+ (s->num_p2p_clients - 1) * 2 * ETH_ALEN);
os_memcpy(s->p2p_client_list +
- (s->num_p2p_clients - 1) * ETH_ALEN,
+ (s->num_p2p_clients - 1) * 2 * ETH_ALEN,
addr, ETH_ALEN);
+ os_memset(s->p2p_client_list +
+ (s->num_p2p_clients - 1) * 2 * ETH_ALEN + ETH_ALEN,
+ 0xff, ETH_ALEN);
}
if (wpa_s->parent->conf->update_config &&
@@ -882,6 +955,7 @@
wpa_s->p2p_in_provisioning = 0;
}
wpa_s->p2p_in_invitation = 0;
+ wpa_s->group_formation_reported = 1;
if (!success) {
wpa_msg_global(wpa_s->parent, MSG_INFO,
@@ -1169,6 +1243,7 @@
static void wpas_start_wps_enrollee(struct wpa_supplicant *wpa_s,
struct p2p_go_neg_results *res)
{
+ wpa_s->group_formation_reported = 0;
wpa_printf(MSG_DEBUG, "P2P: Start WPS Enrollee for peer " MACSTR
" dev_addr " MACSTR " wps_method %d",
MAC2STR(res->peer_interface_addr),
@@ -1239,6 +1314,40 @@
}
+static void p2p_go_dump_common_freqs(struct wpa_supplicant *wpa_s)
+{
+ unsigned int i;
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Common group frequencies (len=%u):",
+ wpa_s->p2p_group_common_freqs_num);
+
+ for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++)
+ wpa_dbg(wpa_s, MSG_DEBUG, "freq[%u]: %d",
+ i, wpa_s->p2p_group_common_freqs[i]);
+}
+
+
+static void p2p_go_save_group_common_freqs(struct wpa_supplicant *wpa_s,
+ struct p2p_go_neg_results *params)
+{
+ unsigned int i, len = int_array_len(wpa_s->go_params->freq_list);
+
+ wpa_s->p2p_group_common_freqs_num = 0;
+ os_free(wpa_s->p2p_group_common_freqs);
+ wpa_s->p2p_group_common_freqs = os_calloc(len, sizeof(int));
+ if (!wpa_s->p2p_group_common_freqs)
+ return;
+
+ for (i = 0; i < len; i++) {
+ if (!wpa_s->go_params->freq_list[i])
+ break;
+ wpa_s->p2p_group_common_freqs[i] =
+ wpa_s->go_params->freq_list[i];
+ }
+ wpa_s->p2p_group_common_freqs_num = i;
+}
+
+
static void p2p_go_configured(void *ctx, void *data)
{
struct wpa_supplicant *wpa_s = ctx;
@@ -1246,6 +1355,9 @@
struct wpa_ssid *ssid;
int network_id = -1;
+ p2p_go_save_group_common_freqs(wpa_s, params);
+ p2p_go_dump_common_freqs(wpa_s);
+
ssid = wpa_s->current_ssid;
if (ssid && ssid->mode == WPAS_MODE_P2P_GO) {
wpa_printf(MSG_DEBUG, "P2P: Group setup without provisioning");
@@ -1257,6 +1369,7 @@
params->passphrase,
wpa_s->global->p2p_dev_addr,
params->persistent_group, "");
+ wpa_s->group_formation_reported = 1;
os_get_reltime(&wpa_s->global->p2p_go_wait_client);
if (params->persistent_group) {
@@ -1340,6 +1453,8 @@
}
wpa_s->show_group_started = 0;
+ wpa_s->p2p_go_group_formation_completed = 0;
+ wpa_s->group_formation_reported = 0;
wpa_config_set_network_defaults(ssid);
ssid->temporary = 1;
@@ -1359,6 +1474,15 @@
ssid->key_mgmt = WPA_KEY_MGMT_PSK;
ssid->proto = WPA_PROTO_RSN;
ssid->pairwise_cipher = WPA_CIPHER_CCMP;
+ ssid->group_cipher = WPA_CIPHER_CCMP;
+ if (params->freq > 56160) {
+ /*
+ * Enable GCMP instead of CCMP as pairwise_cipher and
+ * group_cipher in 60 GHz.
+ */
+ ssid->pairwise_cipher = WPA_CIPHER_GCMP;
+ ssid->group_cipher = WPA_CIPHER_GCMP;
+ }
if (os_strlen(params->passphrase) > 0) {
ssid->passphrase = os_strdup(params->passphrase);
if (ssid->passphrase == NULL) {
@@ -1422,6 +1546,7 @@
d->dtim_period = s->dtim_period;
d->disassoc_low_ack = s->disassoc_low_ack;
d->disable_scan_offload = s->disable_scan_offload;
+ d->passive_scan = s->passive_scan;
if (s->wps_nfc_dh_privkey && s->wps_nfc_dh_pubkey) {
d->wps_nfc_dh_privkey = wpabuf_dup(s->wps_nfc_dh_privkey);
@@ -1443,8 +1568,12 @@
os_snprintf(ifname, len, "p2p-%s-%d", ifname_ptr, wpa_s->p2p_group_idx);
if (os_strlen(ifname) >= IFNAMSIZ &&
os_strlen(wpa_s->ifname) < IFNAMSIZ) {
+ int res;
+
/* Try to avoid going over the IFNAMSIZ length limit */
- os_snprintf(ifname, len, "p2p-%d", wpa_s->p2p_group_idx);
+ res = os_snprintf(ifname, len, "p2p-%d", wpa_s->p2p_group_idx);
+ if (os_snprintf_error(len, res) && len)
+ ifname[len - 1] = '\0';
}
}
@@ -1721,7 +1850,7 @@
wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_DEVICE_FOUND MACSTR
" p2p_dev_addr=" MACSTR
" pri_dev_type=%s name='%s' config_methods=0x%x "
- "dev_capab=0x%x group_capab=0x%x%s%s%s",
+ "dev_capab=0x%x group_capab=0x%x%s%s%s new=%d",
MAC2STR(addr), MAC2STR(info->p2p_device_addr),
wps_dev_type_bin2str(info->pri_dev_type, devtype,
sizeof(devtype)),
@@ -1729,7 +1858,8 @@
info->dev_capab, info->group_capab,
wfd_dev_info_hex ? " wfd_dev_info=0x" : "",
wfd_dev_info_hex ? wfd_dev_info_hex : "",
- info->vendor_elems ? " vendor_elems=1" : "");
+ info->vendor_elems ? " vendor_elems=1" : "",
+ new_device);
os_free(wfd_dev_info_hex);
#endif /* CONFIG_NO_STDOUT_DEBUG */
@@ -1790,6 +1920,7 @@
{
struct wpa_supplicant *wpa_s = work->wpa_s;
struct wpas_p2p_listen_work *lwork = work->ctx;
+ unsigned int duration;
if (deinit) {
if (work->started) {
@@ -1814,8 +1945,16 @@
wpa_s->pending_listen_freq = lwork->freq;
wpa_s->pending_listen_duration = lwork->duration;
- if (wpa_drv_remain_on_channel(wpa_s, lwork->freq, lwork->duration) < 0)
- {
+ duration = lwork->duration;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->extra_roc_dur) {
+ wpa_printf(MSG_DEBUG, "TESTING: Increase ROC duration %u -> %u",
+ duration, duration + wpa_s->extra_roc_dur);
+ duration += wpa_s->extra_roc_dur;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (wpa_drv_remain_on_channel(wpa_s, lwork->freq, duration) < 0) {
wpa_printf(MSG_DEBUG, "P2P: Failed to request the driver "
"to remain on channel (%u MHz) for Listen "
"state", lwork->freq);
@@ -2824,6 +2963,7 @@
u8 empty_dev_type[8];
unsigned int generated_pin = 0;
struct wpa_supplicant *group = NULL;
+ int res;
if (group_id) {
for (group = wpa_s->global->ifaces; group; group = group->next)
@@ -2842,15 +2982,17 @@
os_memset(empty_dev_type, 0, sizeof(empty_dev_type));
pri_dev_type = empty_dev_type;
}
- os_snprintf(params, sizeof(params), " p2p_dev_addr=" MACSTR
- " pri_dev_type=%s name='%s' config_methods=0x%x "
- "dev_capab=0x%x group_capab=0x%x%s%s",
- MAC2STR(dev_addr),
- wps_dev_type_bin2str(pri_dev_type, devtype,
- sizeof(devtype)),
- dev_name, supp_config_methods, dev_capab, group_capab,
- group ? " group=" : "",
- group ? group->ifname : "");
+ res = os_snprintf(params, sizeof(params), " p2p_dev_addr=" MACSTR
+ " pri_dev_type=%s name='%s' config_methods=0x%x "
+ "dev_capab=0x%x group_capab=0x%x%s%s",
+ MAC2STR(dev_addr),
+ wps_dev_type_bin2str(pri_dev_type, devtype,
+ sizeof(devtype)),
+ dev_name, supp_config_methods, dev_capab, group_capab,
+ group ? " group=" : "",
+ group ? group->ifname : "");
+ if (os_snprintf_error(sizeof(params), res))
+ wpa_printf(MSG_DEBUG, "P2P: PD Request event truncated");
params[sizeof(params) - 1] = '\0';
if (config_methods & WPS_CONFIG_DISPLAY) {
@@ -2886,10 +3028,14 @@
}
if (wpa_s->pending_pd_use == AUTO_PD_JOIN ||
- wpa_s->pending_pd_use == AUTO_PD_GO_NEG)
- os_snprintf(params, sizeof(params), " peer_go=%d",
- wpa_s->pending_pd_use == AUTO_PD_JOIN);
- else
+ wpa_s->pending_pd_use == AUTO_PD_GO_NEG) {
+ int res;
+
+ res = os_snprintf(params, sizeof(params), " peer_go=%d",
+ wpa_s->pending_pd_use == AUTO_PD_JOIN);
+ if (os_snprintf_error(sizeof(params), res))
+ params[sizeof(params) - 1] = '\0';
+ } else
params[0] = '\0';
if (config_methods & WPS_CONFIG_DISPLAY)
@@ -3013,14 +3159,14 @@
}
#ifdef CONFIG_WPS_NFC
- if (dev_pw_id >= 0 && wpa_s->parent->p2p_nfc_tag_enabled &&
- dev_pw_id == wpa_s->parent->p2p_oob_dev_pw_id) {
+ if (dev_pw_id >= 0 && wpa_s->p2p_nfc_tag_enabled &&
+ dev_pw_id == wpa_s->p2p_oob_dev_pw_id) {
wpa_printf(MSG_DEBUG, "P2P: Accept invitation based on local enabled NFC Tag");
- wpa_s->parent->p2p_wps_method = WPS_NFC;
- wpa_s->parent->pending_join_wps_method = WPS_NFC;
- os_memcpy(wpa_s->parent->pending_join_dev_addr,
+ wpa_s->p2p_wps_method = WPS_NFC;
+ wpa_s->pending_join_wps_method = WPS_NFC;
+ os_memcpy(wpa_s->pending_join_dev_addr,
go_dev_addr, ETH_ALEN);
- os_memcpy(wpa_s->parent->pending_join_iface_addr,
+ os_memcpy(wpa_s->pending_join_iface_addr,
bssid, ETH_ALEN);
goto accept_inv;
}
@@ -3213,7 +3359,7 @@
return;
for (i = 0; ssid->p2p_client_list && i < ssid->num_p2p_clients; i++) {
- if (os_memcmp(ssid->p2p_client_list + i * ETH_ALEN, peer,
+ if (os_memcmp(ssid->p2p_client_list + i * 2 * ETH_ALEN, peer,
ETH_ALEN) == 0)
break;
}
@@ -3233,9 +3379,9 @@
"group %d client list%s",
MAC2STR(peer), ssid->id,
inv ? " due to invitation result" : "");
- os_memmove(ssid->p2p_client_list + i * ETH_ALEN,
- ssid->p2p_client_list + (i + 1) * ETH_ALEN,
- (ssid->num_p2p_clients - i - 1) * ETH_ALEN);
+ os_memmove(ssid->p2p_client_list + i * 2 * ETH_ALEN,
+ ssid->p2p_client_list + (i + 1) * 2 * ETH_ALEN,
+ (ssid->num_p2p_clients - i - 1) * 2 * ETH_ALEN);
ssid->num_p2p_clients--;
if (wpa_s->parent->conf->update_config &&
wpa_config_write(wpa_s->parent->confname, wpa_s->parent->conf))
@@ -3369,6 +3515,8 @@
{
int i, cla = 0;
+ wpa_s->global->p2p_24ghz_social_channels = 1;
+
os_memset(cli_chan, 0, sizeof(*cli_chan));
wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for 2.4 GHz "
@@ -3439,7 +3587,7 @@
enum chan_allowed {
- NOT_ALLOWED, PASSIVE_ONLY, ALLOWED
+ NOT_ALLOWED, NO_IR, ALLOWED
};
static int has_channel(struct wpa_global *global,
@@ -3461,10 +3609,8 @@
(HOSTAPD_CHAN_DISABLED |
HOSTAPD_CHAN_RADAR))
return NOT_ALLOWED;
- if (mode->channels[i].flag &
- (HOSTAPD_CHAN_PASSIVE_SCAN |
- HOSTAPD_CHAN_NO_IBSS))
- return PASSIVE_ONLY;
+ if (mode->channels[i].flag & HOSTAPD_CHAN_NO_IR)
+ return NO_IR;
return ALLOWED;
}
}
@@ -3553,8 +3699,8 @@
res = has_channel(wpa_s->global, mode, adj_chan, &flags);
if (res == NOT_ALLOWED)
return NOT_ALLOWED;
- if (res == PASSIVE_ONLY)
- ret = PASSIVE_ONLY;
+ if (res == NO_IR)
+ ret = NO_IR;
if (i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_70))
return NOT_ALLOWED;
@@ -3592,8 +3738,8 @@
if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
return NOT_ALLOWED;
- if (res == PASSIVE_ONLY || res2 == PASSIVE_ONLY)
- return PASSIVE_ONLY;
+ if (res == NO_IR || res2 == NO_IR)
+ return NO_IR;
return res;
}
@@ -3622,6 +3768,8 @@
mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode);
if (mode == NULL)
continue;
+ if (mode->mode == HOSTAPD_MODE_IEEE80211G)
+ wpa_s->global->p2p_24ghz_social_channels = 1;
for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
enum chan_allowed res;
res = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw);
@@ -3635,7 +3783,7 @@
}
reg->channel[reg->channels] = ch;
reg->channels++;
- } else if (res == PASSIVE_ONLY &&
+ } else if (res == NO_IR &&
wpa_s->conf->p2p_add_cli_chan) {
if (cli_reg == NULL) {
wpa_printf(MSG_DEBUG, "P2P: Add operating class %u (client only)",
@@ -3795,8 +3943,10 @@
char force_name[100];
int ret;
- os_snprintf(ifname, sizeof(ifname), P2P_MGMT_DEVICE_PREFIX "%s",
- wpa_s->ifname);
+ ret = os_snprintf(ifname, sizeof(ifname), P2P_MGMT_DEVICE_PREFIX "%s",
+ wpa_s->ifname);
+ if (os_snprintf_error(sizeof(ifname), ret))
+ return -1;
force_name[0] = '\0';
wpa_s->pending_interface_type = WPA_IF_P2P_DEVICE;
ret = wpa_drv_if_add(wpa_s, WPA_IF_P2P_DEVICE, ifname, NULL, NULL,
@@ -3833,6 +3983,7 @@
return -1;
}
p2pdev_wpa_s->parent = wpa_s;
+ wpa_s->p2p_dev = p2pdev_wpa_s;
wpa_s->pending_interface_name[0] = '\0';
return 0;
@@ -4079,6 +4230,10 @@
wpabuf_free(wpa_s->p2p_oob_dev_pw);
wpa_s->p2p_oob_dev_pw = NULL;
+ os_free(wpa_s->p2p_group_common_freqs);
+ wpa_s->p2p_group_common_freqs = NULL;
+ wpa_s->p2p_group_common_freqs_num = 0;
+
/* TODO: remove group interface from the driver if this wpa_s instance
* is on top of a P2P group interface */
}
@@ -4837,8 +4992,10 @@
os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin));
else if (wps_method == WPS_PIN_DISPLAY) {
ret = wps_generate_pin();
- os_snprintf(wpa_s->p2p_pin, sizeof(wpa_s->p2p_pin), "%08d",
- ret);
+ res = os_snprintf(wpa_s->p2p_pin, sizeof(wpa_s->p2p_pin),
+ "%08d", ret);
+ if (os_snprintf_error(sizeof(wpa_s->p2p_pin), res))
+ wpa_s->p2p_pin[sizeof(wpa_s->p2p_pin) - 1] = '\0';
wpa_printf(MSG_DEBUG, "P2P: Randomly generated PIN: %s",
wpa_s->p2p_pin);
} else
@@ -5007,6 +5164,7 @@
int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname)
{
struct wpa_global *global = wpa_s->global;
+ struct wpa_supplicant *calling_wpa_s = wpa_s;
if (os_strcmp(ifname, "*") == 0) {
struct wpa_supplicant *prev;
@@ -5018,7 +5176,7 @@
NOT_P2P_GROUP_INTERFACE ||
(prev->current_ssid &&
prev->current_ssid->p2p_group))
- wpas_p2p_disconnect(prev);
+ wpas_p2p_disconnect_safely(prev, calling_wpa_s);
}
return 0;
}
@@ -5028,7 +5186,7 @@
break;
}
- return wpas_p2p_disconnect(wpa_s);
+ return wpas_p2p_disconnect_safely(wpa_s, calling_wpa_s);
}
@@ -5438,13 +5596,21 @@
wpa_s->p2p_fallback_to_go_neg = 0;
- if (force_freq > 0) {
- freq = wpas_p2p_select_go_freq(wpa_s, force_freq);
- if (freq < 0)
- return -1;
+ if (ssid->mode == WPAS_MODE_P2P_GO) {
+ if (force_freq > 0) {
+ freq = wpas_p2p_select_go_freq(wpa_s, force_freq);
+ if (freq < 0)
+ return -1;
+ } else {
+ freq = wpas_p2p_select_go_freq(wpa_s, neg_freq);
+ if (freq < 0 ||
+ (freq > 0 && !freq_included(channels, freq)))
+ freq = 0;
+ }
} else {
- freq = wpas_p2p_select_go_freq(wpa_s, neg_freq);
- if (freq < 0 || (freq > 0 && !freq_included(channels, freq)))
+ freq = neg_freq;
+ if (freq < 0 ||
+ (freq > 0 && !freq_included(channels, freq)))
freq = 0;
}
@@ -5478,6 +5644,8 @@
if (wpa_s == NULL)
return -1;
+ p2p_channels_to_freqs(channels, params.freq_list, P2P_MAX_CHANNELS);
+
wpa_s->p2p_first_connection_timeout = connection_timeout;
wpas_start_wps_go(wpa_s, ¶ms, 0);
@@ -5757,7 +5925,29 @@
}
-static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s)
+static void wpas_p2p_scan_res_ignore_search(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
+{
+ wpa_printf(MSG_DEBUG, "P2P: Ignore scan results");
+
+ if (wpa_s->p2p_scan_work) {
+ struct wpa_radio_work *work = wpa_s->p2p_scan_work;
+ wpa_s->p2p_scan_work = NULL;
+ radio_work_done(work);
+ }
+
+ if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+ return;
+
+ /*
+ * Indicate that results have been processed so that the P2P module can
+ * continue pending tasks.
+ */
+ p2p_scan_res_handled(wpa_s->global->p2p);
+}
+
+
+static void wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s)
{
wpas_p2p_clear_pending_action_tx(wpa_s);
wpa_s->p2p_long_listen = 0;
@@ -5767,14 +5957,17 @@
if (wpa_s->global->p2p)
p2p_stop_find(wpa_s->global->p2p);
- return 0;
+ if (wpa_s->scan_res_handler == wpas_p2p_scan_res_handler) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Do not consider the scan results after stop_find");
+ wpa_s->scan_res_handler = wpas_p2p_scan_res_ignore_search;
+ }
}
void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s)
{
- if (wpas_p2p_stop_find_oper(wpa_s) > 0)
- return;
+ wpas_p2p_stop_find_oper(wpa_s);
wpas_p2p_remove_pending_group_interface(wpa_s);
}
@@ -5985,6 +6178,12 @@
pref_freq = 0;
}
+ /*
+ * Stop any find/listen operations before invitation and possibly
+ * connection establishment.
+ */
+ wpas_p2p_stop_find_oper(wpa_s);
+
return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
ssid->ssid, ssid->ssid_len, force_freq, go_dev_addr,
1, pref_freq, -1);
@@ -6100,11 +6299,16 @@
ip_addr[0] = '\0';
if (wpa_sm_get_p2p_ip_addr(wpa_s->wpa, ip) == 0) {
- os_snprintf(ip_addr, sizeof(ip_addr), " ip_addr=%u.%u.%u.%u "
- "ip_mask=%u.%u.%u.%u go_ip_addr=%u.%u.%u.%u",
- ip[0], ip[1], ip[2], ip[3],
- ip[4], ip[5], ip[6], ip[7],
- ip[8], ip[9], ip[10], ip[11]);
+ int res;
+
+ res = os_snprintf(ip_addr, sizeof(ip_addr),
+ " ip_addr=%u.%u.%u.%u "
+ "ip_mask=%u.%u.%u.%u go_ip_addr=%u.%u.%u.%u",
+ ip[0], ip[1], ip[2], ip[3],
+ ip[4], ip[5], ip[6], ip[7],
+ ip[8], ip[9], ip[10], ip[11]);
+ if (os_snprintf_error(sizeof(ip_addr), res))
+ ip_addr[0] = '\0';
}
wpas_p2p_group_started(wpa_s, 0, ssid, freq,
@@ -6546,7 +6750,8 @@
if (iface->drv_flags &
WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE)
continue;
- if (iface->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE)
+ if ((iface->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE) &&
+ iface != wpa_s->parent)
continue;
wpa_s->cross_connect_enabled = 1;
@@ -6859,7 +7064,7 @@
if (s->mode != WPAS_MODE_P2P_GO || s->p2p_client_list == NULL)
continue;
for (i = 0; i < s->num_p2p_clients; i++) {
- if (os_memcmp(s->p2p_client_list + i * ETH_ALEN,
+ if (os_memcmp(s->p2p_client_list + i * 2 * ETH_ALEN,
addr, ETH_ALEN) == 0)
return s; /* peer is P2P client in persistent
* group */
@@ -6885,6 +7090,20 @@
* provisioning step.
*/
wpa_printf(MSG_DEBUG, "P2P: Canceled P2P group formation timeout on data connection");
+
+ if (!wpa_s->p2p_go_group_formation_completed &&
+ !wpa_s->group_formation_reported) {
+ /*
+ * GO has not yet notified group formation success since
+ * the WPS step was not completed cleanly. Do that
+ * notification now since the P2P Client was able to
+ * connect and as such, must have received the
+ * credential from the WPS step.
+ */
+ if (wpa_s->global->p2p)
+ p2p_wps_success_cb(wpa_s->global->p2p, addr);
+ wpas_group_formation_completed(wpa_s, 1);
+ }
}
if (!wpa_s->p2p_go_group_formation_completed) {
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Marking group formation completed on GO on first data connection");
@@ -7573,7 +7792,7 @@
}
len = WPA_GET_BE16(pos);
pos += 2;
- if (pos + len > end) {
+ if (len > end - pos) {
wpa_printf(MSG_DEBUG, "P2P: Not enough data for WSC "
"attributes");
return -1;
@@ -7589,7 +7808,7 @@
}
len = WPA_GET_BE16(pos);
pos += 2;
- if (pos + len > end) {
+ if (len > end - pos) {
wpa_printf(MSG_DEBUG, "P2P: Not enough data for P2P "
"attributes");
return -1;
@@ -7921,8 +8140,6 @@
void wpas_p2p_deinit_iface(struct wpa_supplicant *wpa_s)
{
- if (wpa_s == wpa_s->parent)
- wpas_p2p_group_remove(wpa_s, "*");
if (wpa_s == wpa_s->global->p2p_init_wpa_s && wpa_s->global->p2p) {
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Disable P2P since removing "
"the management interface is being removed");
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 8e23c18..9f5a83b 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -29,7 +29,6 @@
int pd, int ht40, int vht);
int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s,
int freq, struct wpa_ssid *ssid);
-int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname);
int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
int freq, int ht40, int vht);
int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
@@ -171,6 +170,7 @@
int wpas_p2p_wps_eapol_cb(struct wpa_supplicant *wpa_s);
void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
struct wps_event_fail *fail);
+int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname);
#else /* CONFIG_P2P */
@@ -294,6 +294,12 @@
{
}
+static inline int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s,
+ const char *ifname)
+{
+ return 0;
+}
+
#endif /* CONFIG_P2P */
#endif /* P2P_SUPPLICANT_H */
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index debceb9..0653cc2 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -22,6 +22,7 @@
#include "notify.h"
#include "bss.h"
#include "scan.h"
+#include "mesh.h"
static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s)
@@ -167,15 +168,34 @@
wpa_supplicant_notify_scanning(wpa_s, 1);
- if (wpa_s->clear_driver_scan_cache)
+ if (wpa_s->clear_driver_scan_cache) {
+ wpa_printf(MSG_DEBUG,
+ "Request driver to clear scan cache due to local BSS flush");
params->only_new_results = 1;
+ }
ret = wpa_drv_scan(wpa_s, params);
wpa_scan_free_params(params);
work->ctx = NULL;
if (ret) {
+ int retry = wpa_s->last_scan_req != MANUAL_SCAN_REQ;
+
+ if (wpa_s->disconnected)
+ retry = 0;
+
wpa_supplicant_notify_scanning(wpa_s, 0);
wpas_notify_scan_done(wpa_s, 0);
+ if (wpa_s->wpa_state == WPA_SCANNING)
+ wpa_supplicant_set_state(wpa_s,
+ wpa_s->scan_prev_wpa_state);
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_FAILED "ret=%d%s",
+ ret, retry ? " retry=1" : "");
radio_work_done(work);
+
+ if (retry) {
+ /* Restore scan_req since we will try to scan again */
+ wpa_s->scan_req = wpa_s->last_scan_req;
+ wpa_supplicant_req_scan(wpa_s, 1, 0);
+ }
return;
}
@@ -291,7 +311,7 @@
}
if (count == 0)
return NULL;
- ssids = os_zalloc(count * sizeof(struct wpa_driver_scan_filter));
+ ssids = os_calloc(count, sizeof(struct wpa_driver_scan_filter));
if (ssids == NULL)
return NULL;
@@ -319,7 +339,7 @@
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only GO "
"preferred frequency %d MHz",
wpa_s->go_params->freq);
- params->freqs = os_zalloc(2 * sizeof(int));
+ params->freqs = os_calloc(2, sizeof(int));
if (params->freqs)
params->freqs[0] = wpa_s->go_params->freq;
} else if (wpa_s->p2p_in_provisioning < 8 &&
@@ -343,7 +363,7 @@
wpa_s->p2p_invite_go_freq > 0) {
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only GO preferred frequency %d MHz during invitation",
wpa_s->p2p_invite_go_freq);
- params->freqs = os_zalloc(2 * sizeof(int));
+ params->freqs = os_calloc(2, sizeof(int));
if (params->freqs)
params->freqs[0] = wpa_s->p2p_invite_go_freq;
}
@@ -369,7 +389,7 @@
*/
wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Scan only frequency %u MHz "
"that was used during provisioning", wpa_s->wps_freq);
- params->freqs = os_zalloc(2 * sizeof(int));
+ params->freqs = os_calloc(2, sizeof(int));
if (params->freqs)
params->freqs[0] = wpa_s->wps_freq;
wpa_s->after_wps--;
@@ -381,7 +401,7 @@
/* Optimize provisioning scan based on already known channel */
wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Scan only frequency %u MHz",
wpa_s->wps_freq);
- params->freqs = os_zalloc(2 * sizeof(int));
+ params->freqs = os_calloc(2, sizeof(int));
if (params->freqs)
params->freqs[0] = wpa_s->wps_freq;
wpa_s->known_wps_freq = 0; /* only do this once */
@@ -460,6 +480,8 @@
}
#endif /* CONFIG_P2P */
+ wpa_supplicant_mesh_add_scan_ie(wpa_s, &extra_ie);
+
#endif /* CONFIG_WPS */
#ifdef CONFIG_HS20
@@ -528,7 +550,7 @@
return;
}
- params->freqs = os_zalloc((mode->num_channels + 1) * sizeof(int));
+ params->freqs = os_calloc(mode->num_channels + 1, sizeof(int));
if (params->freqs == NULL)
return;
for (count = 0, i = 0; i < mode->num_channels; i++) {
@@ -600,12 +622,11 @@
{
struct wpa_supplicant *wpa_s = eloop_ctx;
struct wpa_ssid *ssid;
- int ret;
+ int ret, p2p_in_prog;
struct wpabuf *extra_ie = NULL;
struct wpa_driver_scan_params params;
struct wpa_driver_scan_params *scan_params;
size_t max_ssids;
- enum wpa_states prev_state;
if (wpa_s->pno || wpa_s->pno_sched_pending) {
wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - PNO is in progress");
@@ -653,7 +674,8 @@
return;
}
- if (wpas_p2p_in_progress(wpa_s)) {
+ p2p_in_prog = wpas_p2p_in_progress(wpa_s);
+ if (p2p_in_prog && p2p_in_prog != 2) {
wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan while P2P operation is in progress");
wpa_supplicant_req_scan(wpa_s, 5, 0);
return;
@@ -672,7 +694,7 @@
os_memset(¶ms, 0, sizeof(params));
- prev_state = wpa_s->wpa_state;
+ wpa_s->scan_prev_wpa_state = wpa_s->wpa_state;
if (wpa_s->wpa_state == WPA_DISCONNECTED ||
wpa_s->wpa_state == WPA_INACTIVE)
wpa_supplicant_set_state(wpa_s, WPA_SCANNING);
@@ -702,7 +724,7 @@
#ifdef CONFIG_P2P
if ((wpa_s->p2p_in_provisioning || wpa_s->show_group_started) &&
- wpa_s->go_params) {
+ wpa_s->go_params && !wpa_s->conf->passive_scan) {
wpa_printf(MSG_DEBUG, "P2P: Use specific SSID for scan during P2P group formation (p2p_in_provisioning=%d show_group_started=%d)",
wpa_s->p2p_in_provisioning,
wpa_s->show_group_started);
@@ -810,7 +832,9 @@
wpa_s->last_scan_req == MANUAL_SCAN_REQ)
wpa_set_scan_ssids(wpa_s, ¶ms, max_ssids);
- for (tssid = wpa_s->conf->ssid; tssid; tssid = tssid->next) {
+ for (tssid = wpa_s->conf->ssid;
+ wpa_s->last_scan_req != MANUAL_SCAN_REQ && tssid;
+ tssid = tssid->next) {
if (wpas_network_disabled(wpa_s, tssid))
continue;
if ((params.freqs || !freqs_set) && tssid->scan_freq) {
@@ -854,6 +878,9 @@
} else if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
wpa_s->manual_scan_passive && params.num_ssids == 0) {
wpa_dbg(wpa_s, MSG_DEBUG, "Use passive scan based on manual request");
+ } else if (wpa_s->conf->passive_scan) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Use passive scan based on configuration");
} else {
wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
params.num_ssids++;
@@ -868,8 +895,11 @@
extra_ie = wpa_supplicant_extra_ies(wpa_s);
if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
- wpa_s->manual_scan_only_new)
+ wpa_s->manual_scan_only_new) {
+ wpa_printf(MSG_DEBUG,
+ "Request driver to clear scan cache due to manual only_new=1 scan");
params.only_new_results = 1;
+ }
if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && params.freqs == NULL &&
wpa_s->manual_scan_freqs) {
@@ -930,6 +960,14 @@
}
#endif /* CONFIG_P2P */
+ if (wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN) {
+ params.mac_addr_rand = 1;
+ if (wpa_s->mac_addr_scan) {
+ params.mac_addr = wpa_s->mac_addr_scan;
+ params.mac_addr_mask = wpa_s->mac_addr_scan + ETH_ALEN;
+ }
+ }
+
scan_params = ¶ms;
scan:
@@ -979,13 +1017,17 @@
if (ret) {
wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate AP scan");
- if (prev_state != wpa_s->wpa_state)
- wpa_supplicant_set_state(wpa_s, prev_state);
+ if (wpa_s->scan_prev_wpa_state != wpa_s->wpa_state)
+ wpa_supplicant_set_state(wpa_s,
+ wpa_s->scan_prev_wpa_state);
/* Restore scan_req since we will try to scan again */
wpa_s->scan_req = wpa_s->last_scan_req;
wpa_supplicant_req_scan(wpa_s, 1, 0);
} else {
wpa_s->scan_for_connection = 0;
+#ifdef CONFIG_INTERWORKING
+ wpa_s->interworking_fast_assoc_tried = 0;
+#endif /* CONFIG_INTERWORKING */
}
}
@@ -1145,7 +1187,7 @@
os_memset(¶ms, 0, sizeof(params));
/* If we can't allocate space for the filters, we just don't filter */
- params.filter_ssids = os_zalloc(wpa_s->max_match_sets *
+ params.filter_ssids = os_calloc(wpa_s->max_match_sets,
sizeof(struct wpa_driver_scan_filter));
prev_state = wpa_s->wpa_state;
@@ -1273,6 +1315,15 @@
wpa_setband_scan_freqs(wpa_s, scan_params);
+ if (wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCHED_SCAN) {
+ params.mac_addr_rand = 1;
+ if (wpa_s->mac_addr_sched_scan) {
+ params.mac_addr = wpa_s->mac_addr_sched_scan;
+ params.mac_addr_mask = wpa_s->mac_addr_sched_scan +
+ ETH_ALEN;
+ }
+ }
+
ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params,
wpa_s->sched_scan_interval);
wpabuf_free(extra_ie);
@@ -1918,6 +1969,23 @@
params->only_new_results = src->only_new_results;
params->low_priority = src->low_priority;
+ if (src->mac_addr_rand) {
+ params->mac_addr_rand = src->mac_addr_rand;
+
+ if (src->mac_addr && src->mac_addr_mask) {
+ u8 *mac_addr;
+
+ mac_addr = os_malloc(2 * ETH_ALEN);
+ if (!mac_addr)
+ goto failed;
+
+ os_memcpy(mac_addr, src->mac_addr, ETH_ALEN);
+ os_memcpy(mac_addr + ETH_ALEN, src->mac_addr_mask,
+ ETH_ALEN);
+ params->mac_addr = mac_addr;
+ params->mac_addr_mask = mac_addr + ETH_ALEN;
+ }
+ }
return params;
failed:
@@ -1938,6 +2006,13 @@
os_free((u8 *) params->extra_ies);
os_free(params->freqs);
os_free(params->filter_ssids);
+
+ /*
+ * Note: params->mac_addr_mask points to same memory allocation and
+ * must not be freed separately.
+ */
+ os_free((u8 *) params->mac_addr);
+
os_free(params);
}
@@ -2042,6 +2117,14 @@
params.freqs = wpa_s->manual_sched_scan_freqs;
}
+ if (wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_PNO) {
+ params.mac_addr_rand = 1;
+ if (wpa_s->mac_addr_pno) {
+ params.mac_addr = wpa_s->mac_addr_pno;
+ params.mac_addr_mask = wpa_s->mac_addr_pno + ETH_ALEN;
+ }
+ }
+
ret = wpa_supplicant_start_sched_scan(wpa_s, ¶ms, interval);
os_free(params.filter_ssids);
if (ret == 0)
@@ -2069,3 +2152,61 @@
return ret;
}
+
+
+void wpas_mac_addr_rand_scan_clear(struct wpa_supplicant *wpa_s,
+ unsigned int type)
+{
+ type &= MAC_ADDR_RAND_ALL;
+ wpa_s->mac_addr_rand_enable &= ~type;
+
+ if (type & MAC_ADDR_RAND_SCAN) {
+ os_free(wpa_s->mac_addr_scan);
+ wpa_s->mac_addr_scan = NULL;
+ }
+
+ if (type & MAC_ADDR_RAND_SCHED_SCAN) {
+ os_free(wpa_s->mac_addr_sched_scan);
+ wpa_s->mac_addr_sched_scan = NULL;
+ }
+
+ if (type & MAC_ADDR_RAND_PNO) {
+ os_free(wpa_s->mac_addr_pno);
+ wpa_s->mac_addr_pno = NULL;
+ }
+}
+
+
+int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s,
+ unsigned int type, const u8 *addr,
+ const u8 *mask)
+{
+ u8 *tmp = NULL;
+
+ wpas_mac_addr_rand_scan_clear(wpa_s, type);
+
+ if (addr) {
+ tmp = os_malloc(2 * ETH_ALEN);
+ if (!tmp)
+ return -1;
+ os_memcpy(tmp, addr, ETH_ALEN);
+ os_memcpy(tmp + ETH_ALEN, mask, ETH_ALEN);
+ }
+
+ if (type == MAC_ADDR_RAND_SCAN) {
+ wpa_s->mac_addr_scan = tmp;
+ } else if (type == MAC_ADDR_RAND_SCHED_SCAN) {
+ wpa_s->mac_addr_sched_scan = tmp;
+ } else if (type == MAC_ADDR_RAND_PNO) {
+ wpa_s->mac_addr_pno = tmp;
+ } else {
+ wpa_printf(MSG_INFO,
+ "scan: Invalid MAC randomization type=0x%x",
+ type);
+ os_free(tmp);
+ return -1;
+ }
+
+ wpa_s->mac_addr_rand_enable |= type;
+ return 0;
+}
diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
index 946d2b3..7650f5a 100644
--- a/wpa_supplicant/scan.h
+++ b/wpa_supplicant/scan.h
@@ -49,4 +49,10 @@
int wpas_start_pno(struct wpa_supplicant *wpa_s);
int wpas_stop_pno(struct wpa_supplicant *wpa_s);
+void wpas_mac_addr_rand_scan_clear(struct wpa_supplicant *wpa_s,
+ unsigned int type);
+int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s,
+ unsigned int type, const u8 *addr,
+ const u8 *mask);
+
#endif /* SCAN_H */
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index e616319..c2b0990 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -137,6 +137,60 @@
#endif /* CONFIG_SAE */
+/**
+ * sme_auth_handle_rrm - Handle RRM aspects of current authentication attempt
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bss: Pointer to the bss which is the target of authentication attempt
+ */
+static void sme_auth_handle_rrm(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss)
+{
+ const u8 rrm_ie_len = 5;
+ u8 *pos;
+ const u8 *rrm_ie;
+
+ wpa_s->rrm.rrm_used = 0;
+
+ wpa_printf(MSG_DEBUG,
+ "RRM: Determining whether RRM can be used - device support: 0x%x",
+ wpa_s->drv_rrm_flags);
+
+ rrm_ie = wpa_bss_get_ie(bss, WLAN_EID_RRM_ENABLED_CAPABILITIES);
+ if (!rrm_ie || !(bss->caps & IEEE80211_CAP_RRM)) {
+ wpa_printf(MSG_DEBUG, "RRM: No RRM in network");
+ return;
+ }
+
+ if (!(wpa_s->drv_rrm_flags &
+ WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES) ||
+ !(wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_QUIET)) {
+ wpa_printf(MSG_DEBUG,
+ "RRM: Insufficient RRM support in driver - do not use RRM");
+ return;
+ }
+
+ if (sizeof(wpa_s->sme.assoc_req_ie) <
+ wpa_s->sme.assoc_req_ie_len + rrm_ie_len + 2) {
+ wpa_printf(MSG_INFO,
+ "RRM: Unable to use RRM, no room for RRM IE");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "RRM: Adding RRM IE to Association Request");
+ pos = wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len;
+ os_memset(pos, 0, 2 + rrm_ie_len);
+ *pos++ = WLAN_EID_RRM_ENABLED_CAPABILITIES;
+ *pos++ = rrm_ie_len;
+
+ /* Set supported capabilites flags */
+ if (wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION)
+ *pos |= WLAN_RRM_CAPS_LINK_MEASUREMENT;
+
+ wpa_s->sme.assoc_req_ie_len += rrm_ie_len + 2;
+ wpa_s->rrm.rrm_used = 1;
+}
+
+
static void sme_send_authentication(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, struct wpa_ssid *ssid,
int start)
@@ -199,17 +253,22 @@
"0x%x", params.auth_alg);
}
#ifdef CONFIG_SAE
+ wpa_s->sme.sae_pmksa_caching = 0;
if (wpa_key_mgmt_sae(ssid->key_mgmt)) {
const u8 *rsn;
struct wpa_ie_data ied;
rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
- if (rsn &&
- wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0) {
- if (wpa_key_mgmt_sae(ied.key_mgmt)) {
- wpa_dbg(wpa_s, MSG_DEBUG, "Using SAE auth_alg");
- params.auth_alg = WPA_AUTH_ALG_SAE;
- }
+ if (!rsn) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "SAE enabled, but target BSS does not advertise RSN");
+ } else if (wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0 &&
+ wpa_key_mgmt_sae(ied.key_mgmt)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Using SAE auth_alg");
+ params.auth_alg = WPA_AUTH_ALG_SAE;
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "SAE enabled, but target BSS does not advertise SAE AKM for RSN");
}
}
#endif /* CONFIG_SAE */
@@ -325,8 +384,7 @@
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211W
- wpa_s->sme.mfp = ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
- wpa_s->conf->pmf : ssid->ieee80211w;
+ wpa_s->sme.mfp = wpas_get_ssid_pmf(wpa_s, ssid);
if (wpa_s->sme.mfp != NO_MGMT_FRAME_PROTECTION) {
const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
struct wpa_ie_data _ie;
@@ -390,7 +448,32 @@
os_memcpy(pos, ext_capab, ext_capab_len);
}
+ if (wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ]) {
+ struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ];
+ size_t len;
+
+ len = sizeof(wpa_s->sme.assoc_req_ie) -
+ wpa_s->sme.assoc_req_ie_len;
+ if (wpabuf_len(buf) <= len) {
+ os_memcpy(wpa_s->sme.assoc_req_ie +
+ wpa_s->sme.assoc_req_ie_len,
+ wpabuf_head(buf), wpabuf_len(buf));
+ wpa_s->sme.assoc_req_ie_len += wpabuf_len(buf);
+ }
+ }
+
+ sme_auth_handle_rrm(wpa_s, bss);
+
#ifdef CONFIG_SAE
+ if (params.auth_alg == WPA_AUTH_ALG_SAE &&
+ pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, ssid, 0) == 0)
+ {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "PMKSA cache entry found - try to use PMKSA caching instead of new SAE authentication");
+ params.auth_alg = WPA_AUTH_ALG_OPEN;
+ wpa_s->sme.sae_pmksa_caching = 1;
+ }
+
if (params.auth_alg == WPA_AUTH_ALG_SAE) {
if (start)
resp = sme_auth_build_sae_commit(wpa_s, ssid,
@@ -398,7 +481,7 @@
else
resp = sme_auth_build_sae_confirm(wpa_s);
if (resp == NULL) {
- wpas_connect_work_done(wpa_s);
+ wpas_connection_failed(wpa_s, bss->bssid);
return;
}
params.sae_data = wpabuf_head(resp);
@@ -545,6 +628,8 @@
static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
u16 status_code, const u8 *data, size_t len)
{
+ int *groups;
+
wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE authentication transaction %u "
"status code %u", auth_transaction, status_code);
@@ -552,10 +637,32 @@
status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ &&
wpa_s->sme.sae.state == SAE_COMMITTED &&
wpa_s->current_bss && wpa_s->current_ssid) {
- wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE anti-clogging token "
- "requested");
+ int default_groups[] = { 19, 20, 21, 25, 26, 0 };
+ u16 group;
+
+ groups = wpa_s->conf->sae_groups;
+ if (!groups || groups[0] <= 0)
+ groups = default_groups;
+
+ if (len < sizeof(le16)) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "SME: Too short SAE anti-clogging token request");
+ return -1;
+ }
+ group = WPA_GET_LE16(data);
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "SME: SAE anti-clogging token requested (group %u)",
+ group);
+ if (sae_group_allowed(&wpa_s->sme.sae, groups, group) !=
+ WLAN_STATUS_SUCCESS) {
+ wpa_dbg(wpa_s, MSG_ERROR,
+ "SME: SAE group %u of anti-clogging request is invalid",
+ group);
+ return -1;
+ }
wpabuf_free(wpa_s->sme.sae_token);
- wpa_s->sme.sae_token = wpabuf_alloc_copy(data, len);
+ wpa_s->sme.sae_token = wpabuf_alloc_copy(data + sizeof(le16),
+ len - sizeof(le16));
sme_send_authentication(wpa_s, wpa_s->current_bss,
wpa_s->current_ssid, 1);
return 0;
@@ -579,7 +686,7 @@
return -1;
if (auth_transaction == 1) {
- int *groups = wpa_s->conf->sae_groups;
+ groups = wpa_s->conf->sae_groups;
wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE commit");
if (wpa_s->current_bss == NULL ||
@@ -668,7 +775,8 @@
wpa_printf(MSG_DEBUG, "SME: SAE completed - setting PMK for "
"4-way handshake");
- wpa_sm_set_pmk(wpa_s->wpa, wpa_s->sme.sae.pmk, PMK_LEN);
+ wpa_sm_set_pmk(wpa_s->wpa, wpa_s->sme.sae.pmk, PMK_LEN,
+ wpa_s->pending_bssid);
}
#endif /* CONFIG_SAE */
@@ -775,6 +883,7 @@
#endif /* CONFIG_IEEE80211R */
params.mode = mode;
params.mgmt_frame_protection = wpa_s->sme.mfp;
+ params.rrm_used = wpa_s->rrm.rrm_used;
if (wpa_s->sme.prev_bssid_set)
params.prev_bssid = wpa_s->sme.prev_bssid;
@@ -882,6 +991,27 @@
eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL);
+#ifdef CONFIG_SAE
+ if (wpa_s->sme.sae_pmksa_caching && wpa_s->current_ssid &&
+ wpa_key_mgmt_sae(wpa_s->current_ssid->key_mgmt)) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "PMKSA caching attempt rejected - drop PMKSA cache entry and fall back to SAE authentication");
+ wpa_sm_aborted_cached(wpa_s->wpa);
+ wpa_sm_pmksa_cache_flush(wpa_s->wpa, wpa_s->current_ssid);
+ if (wpa_s->current_bss) {
+ struct wpa_bss *bss = wpa_s->current_bss;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+ wpa_drv_deauthenticate(wpa_s, wpa_s->pending_bssid,
+ WLAN_REASON_DEAUTH_LEAVING);
+ wpas_connect_work_done(wpa_s);
+ wpa_supplicant_mark_disassoc(wpa_s);
+ wpa_supplicant_connect(wpa_s, bss, ssid);
+ return;
+ }
+ }
+#endif /* CONFIG_SAE */
+
/*
* For now, unconditionally terminate the previous authentication. In
* theory, this should not be needed, but mac80211 gets quite confused
@@ -982,6 +1112,21 @@
}
+void sme_clear_on_disassoc(struct wpa_supplicant *wpa_s)
+{
+ wpa_s->sme.prev_bssid_set = 0;
+#ifdef CONFIG_SAE
+ wpabuf_free(wpa_s->sme.sae_token);
+ wpa_s->sme.sae_token = NULL;
+ sae_clear_data(&wpa_s->sme.sae);
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_IEEE80211R
+ if (wpa_s->sme.ft_ies)
+ sme_update_ft_ies(wpa_s, NULL, NULL, 0);
+#endif /* CONFIG_IEEE80211R */
+}
+
+
void sme_deinit(struct wpa_supplicant *wpa_s)
{
os_free(wpa_s->sme.ft_ies);
@@ -990,11 +1135,7 @@
#ifdef CONFIG_IEEE80211W
sme_stop_sa_query(wpa_s);
#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_SAE
- wpabuf_free(wpa_s->sme.sae_token);
- wpa_s->sme.sae_token = NULL;
- sae_clear_data(&wpa_s->sme.sae);
-#endif /* CONFIG_SAE */
+ sme_clear_on_disassoc(wpa_s);
eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL);
eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
@@ -1136,28 +1277,72 @@
}
-static void wpa_setband_scan_freqs_list(struct wpa_supplicant *wpa_s,
- enum hostapd_hw_mode band,
- struct wpa_driver_scan_params *params)
+static void wpa_obss_scan_freqs_list(struct wpa_supplicant *wpa_s,
+ struct wpa_driver_scan_params *params)
{
- /* Include only supported channels for the specified band */
+ /* Include only affected channels */
struct hostapd_hw_modes *mode;
int count, i;
+ int start, end;
- mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band);
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
+ HOSTAPD_MODE_IEEE80211G);
if (mode == NULL) {
/* No channels supported in this band - use empty list */
params->freqs = os_zalloc(sizeof(int));
return;
}
+ if (wpa_s->sme.ht_sec_chan == HT_SEC_CHAN_UNKNOWN &&
+ wpa_s->current_bss) {
+ const u8 *ie;
+
+ ie = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_HT_OPERATION);
+ if (ie && ie[1] >= 2) {
+ u8 o;
+
+ o = ie[3] & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK;
+ if (o == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
+ wpa_s->sme.ht_sec_chan = HT_SEC_CHAN_ABOVE;
+ else if (o == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
+ wpa_s->sme.ht_sec_chan = HT_SEC_CHAN_BELOW;
+ }
+ }
+
+ start = wpa_s->assoc_freq - 10;
+ end = wpa_s->assoc_freq + 10;
+ switch (wpa_s->sme.ht_sec_chan) {
+ case HT_SEC_CHAN_UNKNOWN:
+ /* HT40+ possible on channels 1..9 */
+ if (wpa_s->assoc_freq <= 2452)
+ start -= 20;
+ /* HT40- possible on channels 5-13 */
+ if (wpa_s->assoc_freq >= 2432)
+ end += 20;
+ break;
+ case HT_SEC_CHAN_ABOVE:
+ end += 20;
+ break;
+ case HT_SEC_CHAN_BELOW:
+ start -= 20;
+ break;
+ }
+ wpa_printf(MSG_DEBUG,
+ "OBSS: assoc_freq %d possible affected range %d-%d",
+ wpa_s->assoc_freq, start, end);
+
params->freqs = os_calloc(mode->num_channels + 1, sizeof(int));
if (params->freqs == NULL)
return;
for (count = 0, i = 0; i < mode->num_channels; i++) {
+ int freq;
+
if (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED)
continue;
- params->freqs[count++] = mode->channels[i].freq;
+ freq = mode->channels[i].freq;
+ if (freq - 10 >= end || freq + 10 <= start)
+ continue; /* not affected */
+ params->freqs[count++] = freq;
}
}
@@ -1173,7 +1358,7 @@
}
os_memset(¶ms, 0, sizeof(params));
- wpa_setband_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, ¶ms);
+ wpa_obss_scan_freqs_list(wpa_s, ¶ms);
params.low_priority = 1;
wpa_printf(MSG_DEBUG, "SME OBSS: Request an OBSS scan");
@@ -1198,6 +1383,7 @@
eloop_cancel_timeout(sme_obss_scan_timeout, wpa_s, NULL);
wpa_s->sme.sched_obss_scan = 0;
+ wpa_s->sme.ht_sec_chan = HT_SEC_CHAN_UNKNOWN;
if (!enable)
return;
@@ -1360,9 +1546,7 @@
if (wpa_s->wpa_state != WPA_COMPLETED)
return;
ssid = wpa_s->current_ssid;
- if (ssid == NULL ||
- (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
- wpa_s->conf->pmf : ssid->ieee80211w) == NO_MGMT_FRAME_PROTECTION)
+ if (wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION)
return;
if (os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0)
return;
diff --git a/wpa_supplicant/sme.h b/wpa_supplicant/sme.h
index 04404c1..fd5c3b4 100644
--- a/wpa_supplicant/sme.h
+++ b/wpa_supplicant/sme.h
@@ -33,6 +33,7 @@
void sme_state_changed(struct wpa_supplicant *wpa_s);
void sme_disassoc_while_authenticating(struct wpa_supplicant *wpa_s,
const u8 *prev_pending_bssid);
+void sme_clear_on_disassoc(struct wpa_supplicant *wpa_s);
void sme_deinit(struct wpa_supplicant *wpa_s);
int sme_proc_obss_scan(struct wpa_supplicant *wpa_s);
@@ -94,6 +95,10 @@
{
}
+static inline void sme_clear_on_disassoc(struct wpa_supplicant *wpa_s)
+{
+}
+
static inline void sme_deinit(struct wpa_supplicant *wpa_s)
{
}
diff --git a/wpa_supplicant/todo.txt b/wpa_supplicant/todo.txt
index b84cccc..4c9f98e 100644
--- a/wpa_supplicant/todo.txt
+++ b/wpa_supplicant/todo.txt
@@ -5,8 +5,6 @@
authentication has been completed (cache scard data based on serial#(?)
and try to optimize next connection if the same card is present for next
auth)
-- on disconnect event, could try to associate with another AP if one is
- present in scan results; would need to update scan results periodically..
- if driver/hw is not WPA2 capable, must remove WPA_PROTO_RSN flag from
ssid->proto fields to avoid detecting downgrade attacks when the driver
is not reporting RSN IE, but msg 3/4 has one
@@ -24,14 +22,12 @@
RFC 3748 Sect. 4.2
- test compilation with gcc -W options (more warnings?)
(Done once; number of unused function arguments still present)
-- add proper support for using dot11RSNAConfigSATimeout
-- ctrl_iface: get/set/remove blob
+- ctrl_iface: get/remove blob
- use doc/docbook/*.sgml and docbook2{txt,html,pdf} to replace README and
web pages including the same information.. i.e., have this information only
in one page; how to build a PDF file with all the SGML included?
- EAP-POTP/RSA SecurID profile (RFC 4793)
- document wpa_gui build and consider adding it to 'make install'
-- test madwifi with pairwise=TKIP group=WEP104
- consider merging hostapd and wpa_supplicant PMKSA cache implementations
- consider redesigning pending EAP requests (identity/password/otp from
ctrl_iface) by moving the retrying of the previous request into EAP
@@ -57,14 +53,11 @@
- try to work around race in configuring PTK and sending msg 4/4 (some NDIS
drivers with ndiswrapper end up not being able to complete 4-way handshake
in some cases; extra delay before setting the key seems to help)
-- add wpa_secure_memzero() macro and secure implementation (volatile u8*) to
- clear memory; this would be used to clear temporary buffers containing
- private data (e.g., keys); the macro can be defined to NOP in order to save
- space (i.e., no code should depend on the macro doing something)
- make sure that TLS session cache is not shared between EAP types or if it
is, that the cache entries are bound to only one EAP type; e.g., cache entry
created with EAP-TLS must not be allowed to do fast re-auth with EAP-TTLS
-- consider moving eap_tls_build_ack() call into eap_tls_process_helper()
+- consider moving eap_peer_tls_build_ack() call into
+ eap_peer_tls_process_helper()
(it seems to be called always if helper returns 1)
* could need to modify eap_{ttls,peap,fast}_decrypt to do same
- add support for fetching full user cert chain from Windows certificate
diff --git a/wpa_supplicant/wifi_display.c b/wpa_supplicant/wifi_display.c
index 6dc41de..c363b21 100644
--- a/wpa_supplicant/wifi_display.c
+++ b/wpa_supplicant/wifi_display.c
@@ -233,15 +233,31 @@
if (pos == NULL)
return -1;
*pos++ = '\0';
- subelem = atoi(cmd);
- if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS)
- return -1;
len = os_strlen(pos);
if (len & 1)
return -1;
len /= 2;
+ if (os_strcmp(cmd, "all") == 0) {
+ int res;
+
+ e = wpabuf_alloc(len);
+ if (e == NULL)
+ return -1;
+ if (hexstr2bin(pos, wpabuf_put(e, len), len) < 0) {
+ wpabuf_free(e);
+ return -1;
+ }
+ res = wifi_display_subelem_set_from_ies(global, e);
+ wpabuf_free(e);
+ return res;
+ }
+
+ subelem = atoi(cmd);
+ if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS)
+ return -1;
+
if (len == 0) {
/* Clear subelement */
e = NULL;
@@ -271,7 +287,7 @@
{
int subelements[MAX_WFD_SUBELEMS] = {};
const u8 *pos, *end;
- int len, subelem;
+ unsigned int len, subelem;
struct wpabuf *e;
wpa_printf(MSG_DEBUG, "WFD IEs set: %p - %lu",
@@ -292,7 +308,7 @@
wpa_printf(MSG_DEBUG, "WFD Sub-Element ID %d - len %d",
*pos, len - 3);
- if (pos + len > end)
+ if (len > (unsigned int) (end - pos))
break;
subelem = *pos;
@@ -325,6 +341,19 @@
{
int subelem;
+ if (os_strcmp(cmd, "all") == 0) {
+ struct wpabuf *ie;
+ int res;
+
+ ie = wifi_display_get_wfd_ie(global);
+ if (ie == NULL)
+ return 0;
+ res = wpa_snprintf_hex(buf, buflen, wpabuf_head(ie),
+ wpabuf_len(ie));
+ wpabuf_free(ie);
+ return res;
+ }
+
subelem = atoi(cmd);
if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS)
return -1;
diff --git a/wpa_supplicant/wmm_ac.c b/wpa_supplicant/wmm_ac.c
new file mode 100644
index 0000000..5625d36
--- /dev/null
+++ b/wpa_supplicant/wmm_ac.c
@@ -0,0 +1,995 @@
+/*
+ * Wi-Fi Multimedia Admission Control (WMM-AC)
+ * Copyright(c) 2014, Intel Mobile Communication GmbH.
+ * Copyright(c) 2014, Intel Corporation. All rights reserved.
+ *
+ * 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 "utils/list.h"
+#include "utils/eloop.h"
+#include "common/ieee802_11_common.h"
+#include "wpa_supplicant_i.h"
+#include "bss.h"
+#include "driver_i.h"
+#include "wmm_ac.h"
+
+static void wmm_ac_addts_req_timeout(void *eloop_ctx, void *timeout_ctx);
+
+static const enum wmm_ac up_to_ac[8] = {
+ WMM_AC_BK,
+ WMM_AC_BE,
+ WMM_AC_BE,
+ WMM_AC_BK,
+ WMM_AC_VI,
+ WMM_AC_VI,
+ WMM_AC_VO,
+ WMM_AC_VO
+};
+
+
+static inline u8 wmm_ac_get_tsid(const struct wmm_tspec_element *tspec)
+{
+ return (tspec->ts_info[0] >> 1) & 0x0f;
+}
+
+
+static u8 wmm_ac_get_direction(const struct wmm_tspec_element *tspec)
+{
+ return (tspec->ts_info[0] >> 5) & 0x03;
+}
+
+
+static u8 wmm_ac_get_user_priority(const struct wmm_tspec_element *tspec)
+{
+ return (tspec->ts_info[1] >> 3) & 0x07;
+}
+
+
+static u8 wmm_ac_direction_to_idx(u8 direction)
+{
+ switch (direction) {
+ case WMM_AC_DIR_UPLINK:
+ return TS_DIR_IDX_UPLINK;
+ case WMM_AC_DIR_DOWNLINK:
+ return TS_DIR_IDX_DOWNLINK;
+ case WMM_AC_DIR_BIDIRECTIONAL:
+ return TS_DIR_IDX_BIDI;
+ default:
+ wpa_printf(MSG_ERROR, "Invalid direction: %d", direction);
+ return WMM_AC_DIR_UPLINK;
+ }
+}
+
+
+static int wmm_ac_add_ts(struct wpa_supplicant *wpa_s, const u8 *addr,
+ const struct wmm_tspec_element *tspec)
+{
+ struct wmm_tspec_element *_tspec;
+ int ret;
+ u16 admitted_time = le_to_host16(tspec->medium_time);
+ u8 up = wmm_ac_get_user_priority(tspec);
+ u8 ac = up_to_ac[up];
+ u8 dir = wmm_ac_get_direction(tspec);
+ u8 tsid = wmm_ac_get_tsid(tspec);
+ enum ts_dir_idx idx = wmm_ac_direction_to_idx(dir);
+
+ /* should have been verified before, but double-check here */
+ if (wpa_s->tspecs[ac][idx]) {
+ wpa_printf(MSG_ERROR,
+ "WMM AC: tspec (ac=%d, dir=%d) already exists!",
+ ac, dir);
+ return -1;
+ }
+
+ /* copy tspec */
+ _tspec = os_malloc(sizeof(*_tspec));
+ if (!_tspec)
+ return -1;
+
+ /* store the admitted TSPEC */
+ os_memcpy(_tspec, tspec, sizeof(*_tspec));
+
+ if (dir != WMM_AC_DIR_DOWNLINK) {
+ ret = wpa_drv_add_ts(wpa_s, tsid, addr, up, admitted_time);
+ wpa_printf(MSG_DEBUG,
+ "WMM AC: Add TS: addr=" MACSTR
+ " TSID=%u admitted time=%u, ret=%d",
+ MAC2STR(addr), tsid, admitted_time, ret);
+ if (ret < 0) {
+ os_free(_tspec);
+ return -1;
+ }
+ }
+
+ wpa_s->tspecs[ac][idx] = _tspec;
+
+ wpa_printf(MSG_DEBUG, "Traffic stream was created successfully");
+
+ wpa_msg(wpa_s, MSG_INFO, WMM_AC_EVENT_TSPEC_ADDED
+ "tsid=%d addr=" MACSTR " admitted_time=%d",
+ tsid, MAC2STR(addr), admitted_time);
+
+ return 0;
+}
+
+
+static void wmm_ac_del_ts_idx(struct wpa_supplicant *wpa_s, u8 ac,
+ enum ts_dir_idx dir)
+{
+ struct wmm_tspec_element *tspec = wpa_s->tspecs[ac][dir];
+ u8 tsid;
+
+ if (!tspec)
+ return;
+
+ tsid = wmm_ac_get_tsid(tspec);
+ wpa_printf(MSG_DEBUG, "WMM AC: Del TS ac=%d tsid=%d", ac, tsid);
+
+ /* update the driver in case of uplink/bidi */
+ if (wmm_ac_get_direction(tspec) != WMM_AC_DIR_DOWNLINK)
+ wpa_drv_del_ts(wpa_s, tsid, wpa_s->bssid);
+
+ wpa_msg(wpa_s, MSG_INFO, WMM_AC_EVENT_TSPEC_REMOVED
+ "tsid=%d addr=" MACSTR, tsid, MAC2STR(wpa_s->bssid));
+
+ os_free(wpa_s->tspecs[ac][dir]);
+ wpa_s->tspecs[ac][dir] = NULL;
+}
+
+
+static void wmm_ac_del_req(struct wpa_supplicant *wpa_s, int failed)
+{
+ struct wmm_ac_addts_request *req = wpa_s->addts_request;
+
+ if (!req)
+ return;
+
+ if (failed)
+ wpa_msg(wpa_s, MSG_INFO, WMM_AC_EVENT_TSPEC_REQ_FAILED
+ "tsid=%u", wmm_ac_get_tsid(&req->tspec));
+
+ eloop_cancel_timeout(wmm_ac_addts_req_timeout, wpa_s, req);
+ wpa_s->addts_request = NULL;
+ os_free(req);
+}
+
+
+static void wmm_ac_addts_req_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct wmm_ac_addts_request *addts_req = timeout_ctx;
+
+ wpa_printf(MSG_DEBUG,
+ "Timeout getting ADDTS response (tsid=%d up=%d)",
+ wmm_ac_get_tsid(&addts_req->tspec),
+ wmm_ac_get_user_priority(&addts_req->tspec));
+
+ wmm_ac_del_req(wpa_s, 1);
+}
+
+
+static int wmm_ac_send_addts_request(struct wpa_supplicant *wpa_s,
+ const struct wmm_ac_addts_request *req)
+{
+ struct wpabuf *buf;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "Sending ADDTS Request to " MACSTR,
+ MAC2STR(req->address));
+
+ /* category + action code + dialog token + status + sizeof(tspec) */
+ buf = wpabuf_alloc(4 + sizeof(req->tspec));
+ if (!buf) {
+ wpa_printf(MSG_ERROR, "WMM AC: Allocation error");
+ return -1;
+ }
+
+ wpabuf_put_u8(buf, WLAN_ACTION_WMM);
+ wpabuf_put_u8(buf, WMM_ACTION_CODE_ADDTS_REQ);
+ wpabuf_put_u8(buf, req->dialog_token);
+ wpabuf_put_u8(buf, 0); /* status code */
+ wpabuf_put_data(buf, &req->tspec, sizeof(req->tspec));
+
+ ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, req->address,
+ wpa_s->own_addr, wpa_s->bssid,
+ wpabuf_head(buf), wpabuf_len(buf), 0);
+ if (ret) {
+ wpa_printf(MSG_WARNING,
+ "WMM AC: Failed to send ADDTS Request");
+ }
+
+ wpabuf_free(buf);
+ return ret;
+}
+
+
+static int wmm_ac_send_delts(struct wpa_supplicant *wpa_s,
+ const struct wmm_tspec_element *tspec,
+ const u8 *address)
+{
+ struct wpabuf *buf;
+ int ret;
+
+ /* category + action code + dialog token + status + sizeof(tspec) */
+ buf = wpabuf_alloc(4 + sizeof(*tspec));
+ if (!buf)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "Sending DELTS to " MACSTR, MAC2STR(address));
+
+ /* category + action code + dialog token + status + sizeof(tspec) */
+ wpabuf_put_u8(buf, WLAN_ACTION_WMM);
+ wpabuf_put_u8(buf, WMM_ACTION_CODE_DELTS);
+ wpabuf_put_u8(buf, 0); /* Dialog Token (not used) */
+ wpabuf_put_u8(buf, 0); /* Status Code (not used) */
+ wpabuf_put_data(buf, tspec, sizeof(*tspec));
+
+ ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, address,
+ wpa_s->own_addr, wpa_s->bssid,
+ wpabuf_head(buf), wpabuf_len(buf), 0);
+ if (ret)
+ wpa_printf(MSG_WARNING, "Failed to send DELTS frame");
+
+ wpabuf_free(buf);
+ return ret;
+}
+
+
+/* return the AC using the given TSPEC tid */
+static int wmm_ac_find_tsid(struct wpa_supplicant *wpa_s, u8 tsid,
+ enum ts_dir_idx *dir)
+{
+ int ac;
+ enum ts_dir_idx idx;
+
+ for (ac = 0; ac < WMM_AC_NUM; ac++) {
+ for (idx = 0; idx < TS_DIR_IDX_COUNT; idx++) {
+ if (wpa_s->tspecs[ac][idx] &&
+ wmm_ac_get_tsid(wpa_s->tspecs[ac][idx]) == tsid) {
+ if (dir)
+ *dir = idx;
+ return ac;
+ }
+ }
+ }
+
+ return -1;
+}
+
+
+static struct wmm_ac_addts_request *
+wmm_ac_build_addts_req(struct wpa_supplicant *wpa_s,
+ const struct wmm_ac_ts_setup_params *params,
+ const u8 *address)
+{
+ struct wmm_ac_addts_request *addts_req;
+ struct wmm_tspec_element *tspec;
+ u8 ac = up_to_ac[params->user_priority];
+ u8 uapsd = wpa_s->wmm_ac_assoc_info->ac_params[ac].uapsd;
+
+ addts_req = os_zalloc(sizeof(*addts_req));
+ if (!addts_req)
+ return NULL;
+
+ tspec = &addts_req->tspec;
+ os_memcpy(addts_req->address, address, ETH_ALEN);
+
+ /* The dialog token cannot be zero */
+ if (++wpa_s->wmm_ac_last_dialog_token == 0)
+ wpa_s->wmm_ac_last_dialog_token++;
+
+ addts_req->dialog_token = wpa_s->wmm_ac_last_dialog_token;
+ tspec->eid = WLAN_EID_VENDOR_SPECIFIC;
+ tspec->length = sizeof(*tspec) - 2; /* reduce eid and length */
+ tspec->oui[0] = 0x00;
+ tspec->oui[1] = 0x50;
+ tspec->oui[2] = 0xf2;
+ tspec->oui_type = WMM_OUI_TYPE;
+ tspec->oui_subtype = WMM_OUI_SUBTYPE_TSPEC_ELEMENT;
+ tspec->version = WMM_VERSION;
+
+ tspec->ts_info[0] = params->tsid << 1;
+ tspec->ts_info[0] |= params->direction << 5;
+ tspec->ts_info[0] |= WMM_AC_ACCESS_POLICY_EDCA << 7;
+ tspec->ts_info[1] = uapsd << 2;
+ tspec->ts_info[1] |= params->user_priority << 3;
+ tspec->ts_info[2] = 0;
+
+ tspec->nominal_msdu_size = host_to_le16(params->nominal_msdu_size);
+ if (params->fixed_nominal_msdu)
+ tspec->nominal_msdu_size |=
+ host_to_le16(WMM_AC_FIXED_MSDU_SIZE);
+
+ tspec->mean_data_rate = host_to_le32(params->mean_data_rate);
+ tspec->minimum_phy_rate = host_to_le32(params->minimum_phy_rate);
+ tspec->surplus_bandwidth_allowance =
+ host_to_le16(params->surplus_bandwidth_allowance);
+
+ return addts_req;
+}
+
+
+static int param_in_range(const char *name, long value,
+ long min_val, long max_val)
+{
+ if (value < min_val || (max_val >= 0 && value > max_val)) {
+ wpa_printf(MSG_DEBUG,
+ "WMM AC: param %s (%ld) is out of range (%ld-%ld)",
+ name, value, min_val, max_val);
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static int wmm_ac_should_replace_ts(struct wpa_supplicant *wpa_s,
+ u8 tsid, u8 ac, u8 dir)
+{
+ enum ts_dir_idx idx;
+ int cur_ac, existing_ts = 0, replace_ts = 0;
+
+ cur_ac = wmm_ac_find_tsid(wpa_s, tsid, &idx);
+ if (cur_ac >= 0) {
+ if (cur_ac != ac) {
+ wpa_printf(MSG_DEBUG,
+ "WMM AC: TSID %i already exists on different ac (%d)",
+ tsid, cur_ac);
+ return -1;
+ }
+
+ /* same tsid - this tspec will replace the current one */
+ replace_ts |= BIT(idx);
+ }
+
+ for (idx = 0; idx < TS_DIR_IDX_COUNT; idx++) {
+ if (wpa_s->tspecs[ac][idx])
+ existing_ts |= BIT(idx);
+ }
+
+ switch (dir) {
+ case WMM_AC_DIR_UPLINK:
+ /* replace existing uplink/bidi tspecs */
+ replace_ts |= existing_ts & (BIT(TS_DIR_IDX_UPLINK) |
+ BIT(TS_DIR_IDX_BIDI));
+ break;
+ case WMM_AC_DIR_DOWNLINK:
+ /* replace existing downlink/bidi tspecs */
+ replace_ts |= existing_ts & (BIT(TS_DIR_IDX_DOWNLINK) |
+ BIT(TS_DIR_IDX_BIDI));
+ break;
+ case WMM_AC_DIR_BIDIRECTIONAL:
+ /* replace all existing tspecs */
+ replace_ts |= existing_ts;
+ break;
+ default:
+ return -1;
+ }
+
+ return replace_ts;
+}
+
+
+static int wmm_ac_ts_req_is_valid(struct wpa_supplicant *wpa_s,
+ const struct wmm_ac_ts_setup_params *params)
+{
+ enum wmm_ac req_ac;
+
+#define PARAM_IN_RANGE(field, min_value, max_value) \
+ param_in_range(#field, params->field, min_value, max_value)
+
+ if (!PARAM_IN_RANGE(tsid, 0, WMM_AC_MAX_TID) ||
+ !PARAM_IN_RANGE(user_priority, 0, WMM_AC_MAX_USER_PRIORITY) ||
+ !PARAM_IN_RANGE(nominal_msdu_size, 1, WMM_AC_MAX_NOMINAL_MSDU) ||
+ !PARAM_IN_RANGE(mean_data_rate, 1, -1) ||
+ !PARAM_IN_RANGE(minimum_phy_rate, 1, -1) ||
+ !PARAM_IN_RANGE(surplus_bandwidth_allowance, WMM_AC_MIN_SBA_UNITY,
+ -1))
+ return 0;
+#undef PARAM_IN_RANGE
+
+ if (!(params->direction == WMM_TSPEC_DIRECTION_UPLINK ||
+ params->direction == WMM_TSPEC_DIRECTION_DOWNLINK ||
+ params->direction == WMM_TSPEC_DIRECTION_BI_DIRECTIONAL)) {
+ wpa_printf(MSG_DEBUG, "WMM AC: invalid TS direction: %d",
+ params->direction);
+ return 0;
+ }
+
+ req_ac = up_to_ac[params->user_priority];
+
+ /* Requested accesss category must have acm */
+ if (!wpa_s->wmm_ac_assoc_info->ac_params[req_ac].acm) {
+ wpa_printf(MSG_DEBUG, "WMM AC: AC %d is not ACM", req_ac);
+ return 0;
+ }
+
+ if (wmm_ac_should_replace_ts(wpa_s, params->tsid, req_ac,
+ params->direction) < 0)
+ return 0;
+
+ return 1;
+}
+
+
+static struct wmm_ac_assoc_data *
+wmm_ac_process_param_elem(struct wpa_supplicant *wpa_s, const u8 *ies,
+ size_t ies_len)
+{
+ struct ieee802_11_elems elems;
+ struct wmm_parameter_element *wmm_params;
+ struct wmm_ac_assoc_data *assoc_data;
+ int i;
+
+ /* Parsing WMM Parameter Element */
+ if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
+ wpa_printf(MSG_DEBUG, "WMM AC: could not parse assoc ies");
+ return NULL;
+ }
+
+ if (!elems.wmm) {
+ wpa_printf(MSG_DEBUG, "WMM AC: No WMM IE");
+ return NULL;
+ }
+
+ if (elems.wmm_len != sizeof(*wmm_params)) {
+ wpa_printf(MSG_DEBUG, "WMM AC: Invalid WMM ie length");
+ return NULL;
+ }
+
+ wmm_params = (struct wmm_parameter_element *)(elems.wmm);
+
+ assoc_data = os_zalloc(sizeof(*assoc_data));
+ if (!assoc_data)
+ return NULL;
+
+ for (i = 0; i < WMM_AC_NUM; i++)
+ assoc_data->ac_params[i].acm =
+ !!(wmm_params->ac[i].aci_aifsn & WMM_AC_ACM);
+
+ wpa_printf(MSG_DEBUG,
+ "WMM AC: AC mandatory: AC_BE=%u AC_BK=%u AC_VI=%u AC_VO=%u",
+ assoc_data->ac_params[WMM_AC_BE].acm,
+ assoc_data->ac_params[WMM_AC_BK].acm,
+ assoc_data->ac_params[WMM_AC_VI].acm,
+ assoc_data->ac_params[WMM_AC_VO].acm);
+
+ return assoc_data;
+}
+
+
+static int wmm_ac_init(struct wpa_supplicant *wpa_s, const u8 *ies,
+ size_t ies_len, const struct wmm_params *wmm_params)
+{
+ struct wmm_ac_assoc_data *assoc_data;
+ u8 ac;
+
+ if (wpa_s->wmm_ac_assoc_info) {
+ wpa_printf(MSG_ERROR, "WMM AC: Already initialized");
+ return -1;
+ }
+
+ if (!ies) {
+ wpa_printf(MSG_ERROR, "WMM AC: Missing IEs");
+ return -1;
+ }
+
+ if (!(wmm_params->info_bitmap & WMM_PARAMS_UAPSD_QUEUES_INFO)) {
+ wpa_printf(MSG_DEBUG, "WMM AC: Missing U-APSD configuration");
+ return -1;
+ }
+
+ os_memset(wpa_s->tspecs, 0, sizeof(wpa_s->tspecs));
+ wpa_s->wmm_ac_last_dialog_token = 0;
+ wpa_s->addts_request = NULL;
+
+ assoc_data = wmm_ac_process_param_elem(wpa_s, ies, ies_len);
+ if (!assoc_data)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "WMM AC: U-APSD queues=0x%x",
+ wmm_params->uapsd_queues);
+
+ for (ac = 0; ac < WMM_AC_NUM; ac++) {
+ assoc_data->ac_params[ac].uapsd =
+ !!(wmm_params->uapsd_queues & BIT(ac));
+ }
+
+ wpa_s->wmm_ac_assoc_info = assoc_data;
+ return 0;
+}
+
+
+static void wmm_ac_del_ts(struct wpa_supplicant *wpa_s, u8 ac, int dir_bitmap)
+{
+ enum ts_dir_idx idx;
+
+ for (idx = 0; idx < TS_DIR_IDX_COUNT; idx++) {
+ if (!(dir_bitmap & BIT(idx)))
+ continue;
+
+ wmm_ac_del_ts_idx(wpa_s, ac, idx);
+ }
+}
+
+
+static void wmm_ac_deinit(struct wpa_supplicant *wpa_s)
+{
+ int i;
+
+ for (i = 0; i < WMM_AC_NUM; i++)
+ wmm_ac_del_ts(wpa_s, i, TS_DIR_IDX_ALL);
+
+ /* delete pending add_ts requset */
+ wmm_ac_del_req(wpa_s, 1);
+
+ os_free(wpa_s->wmm_ac_assoc_info);
+ wpa_s->wmm_ac_assoc_info = NULL;
+}
+
+
+void wmm_ac_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *ies,
+ size_t ies_len, const struct wmm_params *wmm_params)
+{
+ if (wmm_ac_init(wpa_s, ies, ies_len, wmm_params))
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "WMM AC: Valid WMM association, WMM AC is enabled");
+}
+
+
+void wmm_ac_notify_disassoc(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->wmm_ac_assoc_info)
+ return;
+
+ wmm_ac_deinit(wpa_s);
+ wpa_printf(MSG_DEBUG, "WMM AC: WMM AC is disabled");
+}
+
+
+int wpas_wmm_ac_delts(struct wpa_supplicant *wpa_s, u8 tsid)
+{
+ struct wmm_tspec_element tspec;
+ int ac;
+ enum ts_dir_idx dir;
+
+ if (!wpa_s->wmm_ac_assoc_info) {
+ wpa_printf(MSG_DEBUG,
+ "WMM AC: Failed to delete TS, WMM AC is disabled");
+ return -1;
+ }
+
+ ac = wmm_ac_find_tsid(wpa_s, tsid, &dir);
+ if (ac < 0) {
+ wpa_printf(MSG_DEBUG, "WMM AC: TS does not exist");
+ return -1;
+ }
+
+ tspec = *wpa_s->tspecs[ac][dir];
+
+ wmm_ac_del_ts_idx(wpa_s, ac, dir);
+
+ wmm_ac_send_delts(wpa_s, &tspec, wpa_s->bssid);
+
+ return 0;
+}
+
+
+int wpas_wmm_ac_addts(struct wpa_supplicant *wpa_s,
+ struct wmm_ac_ts_setup_params *params)
+{
+ struct wmm_ac_addts_request *addts_req;
+
+ if (!wpa_s->wmm_ac_assoc_info) {
+ wpa_printf(MSG_DEBUG,
+ "WMM AC: Cannot add TS - missing assoc data");
+ return -1;
+ }
+
+ if (wpa_s->addts_request) {
+ wpa_printf(MSG_DEBUG,
+ "WMM AC: can't add TS - ADDTS request is already pending");
+ return -1;
+ }
+
+ /*
+ * we can setup downlink TS even without driver support.
+ * however, we need driver support for the other directions.
+ */
+ if (params->direction != WMM_AC_DIR_DOWNLINK &&
+ !wpa_s->wmm_ac_supported) {
+ wpa_printf(MSG_DEBUG,
+ "Cannot set uplink/bidi TS without driver support");
+ return -1;
+ }
+
+ if (!wmm_ac_ts_req_is_valid(wpa_s, params))
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "WMM AC: TS setup request (addr=" MACSTR
+ " tsid=%u user priority=%u direction=%d)",
+ MAC2STR(wpa_s->bssid), params->tsid,
+ params->user_priority, params->direction);
+
+ addts_req = wmm_ac_build_addts_req(wpa_s, params, wpa_s->bssid);
+ if (!addts_req)
+ return -1;
+
+ if (wmm_ac_send_addts_request(wpa_s, addts_req))
+ goto err;
+
+ /* save as pending and set ADDTS resp timeout to 1 second */
+ wpa_s->addts_request = addts_req;
+ eloop_register_timeout(1, 0, wmm_ac_addts_req_timeout,
+ wpa_s, addts_req);
+ return 0;
+err:
+ os_free(addts_req);
+ return -1;
+}
+
+
+static void wmm_ac_handle_delts(struct wpa_supplicant *wpa_s, const u8 *sa,
+ const struct wmm_tspec_element *tspec)
+{
+ int ac;
+ u8 tsid;
+ enum ts_dir_idx idx;
+
+ tsid = wmm_ac_get_tsid(tspec);
+
+ wpa_printf(MSG_DEBUG,
+ "WMM AC: DELTS frame has been received TSID=%u addr="
+ MACSTR, tsid, MAC2STR(sa));
+
+ ac = wmm_ac_find_tsid(wpa_s, tsid, &idx);
+ if (ac < 0) {
+ wpa_printf(MSG_DEBUG,
+ "WMM AC: Ignoring DELTS frame - TSID does not exist");
+ return;
+ }
+
+ wmm_ac_del_ts_idx(wpa_s, ac, idx);
+
+ wpa_printf(MSG_DEBUG,
+ "TS was deleted successfully (tsid=%u address=" MACSTR ")",
+ tsid, MAC2STR(sa));
+}
+
+
+static void wmm_ac_handle_addts_resp(struct wpa_supplicant *wpa_s, const u8 *sa,
+ const u8 resp_dialog_token, const u8 status_code,
+ const struct wmm_tspec_element *tspec)
+{
+ struct wmm_ac_addts_request *req = wpa_s->addts_request;
+ u8 ac, tsid, up, dir;
+ int replace_tspecs;
+
+ tsid = wmm_ac_get_tsid(tspec);
+ dir = wmm_ac_get_direction(tspec);
+ up = wmm_ac_get_user_priority(tspec);
+ ac = up_to_ac[up];
+
+ /* make sure we have a matching addts request */
+ if (!req || req->dialog_token != resp_dialog_token) {
+ wpa_printf(MSG_DEBUG,
+ "WMM AC: no req with dialog=%u, ignoring frame",
+ resp_dialog_token);
+ return;
+ }
+
+ /* make sure the params are the same */
+ if (os_memcmp(req->address, sa, ETH_ALEN) != 0 ||
+ tsid != wmm_ac_get_tsid(&req->tspec) ||
+ up != wmm_ac_get_user_priority(&req->tspec) ||
+ dir != wmm_ac_get_direction(&req->tspec)) {
+ wpa_printf(MSG_DEBUG,
+ "WMM AC: ADDTS params do not match, ignoring frame");
+ return;
+ }
+
+ /* delete pending request */
+ wmm_ac_del_req(wpa_s, 0);
+
+ wpa_printf(MSG_DEBUG,
+ "ADDTS response status=%d tsid=%u up=%u direction=%u",
+ status_code, tsid, up, dir);
+
+ if (status_code != WMM_ADDTS_STATUS_ADMISSION_ACCEPTED) {
+ wpa_printf(MSG_INFO, "WMM AC: ADDTS request was rejected");
+ goto err_msg;
+ }
+
+ replace_tspecs = wmm_ac_should_replace_ts(wpa_s, tsid, ac, dir);
+ if (replace_tspecs < 0)
+ goto err_delts;
+
+ wpa_printf(MSG_DEBUG, "ts idx replace bitmap: 0x%x", replace_tspecs);
+
+ /* when replacing tspecs - delete first */
+ wmm_ac_del_ts(wpa_s, ac, replace_tspecs);
+
+ /* Creating a new traffic stream */
+ wpa_printf(MSG_DEBUG,
+ "WMM AC: adding a new TS with TSID=%u address="MACSTR
+ " medium time=%u access category=%d dir=%d ",
+ tsid, MAC2STR(sa),
+ le_to_host16(tspec->medium_time), ac, dir);
+
+ if (wmm_ac_add_ts(wpa_s, sa, tspec))
+ goto err_delts;
+
+ return;
+
+err_delts:
+ /* ask the ap to delete the tspec */
+ wmm_ac_send_delts(wpa_s, tspec, sa);
+err_msg:
+ wpa_msg(wpa_s, MSG_INFO, WMM_AC_EVENT_TSPEC_REQ_FAILED "tsid=%u",
+ tsid);
+}
+
+
+void wmm_ac_rx_action(struct wpa_supplicant *wpa_s, const u8 *da,
+ const u8 *sa, const u8 *data, size_t len)
+{
+ u8 action;
+ u8 dialog_token;
+ u8 status_code;
+ struct ieee802_11_elems elems;
+ struct wmm_tspec_element *tspec;
+
+ if (wpa_s->wmm_ac_assoc_info == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "WMM AC: WMM AC is disabled, ignoring action frame");
+ return;
+ }
+
+ action = data[0];
+
+ if (action != WMM_ACTION_CODE_ADDTS_RESP &&
+ action != WMM_ACTION_CODE_DELTS) {
+ wpa_printf(MSG_DEBUG,
+ "WMM AC: Unknown action (%d), ignoring action frame",
+ action);
+ return;
+ }
+
+ /* WMM AC action frame */
+ if (os_memcmp(da, wpa_s->own_addr, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "WMM AC: frame destination addr="MACSTR
+ " is other than ours, ignoring frame", MAC2STR(da));
+ return;
+ }
+
+ if (os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "WMM AC: ignore frame with sa " MACSTR
+ " different other than our bssid", MAC2STR(da));
+ return;
+ }
+
+ if (len < 2 + sizeof(struct wmm_tspec_element)) {
+ wpa_printf(MSG_DEBUG,
+ "WMM AC: Short ADDTS response ignored (len=%lu)",
+ (unsigned long) len);
+ return;
+ }
+
+ data++;
+ len--;
+ dialog_token = data[0];
+ status_code = data[1];
+
+ if (ieee802_11_parse_elems(data + 2, len - 2, &elems, 1) != ParseOK) {
+ wpa_printf(MSG_DEBUG,
+ "WMM AC: Could not parse WMM AC action from " MACSTR,
+ MAC2STR(sa));
+ return;
+ }
+
+ /* the struct also contains the type and value, so decrease it */
+ if (elems.wmm_tspec_len != sizeof(struct wmm_tspec_element) - 2) {
+ wpa_printf(MSG_DEBUG, "WMM AC: missing or wrong length TSPEC");
+ return;
+ }
+
+ tspec = (struct wmm_tspec_element *)(elems.wmm_tspec - 2);
+
+ wpa_printf(MSG_DEBUG, "WMM AC: RX WMM AC Action from " MACSTR,
+ MAC2STR(sa));
+ wpa_hexdump(MSG_MSGDUMP, "WMM AC: WMM AC Action content", data, len);
+
+ switch (action) {
+ case WMM_ACTION_CODE_ADDTS_RESP:
+ wmm_ac_handle_addts_resp(wpa_s, sa, dialog_token, status_code,
+ tspec);
+ break;
+ case WMM_ACTION_CODE_DELTS:
+ wmm_ac_handle_delts(wpa_s, sa, tspec);
+ break;
+ default:
+ break;
+ }
+}
+
+
+static const char * get_ac_str(u8 ac)
+{
+ switch (ac) {
+ case WMM_AC_BE:
+ return "BE";
+ case WMM_AC_BK:
+ return "BK";
+ case WMM_AC_VI:
+ return "VI";
+ case WMM_AC_VO:
+ return "VO";
+ default:
+ return "N/A";
+ }
+}
+
+
+static const char * get_direction_str(u8 direction)
+{
+ switch (direction) {
+ case WMM_AC_DIR_DOWNLINK:
+ return "Downlink";
+ case WMM_AC_DIR_UPLINK:
+ return "Uplink";
+ case WMM_AC_DIR_BIDIRECTIONAL:
+ return "Bi-directional";
+ default:
+ return "N/A";
+ }
+}
+
+
+int wpas_wmm_ac_status(struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
+{
+ struct wmm_ac_assoc_data *assoc_info = wpa_s->wmm_ac_assoc_info;
+ enum ts_dir_idx idx;
+ int pos = 0;
+ u8 ac, up;
+
+ if (!assoc_info) {
+ return wpa_scnprintf(buf, buflen - pos,
+ "Not associated to a WMM AP, WMM AC is Disabled\n");
+ }
+
+ pos += wpa_scnprintf(buf + pos, buflen - pos, "WMM AC is Enabled\n");
+
+ for (ac = 0; ac < WMM_AC_NUM; ac++) {
+ int ts_count = 0;
+
+ pos += wpa_scnprintf(buf + pos, buflen - pos,
+ "%s: acm=%d uapsd=%d\n",
+ get_ac_str(ac),
+ assoc_info->ac_params[ac].acm,
+ assoc_info->ac_params[ac].uapsd);
+
+ for (idx = 0; idx < TS_DIR_IDX_COUNT; idx++) {
+ struct wmm_tspec_element *tspec;
+ u8 dir, tsid;
+ const char *dir_str;
+
+ tspec = wpa_s->tspecs[ac][idx];
+ if (!tspec)
+ continue;
+
+ ts_count++;
+
+ dir = wmm_ac_get_direction(tspec);
+ dir_str = get_direction_str(dir);
+ tsid = wmm_ac_get_tsid(tspec);
+ up = wmm_ac_get_user_priority(tspec);
+
+ pos += wpa_scnprintf(buf + pos, buflen - pos,
+ "\tTSID=%u UP=%u\n"
+ "\tAddress = "MACSTR"\n"
+ "\tWMM AC dir = %s\n"
+ "\tTotal admitted time = %u\n\n",
+ tsid, up,
+ MAC2STR(wpa_s->bssid),
+ dir_str,
+ le_to_host16(tspec->medium_time));
+ }
+
+ if (!ts_count) {
+ pos += wpa_scnprintf(buf + pos, buflen - pos,
+ "\t(No Traffic Stream)\n\n");
+ }
+ }
+
+ return pos;
+}
+
+
+static u8 wmm_ac_get_tspecs_count(struct wpa_supplicant *wpa_s)
+{
+ int ac, dir, tspecs_count = 0;
+
+ for (ac = 0; ac < WMM_AC_NUM; ac++) {
+ for (dir = 0; dir < TS_DIR_IDX_COUNT; dir++) {
+ if (wpa_s->tspecs[ac][dir])
+ tspecs_count++;
+ }
+ }
+
+ return tspecs_count;
+}
+
+
+void wmm_ac_save_tspecs(struct wpa_supplicant *wpa_s)
+{
+ int ac, dir, tspecs_count;
+
+ wpa_printf(MSG_DEBUG, "WMM AC: Save last configured tspecs");
+
+ if (!wpa_s->wmm_ac_assoc_info)
+ return;
+
+ tspecs_count = wmm_ac_get_tspecs_count(wpa_s);
+ if (!tspecs_count) {
+ wpa_printf(MSG_DEBUG, "WMM AC: No configured TSPECs");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "WMM AC: Saving tspecs");
+
+ wmm_ac_clear_saved_tspecs(wpa_s);
+ wpa_s->last_tspecs = os_calloc(tspecs_count,
+ sizeof(*wpa_s->last_tspecs));
+ if (!wpa_s->last_tspecs) {
+ wpa_printf(MSG_ERROR, "WMM AC: Failed to save tspecs!");
+ return;
+ }
+
+ for (ac = 0; ac < WMM_AC_NUM; ac++) {
+ for (dir = 0; dir < TS_DIR_IDX_COUNT; dir++) {
+ if (!wpa_s->tspecs[ac][dir])
+ continue;
+
+ wpa_s->last_tspecs[wpa_s->last_tspecs_count++] =
+ *wpa_s->tspecs[ac][dir];
+ }
+ }
+
+ wpa_printf(MSG_DEBUG, "WMM AC: Successfully saved %d TSPECs",
+ wpa_s->last_tspecs_count);
+}
+
+
+void wmm_ac_clear_saved_tspecs(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->last_tspecs) {
+ wpa_printf(MSG_DEBUG, "WMM AC: Clear saved tspecs");
+ os_free(wpa_s->last_tspecs);
+ wpa_s->last_tspecs = NULL;
+ wpa_s->last_tspecs_count = 0;
+ }
+}
+
+
+int wmm_ac_restore_tspecs(struct wpa_supplicant *wpa_s)
+{
+ unsigned int i;
+
+ if (!wpa_s->wmm_ac_assoc_info || !wpa_s->last_tspecs_count)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "WMM AC: Restore %u saved tspecs",
+ wpa_s->last_tspecs_count);
+
+ for (i = 0; i < wpa_s->last_tspecs_count; i++)
+ wmm_ac_add_ts(wpa_s, wpa_s->bssid, &wpa_s->last_tspecs[i]);
+
+ return 0;
+}
diff --git a/wpa_supplicant/wmm_ac.h b/wpa_supplicant/wmm_ac.h
new file mode 100644
index 0000000..5171b16
--- /dev/null
+++ b/wpa_supplicant/wmm_ac.h
@@ -0,0 +1,176 @@
+/*
+ * Wi-Fi Multimedia Admission Control (WMM-AC)
+ * Copyright(c) 2014, Intel Mobile Communication GmbH.
+ * Copyright(c) 2014, Intel Corporation. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WMM_AC_H
+#define WMM_AC_H
+
+#include "common/ieee802_11_defs.h"
+#include "drivers/driver.h"
+
+struct wpa_supplicant;
+
+#define WMM_AC_ACCESS_POLICY_EDCA 1
+#define WMM_AC_FIXED_MSDU_SIZE BIT(15)
+
+#define WMM_AC_MAX_TID 7
+#define WMM_AC_MAX_USER_PRIORITY 7
+#define WMM_AC_MIN_SBA_UNITY 0x2000
+#define WMM_AC_MAX_NOMINAL_MSDU 32767
+
+/**
+ * struct wmm_ac_assoc_data - WMM Admission Control Association Data
+ *
+ * This struct will store any relevant WMM association data needed by WMM AC.
+ * In case there is a valid WMM association, an instance of this struct will be
+ * created. In case there is no instance of this struct, the station is not
+ * associated to a valid WMM BSS and hence, WMM AC will not be used.
+ */
+struct wmm_ac_assoc_data {
+ struct {
+ /*
+ * acm - Admission Control Mandatory
+ * In case an access category is ACM, the traffic will have
+ * to be admitted by WMM-AC's admission mechanism before use.
+ */
+ unsigned int acm:1;
+
+ /*
+ * uapsd_queues - Unscheduled Automatic Power Save Delivery
+ * queues.
+ * Indicates whether ACs are configured for U-APSD (or legacy
+ * PS). Storing this value is necessary in order to set the
+ * Power Save Bit (PSB) in ADDTS request Action frames (if not
+ * given).
+ */
+ unsigned int uapsd:1;
+ } ac_params[WMM_AC_NUM];
+};
+
+/**
+ * wmm_ac_dir - WMM Admission Control Direction
+ */
+enum wmm_ac_dir {
+ WMM_AC_DIR_UPLINK = 0,
+ WMM_AC_DIR_DOWNLINK = 1,
+ WMM_AC_DIR_BIDIRECTIONAL = 3
+};
+
+/**
+ * ts_dir_idx - indices of internally saved tspecs
+ *
+ * we can have multiple tspecs (downlink + uplink) per ac.
+ * save them in array, and use the enum to directly access
+ * the respective tspec slot (according to the direction).
+ */
+enum ts_dir_idx {
+ TS_DIR_IDX_UPLINK,
+ TS_DIR_IDX_DOWNLINK,
+ TS_DIR_IDX_BIDI,
+
+ TS_DIR_IDX_COUNT
+};
+#define TS_DIR_IDX_ALL (BIT(TS_DIR_IDX_COUNT) - 1)
+
+/**
+ * struct wmm_ac_addts_request - ADDTS Request Information
+ *
+ * The last sent ADDTS request(s) will be saved as element(s) of this struct in
+ * order to be compared with the received ADDTS response in ADDTS response
+ * action frame handling and should be stored until that point.
+ * In case a new traffic stream will be created/replaced/updated, only its
+ * relevant traffic stream information will be stored as a wmm_ac_ts struct.
+ */
+struct wmm_ac_addts_request {
+ /*
+ * dialog token - Used to link the recived ADDTS response with this
+ * saved ADDTS request when ADDTS response is being handled
+ */
+ u8 dialog_token;
+
+ /*
+ * address - The alleged traffic stream's receiver/transmitter address
+ * Address and TID are used to identify the TS (TID is contained in
+ * TSPEC)
+ */
+ u8 address[ETH_ALEN];
+
+ /*
+ * tspec - Traffic Stream Specification, will be used to compare the
+ * sent TSPEC in ADDTS request to the received TSPEC in ADDTS response
+ * and act accordingly in ADDTS response handling
+ */
+ struct wmm_tspec_element tspec;
+};
+
+
+/**
+ * struct wmm_ac_ts_setup_params - TS setup parameters
+ *
+ * This struct holds parameters which should be provided
+ * to wmm_ac_ts_setup in order to setup a traffic stream
+ */
+struct wmm_ac_ts_setup_params {
+ /*
+ * tsid - Traffic ID
+ * TID and address are used to identify the TS
+ */
+ int tsid;
+
+ /*
+ * direction - Traffic Stream's direction
+ */
+ enum wmm_ac_dir direction;
+
+ /*
+ * user_priority - Traffic Stream's user priority
+ */
+ int user_priority;
+
+ /*
+ * nominal_msdu_size - Nominal MAC service data unit size
+ */
+ int nominal_msdu_size;
+
+ /*
+ * fixed_nominal_msdu - Whether the size is fixed
+ * 0 = Nominal MSDU size is not fixed
+ * 1 = Nominal MSDU size is fixed
+ */
+ int fixed_nominal_msdu;
+
+ /*
+ * surplus_bandwidth_allowance - Specifies excess time allocation
+ */
+ int mean_data_rate;
+
+ /*
+ * minimum_phy_rate - Specifies the minimum supported PHY rate in bps
+ */
+ int minimum_phy_rate;
+
+ /*
+ * surplus_bandwidth_allowance - Specifies excess time allocation
+ */
+ int surplus_bandwidth_allowance;
+};
+
+void wmm_ac_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *ies,
+ size_t ies_len, const struct wmm_params *wmm_params);
+void wmm_ac_notify_disassoc(struct wpa_supplicant *wpa_s);
+int wpas_wmm_ac_addts(struct wpa_supplicant *wpa_s,
+ struct wmm_ac_ts_setup_params *params);
+int wpas_wmm_ac_delts(struct wpa_supplicant *wpa_s, u8 tsid);
+void wmm_ac_rx_action(struct wpa_supplicant *wpa_s, const u8 *da,
+ const u8 *sa, const u8 *data, size_t len);
+int wpas_wmm_ac_status(struct wpa_supplicant *wpa_s, char *buf, size_t buflen);
+void wmm_ac_save_tspecs(struct wpa_supplicant *wpa_s);
+void wmm_ac_clear_saved_tspecs(struct wpa_supplicant *wpa_s);
+int wmm_ac_restore_tspecs(struct wpa_supplicant *wpa_s);
+
+#endif /* WMM_AC_H */
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index 4a792c4..954de67 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -10,6 +10,7 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
#include "rsn_supp/wpa.h"
#include "wpa_supplicant_i.h"
@@ -244,6 +245,7 @@
/* multiple TFS Resp IE (assuming consecutive) */
u8 *tfsresp_ie_start = NULL;
u8 *tfsresp_ie_end = NULL;
+ size_t left;
if (len < 3)
return;
@@ -251,11 +253,12 @@
wpa_printf(MSG_DEBUG, "WNM-Sleep Mode Response token=%u key_len_total=%d",
frm[0], key_len_total);
- pos += 3 + key_len_total;
- if (pos > frm + len) {
+ left = len - 3;
+ if (key_len_total > left) {
wpa_printf(MSG_INFO, "WNM: Too short frame for Key Data field");
return;
}
+ pos += 3 + key_len_total;
while (pos - frm < len) {
u8 ie_len = *(pos + 1);
if (pos + 2 + ie_len > frm + len) {
@@ -309,13 +312,7 @@
int i;
for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
- os_free(wpa_s->wnm_neighbor_report_elements[i].tsf_info);
- os_free(wpa_s->wnm_neighbor_report_elements[i].con_coun_str);
- os_free(wpa_s->wnm_neighbor_report_elements[i].bss_tran_can);
- os_free(wpa_s->wnm_neighbor_report_elements[i].bss_term_dur);
- os_free(wpa_s->wnm_neighbor_report_elements[i].bearing);
os_free(wpa_s->wnm_neighbor_report_elements[i].meas_pilot);
- os_free(wpa_s->wnm_neighbor_report_elements[i].rrm_cap);
os_free(wpa_s->wnm_neighbor_report_elements[i].mul_bssid);
}
@@ -334,12 +331,9 @@
wpa_printf(MSG_DEBUG, "WNM: Too short TSF");
break;
}
- os_free(rep->tsf_info);
- rep->tsf_info = os_zalloc(sizeof(struct tsf_info));
- if (rep->tsf_info == NULL)
- break;
- os_memcpy(rep->tsf_info->tsf_offset, pos, 2);
- os_memcpy(rep->tsf_info->beacon_interval, pos + 2, 2);
+ rep->tsf_offset = WPA_GET_LE16(pos);
+ rep->beacon_int = WPA_GET_LE16(pos + 2);
+ rep->tsf_present = 1;
break;
case WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING:
if (elen < 2) {
@@ -347,12 +341,8 @@
"country string");
break;
}
- os_free(rep->con_coun_str);
- rep->con_coun_str =
- os_zalloc(sizeof(struct condensed_country_string));
- if (rep->con_coun_str == NULL)
- break;
- os_memcpy(rep->con_coun_str->country_string, pos, 2);
+ os_memcpy(rep->country, pos, 2);
+ rep->country_present = 1;
break;
case WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE:
if (elen < 1) {
@@ -360,25 +350,13 @@
"candidate");
break;
}
- os_free(rep->bss_tran_can);
- rep->bss_tran_can =
- os_zalloc(sizeof(struct bss_transition_candidate));
- if (rep->bss_tran_can == NULL)
- break;
- rep->bss_tran_can->preference = pos[0];
+ rep->preference = pos[0];
+ rep->preference_present = 1;
break;
case WNM_NEIGHBOR_BSS_TERMINATION_DURATION:
- if (elen < 10) {
- wpa_printf(MSG_DEBUG, "WNM: Too short BSS termination "
- "duration");
- break;
- }
- os_free(rep->bss_term_dur);
- rep->bss_term_dur =
- os_zalloc(sizeof(struct bss_termination_duration));
- if (rep->bss_term_dur == NULL)
- break;
- os_memcpy(rep->bss_term_dur->duration, pos, 10);
+ rep->bss_term_tsf = WPA_GET_LE64(pos);
+ rep->bss_term_dur = WPA_GET_LE16(pos + 8);
+ rep->bss_term_present = 1;
break;
case WNM_NEIGHBOR_BEARING:
if (elen < 8) {
@@ -386,11 +364,10 @@
"bearing");
break;
}
- os_free(rep->bearing);
- rep->bearing = os_zalloc(sizeof(struct bearing));
- if (rep->bearing == NULL)
- break;
- os_memcpy(rep->bearing->bearing, pos, 8);
+ rep->bearing = WPA_GET_LE16(pos);
+ rep->distance = WPA_GET_LE32(pos + 2);
+ rep->rel_height = WPA_GET_LE16(pos + 2 + 4);
+ rep->bearing_present = 1;
break;
case WNM_NEIGHBOR_MEASUREMENT_PILOT:
if (elen < 1) {
@@ -412,12 +389,8 @@
"capabilities");
break;
}
- os_free(rep->rrm_cap);
- rep->rrm_cap =
- os_zalloc(sizeof(struct rrm_enabled_capabilities));
- if (rep->rrm_cap == NULL)
- break;
- os_memcpy(rep->rrm_cap->capabilities, pos, 5);
+ os_memcpy(rep->rm_capab, pos, 5);
+ rep->rm_capab_present = 1;
break;
case WNM_NEIGHBOR_MULTIPLE_BSSID:
if (elen < 1) {
@@ -436,6 +409,22 @@
}
+static int wnm_nei_get_chan(struct wpa_supplicant *wpa_s, u8 op_class, u8 chan)
+{
+ struct wpa_bss *bss = wpa_s->current_bss;
+ const char *country = NULL;
+
+ if (bss) {
+ const u8 *elem = wpa_bss_get_ie(bss, WLAN_EID_COUNTRY);
+
+ if (elem && elem[1] >= 2)
+ country = (const char *) (elem + 2);
+ }
+
+ return ieee80211_chan_to_freq(country, op_class, chan);
+}
+
+
static void wnm_parse_neighbor_report(struct wpa_supplicant *wpa_s,
const u8 *pos, u8 len,
struct neighbor_report *rep)
@@ -448,7 +437,7 @@
}
os_memcpy(rep->bssid, pos, ETH_ALEN);
- os_memcpy(rep->bssid_information, pos + ETH_ALEN, 4);
+ rep->bssid_info = WPA_GET_LE32(pos + ETH_ALEN);
rep->regulatory_class = *(pos + 10);
rep->channel_number = *(pos + 11);
rep->phy_type = *(pos + 12);
@@ -472,47 +461,78 @@
left -= elen;
pos += elen;
}
+
+ rep->freq = wnm_nei_get_chan(wpa_s, rep->regulatory_class,
+ rep->channel_number);
}
-static int compare_scan_neighbor_results(struct wpa_supplicant *wpa_s,
- struct wpa_scan_results *scan_res,
- struct neighbor_report *neigh_rep,
- u8 num_neigh_rep, u8 *bssid_to_connect)
+static struct wpa_bss *
+compare_scan_neighbor_results(struct wpa_supplicant *wpa_s)
{
- u8 i, j;
+ u8 i;
+ struct wpa_bss *bss = wpa_s->current_bss;
+ struct wpa_bss *target;
- if (scan_res == NULL || num_neigh_rep == 0 || !wpa_s->current_bss)
+ if (!bss)
return 0;
wpa_printf(MSG_DEBUG, "WNM: Current BSS " MACSTR " RSSI %d",
- MAC2STR(wpa_s->bssid), wpa_s->current_bss->level);
+ MAC2STR(wpa_s->bssid), bss->level);
- for (i = 0; i < num_neigh_rep; i++) {
- for (j = 0; j < scan_res->num; j++) {
- /* Check for a better RSSI AP */
- if (os_memcmp(scan_res->res[j]->bssid,
- neigh_rep[i].bssid, ETH_ALEN) == 0 &&
- scan_res->res[j]->level >
- wpa_s->current_bss->level) {
- /* Got a BSSID with better RSSI value */
- os_memcpy(bssid_to_connect, neigh_rep[i].bssid,
- ETH_ALEN);
- wpa_printf(MSG_DEBUG, "Found a BSS " MACSTR
- " with better scan RSSI %d",
- MAC2STR(scan_res->res[j]->bssid),
- scan_res->res[j]->level);
- return 1;
- }
- wpa_printf(MSG_DEBUG, "scan_res[%d] " MACSTR
- " RSSI %d", j,
- MAC2STR(scan_res->res[j]->bssid),
- scan_res->res[j]->level);
+ for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
+ struct neighbor_report *nei;
+
+ nei = &wpa_s->wnm_neighbor_report_elements[i];
+ if (nei->preference_present && nei->preference == 0) {
+ wpa_printf(MSG_DEBUG, "Skip excluded BSS " MACSTR,
+ MAC2STR(nei->bssid));
+ continue;
}
+
+ target = wpa_bss_get_bssid(wpa_s, nei->bssid);
+ if (!target) {
+ wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
+ " (pref %d) not found in scan results",
+ MAC2STR(nei->bssid),
+ nei->preference_present ? nei->preference :
+ -1);
+ continue;
+ }
+
+ if (bss->ssid_len != target->ssid_len ||
+ os_memcmp(bss->ssid, target->ssid, bss->ssid_len) != 0) {
+ /*
+ * TODO: Could consider allowing transition to another
+ * ESS if PMF was enabled for the association.
+ */
+ wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
+ " (pref %d) in different ESS",
+ MAC2STR(nei->bssid),
+ nei->preference_present ? nei->preference :
+ -1);
+ continue;
+ }
+
+ if (target->level < bss->level && target->level < -80) {
+ wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
+ " (pref %d) does not have sufficient signal level (%d)",
+ MAC2STR(nei->bssid),
+ nei->preference_present ? nei->preference :
+ -1,
+ target->level);
+ continue;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "WNM: Found an acceptable preferred transition candidate BSS "
+ MACSTR " (RSSI %d)",
+ MAC2STR(nei->bssid), target->level);
+ return target;
}
- return 0;
+ return NULL;
}
@@ -524,10 +544,16 @@
u8 buf[1000], *pos;
struct ieee80211_mgmt *mgmt;
size_t len;
+ int res;
wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Response "
"to " MACSTR " dialog_token=%u status=%u delay=%d",
MAC2STR(wpa_s->bssid), dialog_token, status, delay);
+ if (!wpa_s->current_bss) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Current BSS not known - drop response");
+ return;
+ }
mgmt = (struct ieee80211_mgmt *) buf;
os_memset(&buf, 0, sizeof(buf));
@@ -557,62 +583,203 @@
len = pos - (u8 *) &mgmt->u.action.category;
- wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
- wpa_s->own_addr, wpa_s->bssid,
- &mgmt->u.action.category, len, 0);
+ res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->bssid,
+ &mgmt->u.action.category, len, 0);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Failed to send BSS Transition Management Response");
+ }
}
-void wnm_scan_response(struct wpa_supplicant *wpa_s,
- struct wpa_scan_results *scan_res)
+int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail)
{
- u8 bssid[ETH_ALEN];
+ struct wpa_bss *bss;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ enum bss_trans_mgmt_status_code status = WNM_BSS_TM_REJECT_UNSPECIFIED;
- if (scan_res == NULL) {
- wpa_printf(MSG_ERROR, "Scan result is NULL");
- goto send_bss_resp_fail;
+ if (!wpa_s->wnm_neighbor_report_elements)
+ return 0;
+
+ if (os_reltime_before(&wpa_s->wnm_cand_valid_until,
+ &wpa_s->scan_trigger_time)) {
+ wpa_printf(MSG_DEBUG, "WNM: Previously stored BSS transition candidate list is not valid anymore - drop it");
+ wnm_deallocate_memory(wpa_s);
+ return 0;
+ }
+
+ if (!wpa_s->current_bss ||
+ os_memcmp(wpa_s->wnm_cand_from_bss, wpa_s->current_bss->bssid,
+ ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "WNM: Stored BSS transition candidate list not from the current BSS - ignore it");
+ return 0;
}
/* Compare the Neighbor Report and scan results */
- if (compare_scan_neighbor_results(wpa_s, scan_res,
- wpa_s->wnm_neighbor_report_elements,
- wpa_s->wnm_num_neighbor_report,
- bssid) == 1) {
- /* Associate to the network */
- struct wpa_bss *bss;
- struct wpa_ssid *ssid = wpa_s->current_ssid;
+ bss = compare_scan_neighbor_results(wpa_s);
+ if (!bss) {
+ wpa_printf(MSG_DEBUG, "WNM: No BSS transition candidate match found");
+ status = WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES;
+ goto send_bss_resp_fail;
+ }
- bss = wpa_bss_get_bssid(wpa_s, bssid);
- if (!bss) {
- wpa_printf(MSG_DEBUG, "WNM: Target AP not found from "
- "BSS table");
- goto send_bss_resp_fail;
- }
-
- /* Send the BSS Management Response - Accept */
- if (wpa_s->wnm_reply) {
- wnm_send_bss_transition_mgmt_resp(wpa_s,
+ /* Associate to the network */
+ /* Send the BSS Management Response - Accept */
+ if (wpa_s->wnm_reply) {
+ wpa_s->wnm_reply = 0;
+ wnm_send_bss_transition_mgmt_resp(wpa_s,
wpa_s->wnm_dialog_token,
WNM_BSS_TM_ACCEPT,
- 0, bssid);
- }
+ 0, bss->bssid);
+ }
- wpa_s->reassociate = 1;
- wpa_supplicant_connect(wpa_s, bss, ssid);
- wnm_deallocate_memory(wpa_s);
+ if (bss == wpa_s->current_bss) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Already associated with the preferred candidate");
+ return 1;
+ }
+
+ wpa_s->reassociate = 1;
+ wpa_supplicant_connect(wpa_s, bss, ssid);
+ wnm_deallocate_memory(wpa_s);
+ return 1;
+
+send_bss_resp_fail:
+ if (!reply_on_fail)
+ return 0;
+
+ /* Send reject response for all the failures */
+
+ if (wpa_s->wnm_reply) {
+ wpa_s->wnm_reply = 0;
+ wnm_send_bss_transition_mgmt_resp(wpa_s,
+ wpa_s->wnm_dialog_token,
+ status, 0, NULL);
+ }
+ wnm_deallocate_memory(wpa_s);
+
+ return 0;
+}
+
+
+static int cand_pref_compar(const void *a, const void *b)
+{
+ const struct neighbor_report *aa = a;
+ const struct neighbor_report *bb = b;
+
+ if (!aa->preference_present && !bb->preference_present)
+ return 0;
+ if (!aa->preference_present)
+ return 1;
+ if (!bb->preference_present)
+ return -1;
+ if (bb->preference > aa->preference)
+ return 1;
+ if (bb->preference < aa->preference)
+ return -1;
+ return 0;
+}
+
+
+static void wnm_sort_cand_list(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->wnm_neighbor_report_elements)
+ return;
+ qsort(wpa_s->wnm_neighbor_report_elements,
+ wpa_s->wnm_num_neighbor_report, sizeof(struct neighbor_report),
+ cand_pref_compar);
+}
+
+
+static void wnm_dump_cand_list(struct wpa_supplicant *wpa_s)
+{
+ unsigned int i;
+
+ wpa_printf(MSG_DEBUG, "WNM: BSS Transition Candidate List");
+ if (!wpa_s->wnm_neighbor_report_elements)
+ return;
+ for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
+ struct neighbor_report *nei;
+
+ nei = &wpa_s->wnm_neighbor_report_elements[i];
+ wpa_printf(MSG_DEBUG, "%u: " MACSTR
+ " info=0x%x op_class=%u chan=%u phy=%u pref=%d freq=%d",
+ i, MAC2STR(nei->bssid), nei->bssid_info,
+ nei->regulatory_class,
+ nei->channel_number, nei->phy_type,
+ nei->preference_present ? nei->preference : -1,
+ nei->freq);
+ }
+}
+
+
+static int chan_supported(struct wpa_supplicant *wpa_s, int freq)
+{
+ unsigned int i;
+
+ for (i = 0; i < wpa_s->hw.num_modes; i++) {
+ struct hostapd_hw_modes *mode = &wpa_s->hw.modes[i];
+ int j;
+
+ for (j = 0; j < mode->num_channels; j++) {
+ struct hostapd_channel_data *chan;
+
+ chan = &mode->channels[j];
+ if (chan->freq == freq &&
+ !(chan->flag & HOSTAPD_CHAN_DISABLED))
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+static void wnm_set_scan_freqs(struct wpa_supplicant *wpa_s)
+{
+ int *freqs;
+ int num_freqs = 0;
+ unsigned int i;
+
+ if (!wpa_s->wnm_neighbor_report_elements)
+ return;
+
+ if (wpa_s->hw.modes == NULL)
+ return;
+
+ os_free(wpa_s->next_scan_freqs);
+ wpa_s->next_scan_freqs = NULL;
+
+ freqs = os_calloc(wpa_s->wnm_num_neighbor_report + 1, sizeof(int));
+ if (freqs == NULL)
+ return;
+
+ for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
+ struct neighbor_report *nei;
+
+ nei = &wpa_s->wnm_neighbor_report_elements[i];
+ if (nei->freq <= 0) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Unknown neighbor operating frequency for "
+ MACSTR " - scan all channels",
+ MAC2STR(nei->bssid));
+ os_free(freqs);
+ return;
+ }
+ if (chan_supported(wpa_s, nei->freq))
+ add_freq(freqs, &num_freqs, nei->freq);
+ }
+
+ if (num_freqs == 0) {
+ os_free(freqs);
return;
}
- /* Send reject response for all the failures */
-send_bss_resp_fail:
- wnm_deallocate_memory(wpa_s);
- if (wpa_s->wnm_reply) {
- wnm_send_bss_transition_mgmt_resp(wpa_s,
- wpa_s->wnm_dialog_token,
- WNM_BSS_TM_REJECT_UNSPECIFIED,
- 0, NULL);
- }
- return;
+ wpa_printf(MSG_DEBUG,
+ "WNM: Scan %d frequencies based on transition candidate list",
+ num_freqs);
+ wpa_s->next_scan_freqs = freqs;
}
@@ -620,20 +787,28 @@
const u8 *pos, const u8 *end,
int reply)
{
+ unsigned int beacon_int;
+ u8 valid_int;
+
if (pos + 5 > end)
return;
+ if (wpa_s->current_bss)
+ beacon_int = wpa_s->current_bss->beacon_int;
+ else
+ beacon_int = 100; /* best guess */
+
wpa_s->wnm_dialog_token = pos[0];
wpa_s->wnm_mode = pos[1];
wpa_s->wnm_dissoc_timer = WPA_GET_LE16(pos + 2);
- wpa_s->wnm_validity_interval = pos[4];
+ valid_int = pos[4];
wpa_s->wnm_reply = reply;
wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Request: "
"dialog_token=%u request_mode=0x%x "
"disassoc_timer=%u validity_interval=%u",
wpa_s->wnm_dialog_token, wpa_s->wnm_mode,
- wpa_s->wnm_dissoc_timer, wpa_s->wnm_validity_interval);
+ wpa_s->wnm_dissoc_timer, valid_int);
pos += 5;
@@ -648,7 +823,6 @@
if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) {
char url[256];
- unsigned int beacon_int;
if (pos + 1 > end || pos + 1 + pos[0] > end) {
wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition "
@@ -659,11 +833,6 @@
url[pos[0]] = '\0';
pos += 1 + pos[0];
- if (wpa_s->current_bss)
- beacon_int = wpa_s->current_bss->beacon_int;
- else
- beacon_int = 100; /* best guess */
-
wpa_msg(wpa_s, MSG_INFO, ESS_DISASSOC_IMMINENT "%d %u %s",
wpa_sm_pmf_enabled(wpa_s->wpa),
wpa_s->wnm_dissoc_timer * beacon_int * 128 / 125, url);
@@ -681,11 +850,12 @@
}
if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) {
+ unsigned int valid_ms;
+
wpa_msg(wpa_s, MSG_INFO, "WNM: Preferred List Available");
- wpa_s->wnm_num_neighbor_report = 0;
- os_free(wpa_s->wnm_neighbor_report_elements);
- wpa_s->wnm_neighbor_report_elements = os_zalloc(
- WNM_MAX_NEIGHBOR_REPORT *
+ wnm_deallocate_memory(wpa_s);
+ wpa_s->wnm_neighbor_report_elements = os_calloc(
+ WNM_MAX_NEIGHBOR_REPORT,
sizeof(struct neighbor_report));
if (wpa_s->wnm_neighbor_report_elements == NULL)
return;
@@ -712,8 +882,34 @@
pos += len;
wpa_s->wnm_num_neighbor_report++;
}
+ wnm_sort_cand_list(wpa_s);
+ wnm_dump_cand_list(wpa_s);
+ valid_ms = valid_int * beacon_int * 128 / 125;
+ wpa_printf(MSG_DEBUG, "WNM: Candidate list valid for %u ms",
+ valid_ms);
+ os_get_reltime(&wpa_s->wnm_cand_valid_until);
+ wpa_s->wnm_cand_valid_until.sec += valid_ms / 1000;
+ wpa_s->wnm_cand_valid_until.usec += (valid_ms % 1000) * 1000;
+ wpa_s->wnm_cand_valid_until.sec +=
+ wpa_s->wnm_cand_valid_until.usec / 1000000;
+ wpa_s->wnm_cand_valid_until.usec %= 1000000;
+ os_memcpy(wpa_s->wnm_cand_from_bss, wpa_s->bssid, ETH_ALEN);
- wpa_s->scan_res_handler = wnm_scan_response;
+ if (wpa_s->last_scan_res_used > 0) {
+ struct os_reltime now;
+
+ os_get_reltime(&now);
+ if (!os_reltime_expired(&now, &wpa_s->last_scan, 10)) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Try to use recent scan results");
+ if (wnm_scan_process(wpa_s, 0) > 0)
+ return;
+ wpa_printf(MSG_DEBUG,
+ "WNM: No match in previous scan results - try a new scan");
+ }
+ }
+
+ wnm_set_scan_freqs(wpa_s);
wpa_supplicant_req_scan(wpa_s, 0, 0);
} else if (reply) {
enum bss_trans_mgmt_status_code status;
diff --git a/wpa_supplicant/wnm_sta.h b/wpa_supplicant/wnm_sta.h
index d2eb96d..8de4348 100644
--- a/wpa_supplicant/wnm_sta.h
+++ b/wpa_supplicant/wnm_sta.h
@@ -9,37 +9,12 @@
#ifndef WNM_STA_H
#define WNM_STA_H
-struct tsf_info {
- u8 tsf_offset[2];
- u8 beacon_interval[2];
-};
-
-struct condensed_country_string {
- u8 country_string[2];
-};
-
-struct bss_transition_candidate {
- u8 preference;
-};
-
-struct bss_termination_duration {
- u8 duration[10];
-};
-
-struct bearing {
- u8 bearing[8];
-};
-
struct measurement_pilot {
u8 measurement_pilot;
u8 subelem_len;
u8 subelems[255];
};
-struct rrm_enabled_capabilities {
- u8 capabilities[5];
-};
-
struct multiple_bssid {
u8 max_bssid_indicator;
u8 subelem_len;
@@ -48,18 +23,29 @@
struct neighbor_report {
u8 bssid[ETH_ALEN];
- u8 bssid_information[4];
+ u32 bssid_info;
u8 regulatory_class;
u8 channel_number;
u8 phy_type;
- struct tsf_info *tsf_info;
- struct condensed_country_string *con_coun_str;
- struct bss_transition_candidate *bss_tran_can;
- struct bss_termination_duration *bss_term_dur;
- struct bearing *bearing;
+ u8 preference; /* valid if preference_present=1 */
+ u16 tsf_offset; /* valid if tsf_present=1 */
+ u16 beacon_int; /* valid if tsf_present=1 */
+ char country[2]; /* valid if country_present=1 */
+ u8 rm_capab[5]; /* valid if rm_capab_present=1 */
+ u16 bearing; /* valid if bearing_present=1 */
+ u16 rel_height; /* valid if bearing_present=1 */
+ u32 distance; /* valid if bearing_present=1 */
+ u64 bss_term_tsf; /* valid if bss_term_present=1 */
+ u16 bss_term_dur; /* valid if bss_term_present=1 */
+ unsigned int preference_present:1;
+ unsigned int tsf_present:1;
+ unsigned int country_present:1;
+ unsigned int rm_capab_present:1;
+ unsigned int bearing_present:1;
+ unsigned int bss_term_present:1;
struct measurement_pilot *meas_pilot;
- struct rrm_enabled_capabilities *rrm_cap;
struct multiple_bssid *mul_bssid;
+ int freq;
};
@@ -69,11 +55,23 @@
void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
const struct ieee80211_mgmt *mgmt, size_t len);
-void wnm_scan_response(struct wpa_supplicant *wpa_s,
- struct wpa_scan_results *scan_res);
-
int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
u8 query_reason);
void wnm_deallocate_memory(struct wpa_supplicant *wpa_s);
+
+#ifdef CONFIG_WNM
+
+int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail);
+
+#else /* CONFIG_WNM */
+
+static inline int wnm_scan_process(struct wpa_supplicant *wpa_s,
+ int reply_on_fail)
+{
+ return 0;
+}
+
+#endif /* CONFIG_WNM */
+
#endif /* WNM_STA_H */
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index fe30b41..911effe 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - command line interface for wpa_supplicant daemon
- * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -28,7 +28,7 @@
static const char *wpa_cli_version =
"wpa_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> and contributors";
static const char *wpa_cli_license =
@@ -333,7 +333,7 @@
return -1;
res = os_snprintf(cfile, flen, "%s/%s", ctrl_iface_dir,
ifname);
- if (res < 0 || res >= flen) {
+ if (os_snprintf_error(flen, res)) {
os_free(cfile);
return -1;
}
@@ -448,13 +448,13 @@
end = buf + buflen;
res = os_snprintf(pos, end - pos, "%s", cmd);
- if (res < 0 || res >= end - pos)
+ 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 (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
goto fail;
pos += res;
}
@@ -584,7 +584,7 @@
if (argc == 1) {
res = os_snprintf(cmd, sizeof(cmd), "SET %s ", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ if (os_snprintf_error(sizeof(cmd), res)) {
printf("Too long SET command.\n");
return -1;
}
@@ -610,7 +610,8 @@
/* global configuration parameters */
"eapol_version", "ap_scan", "disable_scan_offload",
"fast_reauth", "opensc_engine_path", "pkcs11_engine_path",
- "pkcs11_module_path", "pcsc_reader", "pcsc_pin",
+ "pkcs11_module_path", "openssl_ciphers",
+ "pcsc_reader", "pcsc_pin",
"driver_param", "dot11RSNAConfigPMKLifetime",
"dot11RSNAConfigPMKReauthThreshold",
"dot11RSNAConfigSATimeout",
@@ -732,7 +733,7 @@
res = os_snprintf(cmd, sizeof(cmd), "BSS_FLUSH 0");
else
res = os_snprintf(cmd, sizeof(cmd), "BSS_FLUSH %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ if (os_snprintf_error(sizeof(cmd), res)) {
printf("Too long BSS_FLUSH command.\n");
return -1;
}
@@ -907,7 +908,7 @@
return -1;
}
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ if (os_snprintf_error(sizeof(cmd), res)) {
printf("Too long WPS_REG command.\n");
return -1;
}
@@ -1032,7 +1033,7 @@
return -1;
}
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ if (os_snprintf_error(sizeof(cmd), res)) {
printf("Too long WPS_ER_CONFIG command.\n");
return -1;
}
@@ -1084,14 +1085,14 @@
pos = cmd;
ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "IDENTITY-%s:%s",
argv[0], argv[1]);
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
printf("Too long IDENTITY command.\n");
return -1;
}
pos += ret;
for (i = 2; i < argc; i++) {
ret = os_snprintf(pos, end - pos, " %s", argv[i]);
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
printf("Too long IDENTITY command.\n");
return -1;
}
@@ -1117,14 +1118,14 @@
pos = cmd;
ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSWORD-%s:%s",
argv[0], argv[1]);
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
printf("Too long PASSWORD command.\n");
return -1;
}
pos += ret;
for (i = 2; i < argc; i++) {
ret = os_snprintf(pos, end - pos, " %s", argv[i]);
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
printf("Too long PASSWORD command.\n");
return -1;
}
@@ -1151,14 +1152,14 @@
pos = cmd;
ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "NEW_PASSWORD-%s:%s",
argv[0], argv[1]);
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
printf("Too long NEW_PASSWORD command.\n");
return -1;
}
pos += ret;
for (i = 2; i < argc; i++) {
ret = os_snprintf(pos, end - pos, " %s", argv[i]);
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
printf("Too long NEW_PASSWORD command.\n");
return -1;
}
@@ -1184,14 +1185,14 @@
pos = cmd;
ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PIN-%s:%s",
argv[0], argv[1]);
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
printf("Too long PIN command.\n");
return -1;
}
pos += ret;
for (i = 2; i < argc; i++) {
ret = os_snprintf(pos, end - pos, " %s", argv[i]);
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
printf("Too long PIN command.\n");
return -1;
}
@@ -1216,14 +1217,14 @@
pos = cmd;
ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "OTP-%s:%s",
argv[0], argv[1]);
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
printf("Too long OTP command.\n");
return -1;
}
pos += ret;
for (i = 2; i < argc; i++) {
ret = os_snprintf(pos, end - pos, " %s", argv[i]);
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
printf("Too long OTP command.\n");
return -1;
}
@@ -1249,14 +1250,14 @@
pos = cmd;
ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "SIM-%s:%s",
argv[0], argv[1]);
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
printf("Too long SIM command.\n");
return -1;
}
pos += ret;
for (i = 2; i < argc; i++) {
ret = os_snprintf(pos, end - pos, " %s", argv[i]);
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
printf("Too long SIM command.\n");
return -1;
}
@@ -1282,14 +1283,14 @@
pos = cmd;
ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSPHRASE-%s:%s",
argv[0], argv[1]);
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
printf("Too long PASSPHRASE command.\n");
return -1;
}
pos += ret;
for (i = 2; i < argc; i++) {
ret = os_snprintf(pos, end - pos, " %s", argv[i]);
- if (ret < 0 || ret >= end - pos) {
+ if (os_snprintf_error(end - pos, ret)) {
printf("Too long PASSPHRASE command.\n");
return -1;
}
@@ -1576,6 +1577,10 @@
wpa_cli_close_connection();
os_free(ctrl_ifname);
ctrl_ifname = os_strdup(argv[0]);
+ if (!ctrl_ifname) {
+ printf("Failed to allocate memory\n");
+ return 0;
+ }
if (wpa_cli_open_connection(ctrl_ifname, 1) == 0) {
printf("Connected to interface '%s.\n", ctrl_ifname);
@@ -1625,7 +1630,7 @@
argc > 1 ? argv[1] : "", argc > 2 ? argv[2] : "",
argc > 3 ? argv[3] : "", argc > 4 ? argv[4] : "",
argc > 5 ? argv[5] : "");
- if (res < 0 || (size_t) res >= sizeof(cmd))
+ if (os_snprintf_error(sizeof(cmd), res))
return -1;
cmd[sizeof(cmd) - 1] = '\0';
return wpa_ctrl_command(ctrl, cmd);
@@ -1751,6 +1756,31 @@
}
+#ifdef CONFIG_MESH
+
+static int wpa_cli_cmd_mesh_interface_add(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "MESH_INTERFACE_ADD", 0, argc, argv);
+}
+
+
+static int wpa_cli_cmd_mesh_group_add(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "MESH_GROUP_ADD", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_mesh_group_remove(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "MESH_GROUP_REMOVE", 1, argc, argv);
+}
+
+#endif /* CONFIG_MESH */
+
+
#ifdef CONFIG_P2P
static int wpa_cli_cmd_p2p_find(struct wpa_ctrl *ctrl, int argc, char *argv[])
@@ -1914,7 +1944,7 @@
res = os_snprintf(cmd, sizeof(cmd), "P2P_SERV_DISC_RESP %s %s %s %s",
argv[0], argv[1], argv[2], argv[3]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
+ if (os_snprintf_error(sizeof(cmd), res))
return -1;
cmd[sizeof(cmd) - 1] = '\0';
return wpa_ctrl_command(ctrl, cmd);
@@ -1962,7 +1992,7 @@
res = os_snprintf(cmd, sizeof(cmd),
"P2P_SERVICE_ADD %s %s %s",
argv[0], argv[1], argv[2]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
+ if (os_snprintf_error(sizeof(cmd), res))
return -1;
cmd[sizeof(cmd) - 1] = '\0';
return wpa_ctrl_command(ctrl, cmd);
@@ -1989,7 +2019,7 @@
res = os_snprintf(cmd, sizeof(cmd),
"P2P_SERVICE_DEL %s %s",
argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
+ if (os_snprintf_error(sizeof(cmd), res))
return -1;
cmd[sizeof(cmd) - 1] = '\0';
return wpa_ctrl_command(ctrl, cmd);
@@ -2211,7 +2241,7 @@
res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_SET %s %s",
argv[0], argc > 1 ? argv[1] : "");
- if (res < 0 || (size_t) res >= sizeof(cmd))
+ if (os_snprintf_error(sizeof(cmd), res))
return -1;
cmd[sizeof(cmd) - 1] = '\0';
return wpa_ctrl_command(ctrl, cmd);
@@ -2232,7 +2262,7 @@
res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_GET %s",
argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
+ if (os_snprintf_error(sizeof(cmd), res))
return -1;
cmd[sizeof(cmd) - 1] = '\0';
return wpa_ctrl_command(ctrl, cmd);
@@ -2379,6 +2409,41 @@
}
+static int wpa_cli_cmd_wmm_ac_addts(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "WMM_AC_ADDTS", 3, argc, argv);
+}
+
+
+static int wpa_cli_cmd_wmm_ac_delts(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "WMM_AC_DELTS", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_wmm_ac_status(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "WMM_AC_STATUS");
+}
+
+
+static int wpa_cli_cmd_tdls_chan_switch(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "TDLS_CHAN_SWITCH", 2, argc, argv);
+}
+
+
+static int wpa_cli_cmd_tdls_cancel_chan_switch(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "TDLS_CANCEL_CHAN_SWITCH", 1, argc, argv);
+}
+
+
static int wpa_cli_cmd_signal_poll(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -2463,6 +2528,26 @@
}
+static int wpa_cli_cmd_neighbor_rep_request(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "NEIGHBOR_REP_REQUEST", 0, argc, argv);
+}
+
+
+static int wpa_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "ERP_FLUSH");
+}
+
+
+static int wpa_cli_cmd_mac_rand_scan(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "MAC_RAND_SCAN", 1, argc, argv);
+}
+
+
enum wpa_cli_cmd_flags {
cli_cmd_flag_none = 0x00,
cli_cmd_flag_sensitive = 0x01
@@ -2780,6 +2865,17 @@
{ "roam", wpa_cli_cmd_roam, wpa_cli_complete_bss,
cli_cmd_flag_none,
"<addr> = roam to the specified BSS" },
+#ifdef CONFIG_MESH
+ { "mesh_interface_add", wpa_cli_cmd_mesh_interface_add, NULL,
+ cli_cmd_flag_none,
+ "[ifname] = Create a new mesh interface" },
+ { "mesh_group_add", wpa_cli_cmd_mesh_group_add, NULL,
+ cli_cmd_flag_none,
+ "<network id> = join a mesh network (disable others)" },
+ { "mesh_group_remove", wpa_cli_cmd_mesh_group_remove, NULL,
+ cli_cmd_flag_none,
+ "<ifname> = Remove mesh group interface" },
+#endif /* CONFIG_MESH */
#ifdef CONFIG_P2P
{ "p2p_find", wpa_cli_cmd_p2p_find, wpa_cli_complete_p2p_find,
cli_cmd_flag_none,
@@ -2920,6 +3016,25 @@
{ "tdls_teardown", wpa_cli_cmd_tdls_teardown, NULL,
cli_cmd_flag_none,
"<addr> = tear down TDLS with <addr>" },
+ { "wmm_ac_addts", wpa_cli_cmd_wmm_ac_addts, NULL,
+ cli_cmd_flag_none,
+ "<uplink/downlink/bidi> <tsid=0..7> <up=0..7> [nominal_msdu_size=#] "
+ "[mean_data_rate=#] [min_phy_rate=#] [sba=#] [fixed_nominal_msdu] "
+ "= add WMM-AC traffic stream" },
+ { "wmm_ac_delts", wpa_cli_cmd_wmm_ac_delts, NULL,
+ cli_cmd_flag_none,
+ "<tsid> = delete WMM-AC traffic stream" },
+ { "wmm_ac_status", wpa_cli_cmd_wmm_ac_status, NULL,
+ cli_cmd_flag_none,
+ "= show status for Wireless Multi-Media Admission-Control" },
+ { "tdls_chan_switch", wpa_cli_cmd_tdls_chan_switch, NULL,
+ cli_cmd_flag_none,
+ "<addr> <oper class> <freq> [sec_channel_offset=] [center_freq1=] "
+ "[center_freq2=] [bandwidth=] [ht|vht] = enable channel switching "
+ "with TDLS peer" },
+ { "tdls_cancel_chan_switch", wpa_cli_cmd_tdls_cancel_chan_switch, NULL,
+ cli_cmd_flag_none,
+ "<addr> = disable channel switching with TDLS peer <addr>" },
{ "signal_poll", wpa_cli_cmd_signal_poll, NULL,
cli_cmd_flag_none,
"= get signal parameters" },
@@ -2952,6 +3067,18 @@
{ "vendor", wpa_cli_cmd_vendor, NULL, cli_cmd_flag_none,
"<vendor id> <command id> [<hex formatted command argument>] = Send vendor command"
},
+ { "neighbor_rep_request",
+ wpa_cli_cmd_neighbor_rep_request, NULL, cli_cmd_flag_none,
+ "[ssid=<SSID>] = Trigger request to AP for neighboring AP report "
+ "(with optional given SSID, default: current SSID)"
+ },
+ { "erp_flush", wpa_cli_cmd_erp_flush, NULL, cli_cmd_flag_none,
+ "= flush ERP keys" },
+ { "mac_rand_scan",
+ wpa_cli_cmd_mac_rand_scan, NULL, cli_cmd_flag_none,
+ "<scan|sched|pno|all> enable=<0/1> [addr=mac-address "
+ "mask=mac-address-mask] = scan MAC randomization"
+ },
{ NULL, NULL, NULL, cli_cmd_flag_none, NULL }
};
@@ -3245,6 +3372,14 @@
wpa_cli_connected = 0;
wpa_cli_exec(action_file, ifname, "DISCONNECTED");
}
+ } else if (str_match(pos, MESH_GROUP_STARTED)) {
+ wpa_cli_exec(action_file, ctrl_ifname, pos);
+ } else if (str_match(pos, MESH_GROUP_REMOVED)) {
+ wpa_cli_exec(action_file, ctrl_ifname, pos);
+ } else if (str_match(pos, MESH_PEER_CONNECTED)) {
+ wpa_cli_exec(action_file, ctrl_ifname, pos);
+ } else if (str_match(pos, MESH_PEER_DISCONNECTED)) {
+ wpa_cli_exec(action_file, ctrl_ifname, pos);
} else if (str_match(pos, P2P_EVENT_GROUP_STARTED)) {
wpa_cli_exec(action_file, ifname, pos);
} else if (str_match(pos, P2P_EVENT_GROUP_REMOVED)) {
@@ -3594,7 +3729,7 @@
break;
*end = '\0';
ret = os_snprintf(txt, sizeof(txt), "ifname=%s", pos);
- if (ret > 0 && ret < (int) sizeof(txt))
+ if (!os_snprintf_error(sizeof(txt), ret))
cli_txt_list_add(&ifnames, txt);
pos = end + 1;
}
@@ -3612,7 +3747,8 @@
if (!wpa_cli_open_connection(ctrl_ifname, 1) == 0) {
if (!warning_displayed) {
printf("Could not connect to wpa_supplicant: "
- "%s - re-trying\n", ctrl_ifname);
+ "%s - re-trying\n",
+ ctrl_ifname ? ctrl_ifname : "(nil)");
warning_displayed = 1;
}
eloop_register_timeout(1, 0, try_connection, NULL, NULL);
@@ -3873,7 +4009,8 @@
wpa_cli_open_connection(ctrl_ifname, 0) < 0) {
fprintf(stderr, "Failed to connect to non-global "
"ctrl_ifname: %s error: %s\n",
- ctrl_ifname, strerror(errno));
+ ctrl_ifname ? ctrl_ifname : "(nil)",
+ strerror(errno));
return -1;
}
diff --git a/wpa_supplicant/wpa_gui-qt4/scanresults.cpp b/wpa_supplicant/wpa_gui-qt4/scanresults.cpp
index 063347e..ae0c240 100644
--- a/wpa_supplicant/wpa_gui-qt4/scanresults.cpp
+++ b/wpa_supplicant/wpa_gui-qt4/scanresults.cpp
@@ -12,6 +12,7 @@
#include "signalbar.h"
#include "wpagui.h"
#include "networkconfig.h"
+#include "scanresultsitem.h"
ScanResults::ScanResults(QWidget *parent, const char *, bool, Qt::WFlags)
@@ -95,7 +96,7 @@
ssid = (*it).mid(pos);
}
- QTreeWidgetItem *item = new QTreeWidgetItem(scanResultsWidget);
+ ScanResultsItem *item = new ScanResultsItem(scanResultsWidget);
if (item) {
item->setText(0, ssid);
item->setText(1, bssid);
diff --git a/wpa_supplicant/wpa_gui-qt4/scanresultsitem.cpp b/wpa_supplicant/wpa_gui-qt4/scanresultsitem.cpp
new file mode 100644
index 0000000..9cd937c
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/scanresultsitem.cpp
@@ -0,0 +1,18 @@
+/*
+ * wpa_gui - ScanResultsItem class
+ * Copyright (c) 2015, Adrian Nowicki <adinowicki@gmail.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "scanresultsitem.h"
+
+bool ScanResultsItem::operator< (const QTreeWidgetItem &other) const
+{
+ int sortCol = treeWidget()->sortColumn();
+ if (sortCol == 2 || sortCol == 3) {
+ return text(sortCol).toInt() < other.text(sortCol).toInt();
+ }
+ return text(sortCol) < other.text(sortCol);
+}
diff --git a/wpa_supplicant/wpa_gui-qt4/scanresultsitem.h b/wpa_supplicant/wpa_gui-qt4/scanresultsitem.h
new file mode 100644
index 0000000..835b7c0
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/scanresultsitem.h
@@ -0,0 +1,21 @@
+/*
+ * wpa_gui - ScanResultsItem class
+ * Copyright (c) 2015, Adrian Nowicki <adinowicki@gmail.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SCANRESULTSITEM_H
+#define SCANRESULTSITEM_H
+
+#include <QtGui>
+
+class ScanResultsItem : public QTreeWidgetItem
+{
+public:
+ ScanResultsItem(QTreeWidget *tree) : QTreeWidgetItem(tree) {}
+ bool operator< (const QTreeWidgetItem &other) const;
+};
+
+#endif /* SCANRESULTSITEM_H */
diff --git a/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro b/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro
index 3c81929..69bc0f6 100644
--- a/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro
+++ b/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro
@@ -34,6 +34,7 @@
wpagui.h \
eventhistory.h \
scanresults.h \
+ scanresultsitem.h \
signalbar.h \
userdatarequest.h \
networkconfig.h \
@@ -45,6 +46,7 @@
wpagui.cpp \
eventhistory.cpp \
scanresults.cpp \
+ scanresultsitem.cpp \
signalbar.cpp \
userdatarequest.cpp \
networkconfig.cpp \
diff --git a/wpa_supplicant/wpa_gui-qt4/wpagui.cpp b/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
index 6bba8d2..6276176 100644
--- a/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
+++ b/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
@@ -36,6 +36,7 @@
: QMainWindow(parent), app(_app)
{
setupUi(this);
+ this->setWindowFlags(Qt::Dialog);
#ifdef CONFIG_NATIVE_WINDOWS
fileStopServiceAction = new QAction(this);
@@ -129,6 +130,7 @@
udr = NULL;
tray_icon = NULL;
startInTray = false;
+ quietMode = false;
ctrl_iface = NULL;
ctrl_conn = NULL;
monitor_conn = NULL;
@@ -233,7 +235,7 @@
{
int c;
for (;;) {
- c = getopt(qApp->argc(), qApp->argv(), "i:p:t");
+ c = getopt(qApp->argc(), qApp->argv(), "i:p:tq");
if (c < 0)
break;
switch (c) {
@@ -248,6 +250,9 @@
case 't':
startInTray = true;
break;
+ case 'q':
+ quietMode = true;
+ break;
}
}
}
@@ -491,6 +496,7 @@
textSsid->clear();
textBssid->clear();
textIpAddress->clear();
+ updateTrayToolTip(tr("no status information"));
#ifdef CONFIG_NATIVE_WINDOWS
static bool first = true;
@@ -538,6 +544,7 @@
} else if (strcmp(start, "ssid") == 0) {
ssid_updated = true;
textSsid->setText(pos);
+ updateTrayToolTip(pos + tr(" (associated)"));
} else if (strcmp(start, "ip_address") == 0) {
ipaddr_updated = true;
textIpAddress->setText(pos);
@@ -585,8 +592,10 @@
textStatus->clear();
if (!auth_updated)
textAuthentication->clear();
- if (!ssid_updated)
+ if (!ssid_updated) {
textSsid->clear();
+ updateTrayToolTip(tr("(not-associated)"));
+ }
if (!bssid_updated)
textBssid->clear();
if (!ipaddr_updated)
@@ -1270,7 +1279,6 @@
QApplication::setQuitOnLastWindowClosed(false);
tray_icon = new QSystemTrayIcon(this);
- tray_icon->setToolTip(qAppName() + tr(" - wpa_supplicant user interface"));
if (QImageReader::supportedImageFormats().contains(QByteArray("svg")))
tray_icon->setIcon(QIcon(":/icons/wpa_gui.svg"));
else
@@ -1332,7 +1340,7 @@
if (!QSystemTrayIcon::supportsMessages())
return;
- if (isVisible() || !tray_icon || !tray_icon->isVisible())
+ if (isVisible() || !tray_icon || !tray_icon->isVisible() || quietMode)
return;
tray_icon->showMessage(qAppName(), msg, type, sec * 1000);
@@ -1407,6 +1415,13 @@
}
+void WpaGui::updateTrayToolTip(const QString &msg)
+{
+ if (tray_icon)
+ tray_icon->setToolTip(msg);
+}
+
+
void WpaGui::closeEvent(QCloseEvent *event)
{
if (eh) {
diff --git a/wpa_supplicant/wpa_gui-qt4/wpagui.h b/wpa_supplicant/wpa_gui-qt4/wpagui.h
index 340286c..026eacb 100644
--- a/wpa_supplicant/wpa_gui-qt4/wpagui.h
+++ b/wpa_supplicant/wpa_gui-qt4/wpagui.h
@@ -70,6 +70,7 @@
virtual void showTrayMessage(QSystemTrayIcon::MessageIcon type,
int sec, const QString &msg);
virtual void showTrayStatus();
+ virtual void updateTrayToolTip(const QString &msg);
virtual void wpsDialog();
virtual void peersDialog();
virtual void tabChanged(int index);
@@ -116,6 +117,7 @@
void createTrayIcon(bool);
bool ackTrayIcon;
bool startInTray;
+ bool quietMode;
int openCtrlConnection(const char *ifname);
diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c
index 5426177..ac38d69 100644
--- a/wpa_supplicant/wpa_priv.c
+++ b/wpa_supplicant/wpa_priv.c
@@ -202,7 +202,9 @@
if (assoc->ssid_len > 32)
return;
params.ssid_len = assoc->ssid_len;
- params.freq = assoc->freq;
+ params.freq.mode = assoc->hwmode;
+ params.freq.freq = assoc->freq;
+ params.freq.channel = assoc->channel;
if (assoc->wpa_ie_len) {
params.wpa_ie = (u8 *) (assoc + 1);
params.wpa_ie_len = assoc->wpa_ie_len;
@@ -333,7 +335,7 @@
msg.msg_namelen = sizeof(iface->l2_addr);
if (sendmsg(iface->fd, &msg, 0) < 0) {
- perror("sendmsg(l2 rx)");
+ wpa_printf(MSG_ERROR, "sendmsg(l2 rx): %s", strerror(errno));
}
}
@@ -465,7 +467,7 @@
res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &from,
&fromlen);
if (res < 0) {
- perror("recvfrom");
+ wpa_printf(MSG_ERROR, "recvfrom: %s", strerror(errno));
return;
}
@@ -613,7 +615,7 @@
iface->fd = socket(PF_UNIX, SOCK_DGRAM, 0);
if (iface->fd < 0) {
- perror("socket(PF_UNIX)");
+ wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
wpa_priv_interface_deinit(iface);
return NULL;
}
@@ -631,15 +633,16 @@
"allow connections - assuming it was "
"leftover from forced program termination");
if (unlink(iface->sock_name) < 0) {
- perror("unlink[ctrl_iface]");
- wpa_printf(MSG_ERROR, "Could not unlink "
- "existing ctrl_iface socket '%s'",
- iface->sock_name);
+ wpa_printf(MSG_ERROR,
+ "Could not unlink existing ctrl_iface socket '%s': %s",
+ iface->sock_name, strerror(errno));
goto fail;
}
if (bind(iface->fd, (struct sockaddr *) &addr,
sizeof(addr)) < 0) {
- perror("wpa-priv-iface-init: bind(PF_UNIX)");
+ wpa_printf(MSG_ERROR,
+ "wpa-priv-iface-init: bind(PF_UNIX): %s",
+ strerror(errno));
goto fail;
}
wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
@@ -654,7 +657,7 @@
}
if (chmod(iface->sock_name, S_IRWXU | S_IRWXG | S_IRWXO) < 0) {
- perror("chmod");
+ wpa_printf(MSG_ERROR, "chmod: %s", strerror(errno));
goto fail;
}
@@ -686,7 +689,8 @@
msg.msg_namelen = sizeof(iface->drv_addr);
if (sendmsg(iface->fd, &msg, 0) < 0) {
- perror("sendmsg(wpas_socket)");
+ wpa_printf(MSG_ERROR, "sendmsg(wpas_socket): %s",
+ strerror(errno));
return -1;
}
@@ -901,7 +905,8 @@
msg.msg_namelen = sizeof(iface->drv_addr);
if (sendmsg(iface->fd, &msg, 0) < 0)
- perror("sendmsg(wpas_socket)");
+ wpa_printf(MSG_ERROR, "sendmsg(wpas_socket): %s",
+ strerror(errno));
}
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index eef3d21..434847d 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant
- * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -33,6 +33,7 @@
#include "rsn_supp/pmksa_cache.h"
#include "common/wpa_ctrl.h"
#include "common/ieee802_11_defs.h"
+#include "common/hw_features_common.h"
#include "p2p/p2p.h"
#include "blacklist.h"
#include "wpas_glue.h"
@@ -52,10 +53,11 @@
#include "hs20_supplicant.h"
#include "wnm_sta.h"
#include "wpas_kay.h"
+#include "mesh.h"
const char *wpa_supplicant_version =
"wpa_supplicant v" VERSION_STR "\n"
-"Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi> and contributors";
const char *wpa_supplicant_license =
"This software may be distributed under the terms of the BSD license.\n"
@@ -105,9 +107,6 @@
"\n";
#endif /* CONFIG_NO_STDOUT_DEBUG */
-struct wowlan_triggers *wpa_get_wowlan_triggers(const char *wowlan_triggers,
- struct wpa_driver_capa *capa);
-
/* Configure default/group WEP keys for static WEP */
int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
{
@@ -134,6 +133,7 @@
size_t keylen;
enum wpa_alg alg;
u8 seq[6] = { 0 };
+ int ret;
/* IBSS/WPA-None uses only one key (Group) for both receiving and
* sending unicast and multicast packets. */
@@ -177,7 +177,9 @@
/* TODO: should actually remember the previously used seq#, both for TX
* and RX from each STA.. */
- return wpa_drv_set_key(wpa_s, alg, NULL, 0, 1, seq, 6, key, keylen);
+ ret = wpa_drv_set_key(wpa_s, alg, NULL, 0, 1, seq, 6, key, keylen);
+ os_memset(key, 0, sizeof(key));
+ return ret;
}
@@ -300,11 +302,28 @@
wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
wpa_s->key_mgmt != WPA_KEY_MGMT_WPS;
eapol_conf.external_sim = wpa_s->conf->external_sim;
- eapol_conf.wps = wpa_s->key_mgmt == WPA_KEY_MGMT_WPS;
+
+#ifdef CONFIG_WPS
+ if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) {
+ eapol_conf.wps |= EAPOL_LOCAL_WPS_IN_USE;
+ if (wpa_s->current_bss) {
+ struct wpabuf *ie;
+ ie = wpa_bss_get_vendor_ie_multi(wpa_s->current_bss,
+ WPS_IE_VENDOR_TYPE);
+ if (ie) {
+ if (wps_is_20(ie))
+ eapol_conf.wps |=
+ EAPOL_PEER_IS_WPS20_AP;
+ wpabuf_free(ie);
+ }
+ }
+ }
+#endif /* CONFIG_WPS */
+
eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
-#endif /* IEEE8021X_EAPOL */
ieee802_1x_alloc_kay_sm(wpa_s, ssid);
+#endif /* IEEE8021X_EAPOL */
}
@@ -393,6 +412,10 @@
l2_packet_deinit(wpa_s->l2_br);
wpa_s->l2_br = NULL;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ l2_packet_deinit(wpa_s->l2_test);
+ wpa_s->l2_test = NULL;
+#endif /* CONFIG_TESTING_OPTIONS */
if (wpa_s->conf != NULL) {
struct wpa_ssid *ssid;
@@ -416,6 +439,7 @@
wpa_tdls_deinit(wpa_s->wpa);
#endif /* CONFIG_TDLS */
+ wmm_ac_clear_saved_tspecs(wpa_s);
pmksa_candidate_free(wpa_s->wpa);
wpa_sm_deinit(wpa_s->wpa);
wpa_s->wpa = NULL;
@@ -465,6 +489,8 @@
os_free(wpa_s->manual_sched_scan_freqs);
wpa_s->manual_sched_scan_freqs = NULL;
+ wpas_mac_addr_rand_scan_clear(wpa_s, MAC_ADDR_RAND_ALL);
+
gas_query_deinit(wpa_s->gas);
wpa_s->gas = NULL;
@@ -504,6 +530,8 @@
wpabuf_free(wpa_s->vendor_elem[i]);
wpa_s->vendor_elem[i] = NULL;
}
+
+ wmm_ac_notify_disassoc(wpa_s);
}
@@ -736,6 +764,9 @@
if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
wpa_supplicant_start_autoscan(wpa_s);
+ if (old_state >= WPA_ASSOCIATED && wpa_s->wpa_state < WPA_ASSOCIATED)
+ wmm_ac_notify_disassoc(wpa_s);
+
if (wpa_s->wpa_state != old_state) {
wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
@@ -845,7 +876,7 @@
/*
* TODO: should notify EAPOL SM about changes in opensc_engine_path,
- * pkcs11_engine_path, pkcs11_module_path.
+ * pkcs11_engine_path, pkcs11_module_path, openssl_ciphers.
*/
if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
/*
@@ -931,9 +962,7 @@
#ifdef CONFIG_IEEE80211W
if (!(ie->capabilities & WPA_CAPABILITY_MFPC) &&
- (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
- wpa_s->conf->pmf : ssid->ieee80211w) ==
- MGMT_FRAME_PROTECTION_REQUIRED) {
+ wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) {
wpa_msg(wpa_s, MSG_INFO, "WPA: Driver associated with an AP "
"that does not support management frame protection - "
"reject");
@@ -982,7 +1011,7 @@
wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using IEEE 802.11i/D9.0");
proto = WPA_PROTO_RSN;
} else if (bss_wpa && (ssid->proto & WPA_PROTO_WPA) &&
- wpa_parse_wpa_ie(bss_wpa, 2 +bss_wpa[1], &ie) == 0 &&
+ wpa_parse_wpa_ie(bss_wpa, 2 + bss_wpa[1], &ie) == 0 &&
(ie.group_cipher & ssid->group_cipher) &&
(ie.pairwise_cipher & ssid->pairwise_cipher) &&
(ie.key_mgmt & ssid->key_mgmt)) {
@@ -1000,6 +1029,40 @@
#endif /* CONFIG_HS20 */
} else if (bss) {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select WPA/RSN");
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: ssid proto=0x%x pairwise_cipher=0x%x group_cipher=0x%x key_mgmt=0x%x",
+ ssid->proto, ssid->pairwise_cipher, ssid->group_cipher,
+ ssid->key_mgmt);
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: BSS " MACSTR " ssid='%s'%s%s%s",
+ MAC2STR(bss->bssid),
+ wpa_ssid_txt(bss->ssid, bss->ssid_len),
+ bss_wpa ? " WPA" : "",
+ bss_rsn ? " RSN" : "",
+ bss_osen ? " OSEN" : "");
+ if (bss_rsn) {
+ wpa_hexdump(MSG_DEBUG, "RSN", bss_rsn, 2 + bss_rsn[1]);
+ if (wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie)) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Could not parse RSN element");
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "RSN: pairwise_cipher=0x%x group_cipher=0x%x key_mgmt=0x%x",
+ ie.pairwise_cipher, ie.group_cipher,
+ ie.key_mgmt);
+ }
+ }
+ if (bss_wpa) {
+ wpa_hexdump(MSG_DEBUG, "WPA", bss_wpa, 2 + bss_wpa[1]);
+ if (wpa_parse_wpa_ie(bss_wpa, 2 + bss_wpa[1], &ie)) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Could not parse WPA element");
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: pairwise_cipher=0x%x group_cipher=0x%x key_mgmt=0x%x",
+ ie.pairwise_cipher, ie.group_cipher,
+ ie.key_mgmt);
+ }
+ }
return -1;
} else {
if (ssid->proto & WPA_PROTO_OSEN)
@@ -1073,6 +1136,18 @@
sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE);
#endif /* CONFIG_SAE */
if (0) {
+#ifdef CONFIG_SUITEB192
+ } else if (sel & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
+ wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: using KEY_MGMT 802.1X with Suite B (192-bit)");
+#endif /* CONFIG_SUITEB192 */
+#ifdef CONFIG_SUITEB
+ } else if (sel & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
+ wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: using KEY_MGMT 802.1X with Suite B");
+#endif /* CONFIG_SUITEB */
#ifdef CONFIG_IEEE80211R
} else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) {
wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
@@ -1126,8 +1201,7 @@
#ifdef CONFIG_IEEE80211W
sel = ie.mgmt_group_cipher;
- if ((ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
- wpa_s->conf->pmf : ssid->ieee80211w) == NO_MGMT_FRAME_PROTECTION ||
+ if (wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION ||
!(ie.capabilities & WPA_CAPABILITY_MFPC))
sel = 0;
if (sel & WPA_CIPHER_AES_128_CMAC) {
@@ -1153,8 +1227,7 @@
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
wpa_s->mgmt_group_cipher);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP,
- (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
- wpa_s->conf->pmf : ssid->ieee80211w));
+ wpas_get_ssid_pmf(wpa_s, ssid));
#endif /* CONFIG_IEEE80211W */
if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) {
@@ -1163,7 +1236,7 @@
}
if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
- wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN);
+ wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN, NULL);
#ifndef CONFIG_NO_PBKDF2
if (bss && ssid->bssid_set && ssid->ssid_len == 0 &&
ssid->passphrase) {
@@ -1172,7 +1245,8 @@
4096, psk, PMK_LEN);
wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
psk, PMK_LEN);
- wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN);
+ wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL);
+ os_memset(psk, 0, sizeof(psk));
}
#endif /* CONFIG_NO_PBKDF2 */
#ifdef CONFIG_EXT_PASSWORD
@@ -1208,7 +1282,8 @@
wpa_hexdump_key(MSG_MSGDUMP, "PSK (from "
"external passphrase)",
psk, PMK_LEN);
- wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN);
+ wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL);
+ os_memset(psk, 0, sizeof(psk));
} else
#endif /* CONFIG_NO_PBKDF2 */
if (wpabuf_len(pw) == 2 * PMK_LEN) {
@@ -1219,7 +1294,8 @@
ext_password_free(pw);
return -1;
}
- wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN);
+ wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL);
+ os_memset(psk, 0, sizeof(psk));
} else {
wpa_msg(wpa_s, MSG_INFO, "EXT PW: No suitable "
"PSK available");
@@ -1461,8 +1537,15 @@
else
rand_style = ssid->mac_addr;
+ wmm_ac_clear_saved_tspecs(wpa_s);
+ wpa_s->reassoc_same_bss = 0;
+
if (wpa_s->last_ssid == ssid) {
wpa_dbg(wpa_s, MSG_DEBUG, "Re-association to the same ESS");
+ if (wpa_s->current_bss && wpa_s->current_bss == bss) {
+ wmm_ac_save_tspecs(wpa_s);
+ wpa_s->reassoc_same_bss = 1;
+ }
} else if (rand_style > 0) {
if (wpas_update_random_addr(wpa_s, rand_style) < 0)
return;
@@ -1510,6 +1593,31 @@
return;
}
+ if (ssid->mode == WPAS_MODE_MESH) {
+#ifdef CONFIG_MESH
+ if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MESH)) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Driver does not support mesh mode");
+ return;
+ }
+ if (bss)
+ ssid->frequency = bss->freq;
+ if (wpa_supplicant_join_mesh(wpa_s, ssid) < 0) {
+ wpa_msg(wpa_s, MSG_ERROR, "Could not join mesh");
+ return;
+ }
+ wpa_s->current_bss = bss;
+ wpa_msg_ctrl(wpa_s, MSG_INFO, MESH_GROUP_STARTED
+ "ssid=\"%s\" id=%d",
+ wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
+ ssid->id);
+#else /* CONFIG_MESH */
+ wpa_msg(wpa_s, MSG_ERROR,
+ "mesh mode support not included in the build");
+#endif /* CONFIG_MESH */
+ return;
+ }
+
#ifdef CONFIG_TDLS
if (bss)
wpa_tdls_ap_ies(wpa_s->wpa, (const u8 *) (bss + 1),
@@ -1546,6 +1654,137 @@
}
+void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
+ const struct wpa_ssid *ssid,
+ struct hostapd_freq_params *freq)
+{
+ enum hostapd_hw_mode hw_mode;
+ struct hostapd_hw_modes *mode = NULL;
+ int ht40plus[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
+ 184, 192 };
+ struct hostapd_channel_data *pri_chan = NULL, *sec_chan = NULL;
+ u8 channel;
+ int i, chan_idx, ht40 = -1, res;
+ unsigned int j;
+
+ freq->freq = ssid->frequency;
+
+ /* For IBSS check HT_IBSS flag */
+ if (ssid->mode == WPAS_MODE_IBSS &&
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_HT_IBSS))
+ return;
+
+ hw_mode = ieee80211_freq_to_chan(ssid->frequency, &channel);
+ for (i = 0; wpa_s->hw.modes && i < wpa_s->hw.num_modes; i++) {
+ if (wpa_s->hw.modes[i].mode == hw_mode) {
+ mode = &wpa_s->hw.modes[i];
+ break;
+ }
+ }
+
+ if (!mode)
+ return;
+
+ freq->ht_enabled = ht_supported(mode);
+ if (!freq->ht_enabled)
+ return;
+
+ /* Setup higher BW only for 5 GHz */
+ if (mode->mode != HOSTAPD_MODE_IEEE80211A)
+ return;
+
+ for (chan_idx = 0; chan_idx < mode->num_channels; chan_idx++) {
+ pri_chan = &mode->channels[chan_idx];
+ if (pri_chan->chan == channel)
+ break;
+ pri_chan = NULL;
+ }
+ if (!pri_chan)
+ return;
+
+ /* Check primary channel flags */
+ if (pri_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
+ return;
+
+ /* Check/setup HT40+/HT40- */
+ for (j = 0; j < ARRAY_SIZE(ht40plus); j++) {
+ if (ht40plus[j] == channel) {
+ ht40 = 1;
+ break;
+ }
+ }
+
+ /* Find secondary channel */
+ for (i = 0; i < mode->num_channels; i++) {
+ sec_chan = &mode->channels[i];
+ if (sec_chan->chan == channel + ht40 * 4)
+ break;
+ sec_chan = NULL;
+ }
+ if (!sec_chan)
+ return;
+
+ /* Check secondary channel flags */
+ if (sec_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
+ return;
+
+ freq->channel = pri_chan->chan;
+
+ switch (ht40) {
+ case -1:
+ if (!(pri_chan->flag & HOSTAPD_CHAN_HT40MINUS))
+ return;
+ freq->sec_channel_offset = -1;
+ break;
+ case 1:
+ if (!(pri_chan->flag & HOSTAPD_CHAN_HT40PLUS))
+ return;
+ freq->sec_channel_offset = 1;
+ break;
+ default:
+ break;
+ }
+
+ if (freq->sec_channel_offset) {
+ struct wpa_scan_results *scan_res;
+
+ scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0);
+ if (scan_res == NULL) {
+ /* Back to HT20 */
+ freq->sec_channel_offset = 0;
+ return;
+ }
+
+ res = check_40mhz_5g(mode, scan_res, pri_chan->chan,
+ sec_chan->chan);
+ switch (res) {
+ case 0:
+ /* Back to HT20 */
+ freq->sec_channel_offset = 0;
+ break;
+ case 1:
+ /* Configuration allowed */
+ break;
+ case 2:
+ /* Switch pri/sec channels */
+ freq->freq = hw_get_freq(mode, sec_chan->chan);
+ freq->sec_channel_offset = -freq->sec_channel_offset;
+ freq->channel = sec_chan->chan;
+ break;
+ default:
+ freq->sec_channel_offset = 0;
+ break;
+ }
+
+ wpa_scan_results_free(scan_res);
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "IBSS/mesh: setup freq channel %d, sec_channel_offset %d",
+ freq->channel, freq->sec_channel_offset);
+}
+
+
static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
{
struct wpa_connect_work *cwork = work->ctx;
@@ -1593,7 +1832,8 @@
os_memset(¶ms, 0, sizeof(params));
wpa_s->reassociate = 0;
wpa_s->eap_expected_failure = 0;
- if (bss && !wpas_driver_bss_selection(wpa_s)) {
+ if (bss &&
+ (!wpas_driver_bss_selection(wpa_s) || wpas_wps_searching(wpa_s))) {
#ifdef CONFIG_IEEE80211R
const u8 *ie, *md = NULL;
#endif /* CONFIG_IEEE80211R */
@@ -1793,6 +2033,18 @@
}
}
+ if (wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ]) {
+ struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ];
+ size_t len;
+
+ len = sizeof(wpa_ie) - wpa_ie_len;
+ if (wpabuf_len(buf) <= len) {
+ os_memcpy(wpa_ie + wpa_ie_len,
+ wpabuf_head(buf), wpabuf_len(buf));
+ wpa_ie_len += wpabuf_len(buf);
+ }
+ }
+
wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
use_crypt = 1;
cipher_pairwise = wpa_s->pairwise_cipher;
@@ -1856,24 +2108,10 @@
params.fixed_bssid = 1;
}
- if (ssid->mode == WPAS_MODE_IBSS && ssid->frequency > 0 &&
- params.freq.freq == 0) {
- enum hostapd_hw_mode hw_mode;
- u8 channel;
-
- params.freq.freq = ssid->frequency;
-
- hw_mode = ieee80211_freq_to_chan(ssid->frequency, &channel);
- for (i = 0; wpa_s->hw.modes && i < wpa_s->hw.num_modes; i++) {
- if (wpa_s->hw.modes[i].mode == hw_mode) {
- struct hostapd_hw_modes *mode;
-
- mode = &wpa_s->hw.modes[i];
- params.freq.ht_enabled = ht_supported(mode);
- break;
- }
- }
- }
+ /* Initial frequency for IBSS/mesh */
+ if ((ssid->mode == WPAS_MODE_IBSS || ssid->mode == WPAS_MODE_MESH) &&
+ ssid->frequency > 0 && params.freq.freq == 0)
+ ibss_mesh_setup_freq(wpa_s, ssid, ¶ms.freq);
if (ssid->mode == WPAS_MODE_IBSS) {
if (ssid->beacon_int)
@@ -1906,12 +2144,28 @@
params.psk = ssid->psk;
}
+ if (wpa_s->conf->key_mgmt_offload) {
+ if (params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
+ params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
+ params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
+ params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ params.req_key_mgmt_offload =
+ ssid->proactive_key_caching < 0 ?
+ wpa_s->conf->okc : ssid->proactive_key_caching;
+ else
+ params.req_key_mgmt_offload = 1;
+
+ if ((params.key_mgmt_suite == WPA_KEY_MGMT_PSK ||
+ params.key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
+ params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK) &&
+ ssid->psk_set)
+ params.psk = ssid->psk;
+ }
+
params.drop_unencrypted = use_crypt;
#ifdef CONFIG_IEEE80211W
- params.mgmt_frame_protection =
- ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
- wpa_s->conf->pmf : ssid->ieee80211w;
+ params.mgmt_frame_protection = wpas_get_ssid_pmf(wpa_s, ssid);
if (params.mgmt_frame_protection != NO_MGMT_FRAME_PROTECTION && bss) {
const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
struct wpa_ie_data ie;
@@ -1945,7 +2199,7 @@
os_memset(&vhtcaps_mask, 0, sizeof(vhtcaps_mask));
params.vhtcaps = &vhtcaps;
params.vhtcaps_mask = &vhtcaps_mask;
- wpa_supplicant_apply_vht_overrides(wpa_s, wpa_s->current_ssid, ¶ms);
+ wpa_supplicant_apply_vht_overrides(wpa_s, ssid, ¶ms);
#endif /* CONFIG_VHT_OVERRIDES */
#ifdef CONFIG_P2P
@@ -2050,6 +2304,7 @@
{
struct wpa_ssid *old_ssid;
+ wpas_connect_work_done(wpa_s);
wpa_clear_keys(wpa_s, addr);
old_ssid = wpa_s->current_ssid;
wpa_supplicant_mark_disassoc(wpa_s);
@@ -2102,6 +2357,14 @@
wpa_tdls_teardown_peers(wpa_s->wpa);
#endif /* CONFIG_TDLS */
+#ifdef CONFIG_MESH
+ if (wpa_s->ifmsh) {
+ wpa_msg_ctrl(wpa_s, MSG_INFO, MESH_GROUP_REMOVED "%s",
+ wpa_s->ifname);
+ wpa_supplicant_leave_mesh(wpa_s);
+ }
+#endif /* CONFIG_MESH */
+
if (addr) {
wpa_drv_deauthenticate(wpa_s, addr, reason_code);
os_memset(&event, 0, sizeof(event));
@@ -2267,12 +2530,17 @@
if (ssid) {
wpa_s->current_ssid = ssid;
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+ wpa_s->connect_without_scan =
+ (ssid->mode == WPAS_MODE_MESH) ? ssid : NULL;
+ } else {
+ wpa_s->connect_without_scan = NULL;
}
- wpa_s->connect_without_scan = NULL;
+
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
- if (wpa_supplicant_fast_associate(wpa_s) != 1)
+ if (wpa_s->connect_without_scan ||
+ wpa_supplicant_fast_associate(wpa_s) != 1)
wpa_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0);
if (ssid)
@@ -2742,15 +3010,9 @@
int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
{
- if (wpa_s->driver->send_eapol) {
- const u8 *addr = wpa_drv_get_mac_addr(wpa_s);
- if (addr)
- os_memcpy(wpa_s->own_addr, addr, ETH_ALEN);
- } else if ((!wpa_s->p2p_mgmt ||
- !(wpa_s->drv_flags &
- WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)) &&
- !(wpa_s->drv_flags &
- WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE)) {
+ if ((!wpa_s->p2p_mgmt ||
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)) &&
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE)) {
l2_packet_deinit(wpa_s->l2);
wpa_s->l2 = l2_packet_init(wpa_s->ifname,
wpa_drv_get_mac_addr(wpa_s),
@@ -2854,12 +3116,14 @@
wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
interface_count = 0;
}
+#ifndef ANDROID
if (!wpa_s->p2p_mgmt &&
wpa_supplicant_delayed_sched_scan(wpa_s,
interface_count % 3,
100000))
wpa_supplicant_req_scan(wpa_s, interface_count % 3,
100000);
+#endif /* ANDROID */
interface_count++;
} else
wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
@@ -3127,10 +3391,6 @@
{
struct ieee80211_vht_capabilities *vhtcaps;
struct ieee80211_vht_capabilities *vhtcaps_mask;
-#ifdef CONFIG_HT_OVERRIDES
- int max_ampdu;
- const u32 max_ampdu_mask = VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX;
-#endif /* CONFIG_HT_OVERRIDES */
if (!ssid)
return;
@@ -3148,9 +3408,12 @@
#ifdef CONFIG_HT_OVERRIDES
/* if max ampdu is <= 3, we have to make the HT cap the same */
- if (ssid->vht_capa_mask & max_ampdu_mask) {
- max_ampdu = (ssid->vht_capa & max_ampdu_mask) >>
- find_first_bit(max_ampdu_mask);
+ if (ssid->vht_capa_mask & VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX) {
+ int max_ampdu;
+
+ max_ampdu = (ssid->vht_capa &
+ VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX) >>
+ VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX_SHIFT;
max_ampdu = max_ampdu < 3 ? max_ampdu : 3;
wpa_set_ampdu_factor(wpa_s,
@@ -3261,7 +3524,7 @@
static int wpas_set_wowlan_triggers(struct wpa_supplicant *wpa_s,
- struct wpa_driver_capa *capa)
+ const struct wpa_driver_capa *capa)
{
struct wowlan_triggers *triggers;
int ret = 0;
@@ -3351,7 +3614,7 @@
wpa_s = dl_list_first(&radio->ifaces, struct wpa_supplicant,
radio_list);
- if (wpa_s && wpa_s->external_scan_running) {
+ if (wpa_s && wpa_s->radio->external_scan_running) {
wpa_printf(MSG_DEBUG, "Delay radio work start until externally triggered scan completes");
return;
}
@@ -3430,6 +3693,11 @@
if (dl_list_empty(&radio->work))
return;
+ if (wpa_s->ext_work_in_progress) {
+ wpa_printf(MSG_DEBUG,
+ "External radio work in progress - delay start of pending item");
+ return;
+ }
eloop_cancel_timeout(radio_start_next_work, radio, NULL);
eloop_register_timeout(0, 0, radio_start_next_work, radio, NULL);
}
@@ -3585,6 +3853,7 @@
struct wpa_interface *iface)
{
struct wpa_driver_capa capa;
+ int capa_res;
wpa_printf(MSG_DEBUG, "Initializing interface '%s' conf '%s' driver "
"'%s' ctrl_interface '%s' bridge '%s'", iface->ifname,
@@ -3714,10 +3983,13 @@
&wpa_s->hw.num_modes,
&wpa_s->hw.flags);
- if (wpa_drv_get_capa(wpa_s, &capa) == 0) {
+ capa_res = wpa_drv_get_capa(wpa_s, &capa);
+ if (capa_res == 0) {
wpa_s->drv_capa_known = 1;
wpa_s->drv_flags = capa.flags;
wpa_s->drv_enc = capa.enc;
+ wpa_s->drv_smps_modes = capa.smps_modes;
+ wpa_s->drv_rrm_flags = capa.rrm_flags;
wpa_s->probe_resp_offloads = capa.probe_resp_offloads;
wpa_s->max_scan_ssids = capa.max_scan_ssids;
wpa_s->max_sched_scan_ssids = capa.max_sched_scan_ssids;
@@ -3730,6 +4002,14 @@
wpa_s->extended_capa_len = capa.extended_capa_len;
wpa_s->num_multichan_concurrent =
capa.num_multichan_concurrent;
+ wpa_s->wmm_ac_supported = capa.wmm_ac_supported;
+
+ if (capa.mac_addr_rand_scan_supported)
+ wpa_s->mac_addr_rand_supported |= MAC_ADDR_RAND_SCAN;
+ if (wpa_s->sched_scan_supported &&
+ capa.mac_addr_rand_sched_scan_supported)
+ wpa_s->mac_addr_rand_supported |=
+ (MAC_ADDR_RAND_SCHED_SCAN | MAC_ADDR_RAND_PNO);
}
if (wpa_s->max_remain_on_chan == 0)
wpa_s->max_remain_on_chan = 1000;
@@ -3804,7 +4084,7 @@
* Note: We don't restore/remove the triggers on shutdown (it doesn't
* have effect anyway when the interface is down).
*/
- if (wpas_set_wowlan_triggers(wpa_s, &capa) < 0)
+ if (capa_res == 0 && wpas_set_wowlan_triggers(wpa_s, &capa) < 0)
return -1;
#ifdef CONFIG_EAP_PROXY
@@ -3828,6 +4108,8 @@
if (wpas_init_ext_pw(wpa_s) < 0)
return -1;
+ wpas_rrm_reset(wpa_s);
+
return 0;
}
@@ -3835,6 +4117,26 @@
static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
int notify, int terminate)
{
+ struct wpa_global *global = wpa_s->global;
+ struct wpa_supplicant *iface, *prev;
+
+ if (wpa_s == wpa_s->parent)
+ wpas_p2p_group_remove(wpa_s, "*");
+
+ iface = global->ifaces;
+ while (iface) {
+ if (iface == wpa_s || iface->parent != wpa_s) {
+ iface = iface->next;
+ continue;
+ }
+ wpa_printf(MSG_DEBUG,
+ "Remove remaining child interface %s from parent %s",
+ iface->ifname, wpa_s->ifname);
+ prev = iface;
+ iface = iface->next;
+ wpa_supplicant_remove_iface(global, prev, terminate);
+ }
+
wpa_s->disconnected = 1;
if (wpa_s->drv_priv) {
wpa_supplicant_deauthenticate(wpa_s,
@@ -3864,6 +4166,13 @@
wpa_s->ctrl_iface = NULL;
}
+#ifdef CONFIG_MESH
+ if (wpa_s->ifmsh) {
+ wpa_supplicant_mesh_iface_deinit(wpa_s, wpa_s->ifmsh);
+ wpa_s->ifmsh = NULL;
+ }
+#endif /* CONFIG_MESH */
+
if (wpa_s->conf != NULL) {
wpa_config_free(wpa_s->conf);
wpa_s->conf = NULL;
@@ -3923,14 +4232,16 @@
return NULL;
}
- /* Notify the control interfaces about new iface */
- if (wpas_notify_iface_added(wpa_s)) {
- wpa_supplicant_deinit_iface(wpa_s, 1, 0);
- return NULL;
- }
+ if (iface->p2p_mgmt == 0) {
+ /* Notify the control interfaces about new iface */
+ if (wpas_notify_iface_added(wpa_s)) {
+ wpa_supplicant_deinit_iface(wpa_s, 1, 0);
+ return NULL;
+ }
- for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
- wpas_notify_network_added(wpa_s, ssid);
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
+ wpas_notify_network_added(wpa_s, ssid);
+ }
wpa_s->next = global->ifaces;
global->ifaces = wpa_s;
@@ -3938,6 +4249,16 @@
wpa_dbg(wpa_s, MSG_DEBUG, "Added interface %s", wpa_s->ifname);
wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+#ifdef CONFIG_P2P
+ if (wpa_s->global->p2p == NULL &&
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
+ wpas_p2p_add_p2pdev_interface(wpa_s, iface->conf_p2p_dev) < 0) {
+ wpa_printf(MSG_INFO,
+ "P2P: Failed to enable P2P Device interface");
+ /* Try to continue without. P2P will be disabled. */
+ }
+#endif /* CONFIG_P2P */
+
return wpa_s;
}
@@ -3958,6 +4279,10 @@
int terminate)
{
struct wpa_supplicant *prev;
+#ifdef CONFIG_MESH
+ unsigned int mesh_if_created = wpa_s->mesh_if_created;
+ char *ifname = NULL;
+#endif /* CONFIG_MESH */
/* Remove interface from the global list of interfaces */
prev = global->ifaces;
@@ -3973,12 +4298,30 @@
wpa_dbg(wpa_s, MSG_DEBUG, "Removing interface %s", wpa_s->ifname);
+#ifdef CONFIG_MESH
+ if (mesh_if_created) {
+ ifname = os_strdup(wpa_s->ifname);
+ if (ifname == NULL) {
+ wpa_dbg(wpa_s, MSG_ERROR,
+ "mesh: Failed to malloc ifname");
+ return -1;
+ }
+ }
+#endif /* CONFIG_MESH */
+
if (global->p2p_group_formation == wpa_s)
global->p2p_group_formation = NULL;
if (global->p2p_invite_group == wpa_s)
global->p2p_invite_group = NULL;
wpa_supplicant_deinit_iface(wpa_s, 1, terminate);
+#ifdef CONFIG_MESH
+ if (mesh_if_created) {
+ wpa_drv_if_remove(global->ifaces, WPA_IF_MESH, ifname);
+ os_free(ifname);
+ }
+#endif /* CONFIG_MESH */
+
return 0;
}
@@ -4063,7 +4406,10 @@
wpa_msg_register_ifname_cb(wpa_supplicant_msg_ifname_cb);
#endif /* CONFIG_NO_WPA_MSG */
- wpa_debug_open_file(params->wpa_debug_file_path);
+ if (params->wpa_debug_file_path)
+ wpa_debug_open_file(params->wpa_debug_file_path);
+ else
+ wpa_debug_setup_stdout();
if (params->wpa_debug_syslog)
wpa_debug_open_syslog();
if (params->wpa_debug_tracing) {
@@ -4141,7 +4487,7 @@
wpa_supplicant_deinit(global);
return NULL;
}
- global->drv_priv = os_zalloc(global->drv_count * sizeof(void *));
+ global->drv_priv = os_calloc(global->drv_count, sizeof(void *));
if (global->drv_priv == NULL) {
wpa_supplicant_deinit(global);
return NULL;
@@ -4279,7 +4625,7 @@
}
-static void add_freq(int *freqs, int *num_freqs, int freq)
+void add_freq(int *freqs, int *num_freqs, int freq)
{
int i;
@@ -4300,7 +4646,7 @@
int *freqs;
int num_freqs = 0;
- freqs = os_zalloc(sizeof(int) * (max_freqs + 1));
+ freqs = os_calloc(max_freqs + 1, sizeof(int));
if (freqs == NULL)
return NULL;
@@ -4546,6 +4892,30 @@
}
+int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+#ifdef CONFIG_IEEE80211W
+ if (ssid == NULL || ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT) {
+ if (wpa_s->conf->pmf == MGMT_FRAME_PROTECTION_OPTIONAL &&
+ !(wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_BIP)) {
+ /*
+ * Driver does not support BIP -- ignore pmf=1 default
+ * since the connection with PMF would fail and the
+ * configuration does not require PMF to be enabled.
+ */
+ return NO_MGMT_FRAME_PROTECTION;
+ }
+
+ return wpa_s->conf->pmf;
+ }
+
+ return ssid->ieee80211w;
+#else /* CONFIG_IEEE80211W */
+ return NO_MGMT_FRAME_PROTECTION;
+#endif /* CONFIG_IEEE80211W */
+}
+
+
int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s)
{
if (wpa_s->global->conc_pref == WPA_CONC_PREF_P2P)
@@ -4681,6 +5051,7 @@
void wpas_request_connection(struct wpa_supplicant *wpa_s)
{
wpa_s->normal_scans = 0;
+ wpa_s->scan_req = NORMAL_SCAN_REQ;
wpa_supplicant_reinit_autoscan(wpa_s);
wpa_s->extra_blacklist_count = 0;
wpa_s->disconnected = 0;
@@ -4688,6 +5059,8 @@
if (wpa_supplicant_fast_associate(wpa_s) != 1)
wpa_supplicant_req_scan(wpa_s, 0, 0);
+ else
+ wpa_s->reattach = 0;
}
@@ -4785,3 +5158,268 @@
return num;
}
+
+
+static void wpas_rrm_neighbor_rep_timeout_handler(void *data, void *user_ctx)
+{
+ struct rrm_data *rrm = data;
+
+ if (!rrm->notify_neighbor_rep) {
+ wpa_printf(MSG_ERROR,
+ "RRM: Unexpected neighbor report timeout");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report - NONE");
+ rrm->notify_neighbor_rep(rrm->neighbor_rep_cb_ctx, NULL);
+
+ rrm->notify_neighbor_rep = NULL;
+ rrm->neighbor_rep_cb_ctx = NULL;
+}
+
+
+/*
+ * wpas_rrm_reset - Clear and reset all RRM data in wpa_supplicant
+ * @wpa_s: Pointer to wpa_supplicant
+ */
+void wpas_rrm_reset(struct wpa_supplicant *wpa_s)
+{
+ wpa_s->rrm.rrm_used = 0;
+
+ eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler, &wpa_s->rrm,
+ NULL);
+ if (wpa_s->rrm.notify_neighbor_rep)
+ wpas_rrm_neighbor_rep_timeout_handler(&wpa_s->rrm, NULL);
+ wpa_s->rrm.next_neighbor_rep_token = 1;
+}
+
+
+/*
+ * wpas_rrm_process_neighbor_rep - Handle incoming neighbor report
+ * @wpa_s: Pointer to wpa_supplicant
+ * @report: Neighbor report buffer, prefixed by a 1-byte dialog token
+ * @report_len: Length of neighbor report buffer
+ */
+void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
+ const u8 *report, size_t report_len)
+{
+ struct wpabuf *neighbor_rep;
+
+ wpa_hexdump(MSG_DEBUG, "RRM: New Neighbor Report", report, report_len);
+ if (report_len < 1)
+ return;
+
+ if (report[0] != wpa_s->rrm.next_neighbor_rep_token - 1) {
+ wpa_printf(MSG_DEBUG,
+ "RRM: Discarding neighbor report with token %d (expected %d)",
+ report[0], wpa_s->rrm.next_neighbor_rep_token - 1);
+ return;
+ }
+
+ eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler, &wpa_s->rrm,
+ NULL);
+
+ if (!wpa_s->rrm.notify_neighbor_rep) {
+ wpa_printf(MSG_ERROR, "RRM: Unexpected neighbor report");
+ return;
+ }
+
+ /* skipping the first byte, which is only an id (dialog token) */
+ neighbor_rep = wpabuf_alloc(report_len - 1);
+ if (neighbor_rep == NULL)
+ return;
+ wpabuf_put_data(neighbor_rep, report + 1, report_len - 1);
+ wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report (token = %d)",
+ report[0]);
+ wpa_s->rrm.notify_neighbor_rep(wpa_s->rrm.neighbor_rep_cb_ctx,
+ neighbor_rep);
+ wpa_s->rrm.notify_neighbor_rep = NULL;
+ wpa_s->rrm.neighbor_rep_cb_ctx = NULL;
+}
+
+
+#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS)
+/* Workaround different, undefined for Windows, error codes used here */
+#define ENOTCONN -1
+#define EOPNOTSUPP -1
+#define ECANCELED -1
+#endif
+
+/**
+ * wpas_rrm_send_neighbor_rep_request - Request a neighbor report from our AP
+ * @wpa_s: Pointer to wpa_supplicant
+ * @ssid: if not null, this is sent in the request. Otherwise, no SSID IE
+ * is sent in the request.
+ * @cb: Callback function to be called once the requested report arrives, or
+ * timed out after RRM_NEIGHBOR_REPORT_TIMEOUT seconds.
+ * In the former case, 'neighbor_rep' is a newly allocated wpabuf, and it's
+ * the requester's responsibility to free it.
+ * In the latter case NULL will be sent in 'neighbor_rep'.
+ * @cb_ctx: Context value to send the callback function
+ * Returns: 0 in case of success, negative error code otherwise
+ *
+ * In case there is a previous request which has not been answered yet, the
+ * new request fails. The caller may retry after RRM_NEIGHBOR_REPORT_TIMEOUT.
+ * Request must contain a callback function.
+ */
+int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
+ const struct wpa_ssid *ssid,
+ void (*cb)(void *ctx,
+ struct wpabuf *neighbor_rep),
+ void *cb_ctx)
+{
+ struct wpabuf *buf;
+ const u8 *rrm_ie;
+
+ if (wpa_s->wpa_state != WPA_COMPLETED || wpa_s->current_ssid == NULL) {
+ wpa_printf(MSG_DEBUG, "RRM: No connection, no RRM.");
+ return -ENOTCONN;
+ }
+
+ if (!wpa_s->rrm.rrm_used) {
+ wpa_printf(MSG_DEBUG, "RRM: No RRM in current connection.");
+ return -EOPNOTSUPP;
+ }
+
+ rrm_ie = wpa_bss_get_ie(wpa_s->current_bss,
+ WLAN_EID_RRM_ENABLED_CAPABILITIES);
+ if (!rrm_ie || !(wpa_s->current_bss->caps & IEEE80211_CAP_RRM) ||
+ !(rrm_ie[2] & WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
+ wpa_printf(MSG_DEBUG,
+ "RRM: No network support for Neighbor Report.");
+ return -EOPNOTSUPP;
+ }
+
+ if (!cb) {
+ wpa_printf(MSG_DEBUG,
+ "RRM: Neighbor Report request must provide a callback.");
+ return -EINVAL;
+ }
+
+ /* Refuse if there's a live request */
+ if (wpa_s->rrm.notify_neighbor_rep) {
+ wpa_printf(MSG_DEBUG,
+ "RRM: Currently handling previous Neighbor Report.");
+ return -EBUSY;
+ }
+
+ /* 3 = action category + action code + dialog token */
+ buf = wpabuf_alloc(3 + (ssid ? 2 + ssid->ssid_len : 0));
+ if (buf == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "RRM: Failed to allocate Neighbor Report Request");
+ return -ENOMEM;
+ }
+
+ wpa_printf(MSG_DEBUG, "RRM: Neighbor report request (for %s), token=%d",
+ (ssid ? wpa_ssid_txt(ssid->ssid, ssid->ssid_len) : ""),
+ wpa_s->rrm.next_neighbor_rep_token);
+
+ wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
+ wpabuf_put_u8(buf, WLAN_RRM_NEIGHBOR_REPORT_REQUEST);
+ wpabuf_put_u8(buf, wpa_s->rrm.next_neighbor_rep_token);
+ if (ssid) {
+ wpabuf_put_u8(buf, WLAN_EID_SSID);
+ wpabuf_put_u8(buf, ssid->ssid_len);
+ wpabuf_put_data(buf, ssid->ssid, ssid->ssid_len);
+ }
+
+ wpa_s->rrm.next_neighbor_rep_token++;
+
+ if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->bssid,
+ wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "RRM: Failed to send Neighbor Report Request");
+ wpabuf_free(buf);
+ return -ECANCELED;
+ }
+
+ wpa_s->rrm.neighbor_rep_cb_ctx = cb_ctx;
+ wpa_s->rrm.notify_neighbor_rep = cb;
+ eloop_register_timeout(RRM_NEIGHBOR_REPORT_TIMEOUT, 0,
+ wpas_rrm_neighbor_rep_timeout_handler,
+ &wpa_s->rrm, NULL);
+
+ wpabuf_free(buf);
+ return 0;
+}
+
+
+void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s,
+ const u8 *src,
+ const u8 *frame, size_t len,
+ int rssi)
+{
+ struct wpabuf *buf;
+ const struct rrm_link_measurement_request *req;
+ struct rrm_link_measurement_report report;
+
+ if (wpa_s->wpa_state != WPA_COMPLETED) {
+ wpa_printf(MSG_INFO,
+ "RRM: Ignoring link measurement request. Not associated");
+ return;
+ }
+
+ if (!wpa_s->rrm.rrm_used) {
+ wpa_printf(MSG_INFO,
+ "RRM: Ignoring link measurement request. Not RRM network");
+ return;
+ }
+
+ if (!(wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION)) {
+ wpa_printf(MSG_INFO,
+ "RRM: Measurement report failed. TX power insertion not supported");
+ return;
+ }
+
+ req = (const struct rrm_link_measurement_request *) frame;
+ if (len < sizeof(*req)) {
+ wpa_printf(MSG_INFO,
+ "RRM: Link measurement report failed. Request too short");
+ return;
+ }
+
+ os_memset(&report, 0, sizeof(report));
+ report.tpc.eid = WLAN_EID_TPC_REPORT;
+ report.tpc.len = 2;
+ report.rsni = 255; /* 255 indicates that RSNI is not available */
+ report.dialog_token = req->dialog_token;
+
+ /*
+ * It's possible to estimate RCPI based on RSSI in dBm. This
+ * calculation will not reflect the correct value for high rates,
+ * but it's good enough for Action frames which are transmitted
+ * with up to 24 Mbps rates.
+ */
+ if (!rssi)
+ report.rcpi = 255; /* not available */
+ else if (rssi < -110)
+ report.rcpi = 0;
+ else if (rssi > 0)
+ report.rcpi = 220;
+ else
+ report.rcpi = (rssi + 110) * 2;
+
+ /* action_category + action_code */
+ buf = wpabuf_alloc(2 + sizeof(report));
+ if (buf == NULL) {
+ wpa_printf(MSG_ERROR,
+ "RRM: Link measurement report failed. Buffer allocation failed");
+ return;
+ }
+
+ wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
+ wpabuf_put_u8(buf, WLAN_RRM_LINK_MEASUREMENT_REPORT);
+ wpabuf_put_data(buf, &report, sizeof(report));
+ wpa_hexdump(MSG_DEBUG, "RRM: Link measurement report:",
+ wpabuf_head(buf), wpabuf_len(buf));
+
+ if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, src,
+ wpa_s->own_addr, wpa_s->bssid,
+ wpabuf_head(buf), wpabuf_len(buf), 0)) {
+ wpa_printf(MSG_ERROR,
+ "RRM: Link measurement report failed. Send action failed");
+ }
+ wpabuf_free(buf);
+}
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 89da0da..23c2299 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -114,6 +114,30 @@
# networks are found, a new IBSS or AP mode network is created.
ap_scan=1
+# MPM residency
+# By default, wpa_supplicant implements the mesh peering manager (MPM) for an
+# open mesh. However, if the driver can implement the MPM, you may set this to
+# 0 to use the driver version. When AMPE is enabled, the wpa_supplicant MPM is
+# always used.
+# 0: MPM lives in the driver
+# 1: wpa_supplicant provides an MPM which handles peering (default)
+#user_mpm=1
+
+# Maximum number of peer links (0-255; default: 99)
+# Maximum number of mesh peering currently maintained by the STA.
+#max_peer_links=99
+
+# Timeout in seconds to detect STA inactivity (default: 300 seconds)
+#
+# This timeout value is used in mesh STA to clean up inactive stations.
+#mesh_max_inactivity=300
+
+# cert_in_cb - Whether to include a peer certificate dump in events
+# This controls whether peer certificates for authentication server and
+# its certificate chain are included in EAP peer certificate events. This is
+# enabled by default.
+#cert_in_cb=1
+
# EAP fast re-authentication
# By default, fast re-authentication is enabled for all EAP methods that
# support it. This variable can be used to disable fast re-authentication.
@@ -132,6 +156,16 @@
# configure the path to the pkcs11 module required by the pkcs11 engine
#pkcs11_module_path=/usr/lib/pkcs11/opensc-pkcs11.so
+# OpenSSL cipher string
+#
+# This is an OpenSSL specific configuration option for configuring the default
+# ciphers. If not set, "DEFAULT:!EXP:!LOW" is used as the default.
+# See https://www.openssl.org/docs/apps/ciphers.html for OpenSSL documentation
+# on cipher suite configuration. This is applicable only if wpa_supplicant is
+# built to use OpenSSL.
+#openssl_ciphers=DEFAULT:!EXP:!LOW
+
+
# Dynamic EAP methods
# If EAP methods were built dynamically as shared object files, they need to be
# loaded here before being used in the network blocks. By default, EAP methods
@@ -842,6 +876,10 @@
# sertificate is only accepted if it contains this string in the subject.
# The subject string is in following format:
# /C=US/ST=CA/L=San Francisco/CN=Test AS/emailAddress=as@example.com
+# Note: Since this is a substring match, this cannot be used securily to
+# do a suffix match against a possible domain name in the CN entry. For
+# such a use case, domain_suffix_match or domain_match should be used
+# instead.
# altsubject_match: Semicolon separated string of entries to be matched against
# the alternative subject name of the authentication server certificate.
# If this string is set, the server sertificate is only accepted if it
@@ -850,6 +888,30 @@
# Example: EMAIL:server@example.com
# Example: DNS:server.example.com;DNS:server2.example.com
# Following types are supported: EMAIL, DNS, URI
+# domain_suffix_match: Constraint for server domain name. If set, this FQDN is
+# used as a suffix match requirement for the AAAserver certificate in
+# SubjectAltName dNSName element(s). If a matching dNSName is found, this
+# constraint is met. If no dNSName values are present, this constraint is
+# matched against SubjectName CN using same suffix match comparison.
+#
+# Suffix match here means that the host/domain name is compared one label
+# at a time starting from the top-level domain and all the labels in
+# domain_suffix_match shall be included in the certificate. The
+# certificate may include additional sub-level labels in addition to the
+# required labels.
+#
+# For example, domain_suffix_match=example.com would match
+# test.example.com but would not match test-example.com.
+# domain_match: Constraint for server domain name
+# If set, this FQDN is used as a full match requirement for the
+# server certificate in SubjectAltName dNSName element(s). If a
+# matching dNSName is found, this constraint is met. If no dNSName
+# values are present, this constraint is matched against SubjectName CN
+# using same full match comparison. This behavior is similar to
+# domain_suffix_match, but has the requirement of a full match, i.e.,
+# no subdomains or wildcard matches are allowed. Case-insensitive
+# comparison is used, so "Example.com" matches "example.com", but would
+# not match "test.Example.com".
# phase1: Phase1 (outer authentication, i.e., TLS tunnel) parameters
# (string with field-value pairs, e.g., "peapver=0" or
# "peapver=1 peaplabel=1")
@@ -916,9 +978,12 @@
# private_key2_passwd: Password for private key file
# dh_file2: File path to DH/DSA parameters file (in PEM format)
# subject_match2: Substring to be matched against the subject of the
-# authentication server certificate.
-# altsubject_match2: Substring to be matched against the alternative subject
-# name of the authentication server certificate.
+# authentication server certificate. See subject_match for more details.
+# altsubject_match2: Semicolon separated string of entries to be matched
+# against the alternative subject name of the authentication server
+# certificate. See altsubject_match documentation for more details.
+# domain_suffix_match2: Constraint for server domain name. See
+# domain_suffix_match for more details.
#
# fragment_size: Maximum EAP fragment size in bytes (default 1398).
# This value limits the fragment size for EAP methods that support
@@ -932,6 +997,12 @@
# 1 = try to use OCSP stapling, but not require response
# 2 = require valid OCSP stapling response
#
+# openssl_ciphers: OpenSSL specific cipher configuration
+# This can be used to override the global openssl_ciphers configuration
+# parameter (see above).
+#
+# erp: Whether EAP Re-authentication Protocol (ERP) is enabled
+#
# EAP-FAST variables:
# pac_file: File path for the PAC entries. wpa_supplicant will need to be able
# to create this file and write updates to it when PAC is being
@@ -1310,6 +1381,23 @@
psk="secret passphrase"
}
+# open mesh network
+network={
+ ssid="test mesh"
+ mode=5
+ frequency=2437
+ key_mgmt=NONE
+}
+
+# secure (SAE + AMPE) network
+network={
+ ssid="secure mesh"
+ mode=5
+ frequency=2437
+ key_mgmt=SAE
+ psk="very secret passphrase"
+}
+
# Catch all example that allows more or less all configuration modes
network={
@@ -1385,6 +1473,21 @@
key_mgmt=NONE
}
+# Example configuration blacklisting two APs - these will be ignored
+# for this network.
+network={
+ ssid="example"
+ psk="very secret passphrase"
+ bssid_blacklist=02:11:22:33:44:55 02:22:aa:44:55:66
+}
+
+# Example configuration limiting AP selection to a specific set of APs;
+# any other AP not matching the masked address will be ignored.
+network={
+ ssid="example"
+ psk="very secret passphrase"
+ bssid_whitelist=02:55:ae:bc:00:00/ff:ff:ff:ff:00:00 00:00:77:66:55:44/00:00:ff:ff:ff:ff
+}
# Example config file that will only scan on channel 36.
freq_list=5180
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index ae9dddd..7d22000 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -15,6 +15,7 @@
#include "common/wpa_ctrl.h"
#include "wps/wps_defs.h"
#include "config_ssid.h"
+#include "wmm_ac.h"
extern const char *wpa_supplicant_version;
extern const char *wpa_supplicant_license;
@@ -273,6 +274,7 @@
} conc_pref;
unsigned int p2p_per_sta_psk:1;
unsigned int p2p_fail_on_wps_complete:1;
+ unsigned int p2p_24ghz_social_channels:1;
#ifdef CONFIG_WIFI_DISPLAY
int wifi_display;
@@ -294,6 +296,7 @@
struct wpa_radio {
char name[16]; /* from driver_ops get_radio_name() or empty if not
* available */
+ unsigned int external_scan_running:1;
struct dl_list ifaces; /* struct wpa_supplicant::radio_list entries */
struct dl_list work; /* struct wpa_radio_work::list entries */
};
@@ -376,6 +379,36 @@
unsigned int flags;
};
+#define RRM_NEIGHBOR_REPORT_TIMEOUT 1 /* 1 second for AP to send a report */
+
+/*
+ * struct rrm_data - Data used for managing RRM features
+ */
+struct rrm_data {
+ /* rrm_used - indication regarding the current connection */
+ unsigned int rrm_used:1;
+
+ /*
+ * notify_neighbor_rep - Callback for notifying report requester
+ */
+ void (*notify_neighbor_rep)(void *ctx, struct wpabuf *neighbor_rep);
+
+ /*
+ * neighbor_rep_cb_ctx - Callback context
+ * Received in the callback registration, and sent to the callback
+ * function as a parameter.
+ */
+ void *neighbor_rep_cb_ctx;
+
+ /* next_neighbor_rep_token - Next request's dialog token */
+ u8 next_neighbor_rep_token;
+};
+
+enum wpa_supplicant_test_failure {
+ WPAS_TEST_FAILURE_NONE,
+ WPAS_TEST_FAILURE_SCAN_TRIGGER,
+};
+
/**
* struct wpa_supplicant - Internal data for wpa_supplicant interface
*
@@ -417,6 +450,7 @@
u8 pending_bssid[ETH_ALEN]; /* If wpa_state == WPA_ASSOCIATING, this
* field contains the target BSSID. */
int reassociate; /* reassociation requested */
+ int reassoc_same_bss; /* reassociating to the same bss */
int disconnected; /* all connections disabled; i.e., do no reassociate
* before this has been cleared */
struct wpa_ssid *current_ssid;
@@ -552,6 +586,7 @@
*/
MANUAL_SCAN_REQ
} scan_req, last_scan_req;
+ enum wpa_states scan_prev_wpa_state;
struct os_reltime scan_trigger_time, scan_start_time;
int scan_runs; /* number of scan runs since WPS was started */
int *next_scan_freqs;
@@ -562,7 +597,6 @@
unsigned int manual_scan_only_new:1;
unsigned int own_scan_requested:1;
unsigned int own_scan_running:1;
- unsigned int external_scan_running:1;
unsigned int clear_driver_scan_cache:1;
unsigned int manual_scan_id;
int scan_interval; /* time in sec between scans to find suitable AP */
@@ -573,8 +607,10 @@
int scan_id[MAX_SCAN_ID];
unsigned int scan_id_count;
- unsigned int drv_flags;
+ u64 drv_flags;
unsigned int drv_enc;
+ unsigned int drv_smps_modes;
+ unsigned int drv_rrm_flags;
/*
* A bitmap of supported protocols for probe response offload. See
@@ -646,6 +682,9 @@
* SA Query transaction identifiers */
struct os_reltime sa_query_start;
struct os_reltime last_unprot_disconnect;
+ enum { HT_SEC_CHAN_UNKNOWN,
+ HT_SEC_CHAN_ABOVE,
+ HT_SEC_CHAN_BELOW } ht_sec_chan;
u8 sched_obss_scan;
u16 obss_scan_int;
u16 bss_max_idle_period;
@@ -653,6 +692,7 @@
struct sae_data sae;
struct wpabuf *sae_token;
int sae_group_index;
+ unsigned int sae_pmksa_caching:1;
#endif /* CONFIG_SAE */
} sme;
#endif /* CONFIG_SME */
@@ -664,6 +704,14 @@
void *ap_configured_cb_data;
#endif /* CONFIG_AP */
+ struct hostapd_iface *ifmsh;
+#ifdef CONFIG_MESH
+ struct mesh_rsn *mesh_rsn;
+ int mesh_if_idx;
+ unsigned int mesh_if_created:1;
+ unsigned int mesh_ht_enabled:1;
+#endif /* CONFIG_MESH */
+
unsigned int off_channel_freq;
struct wpabuf *pending_action_tx;
u8 pending_action_src[ETH_ALEN];
@@ -685,6 +733,7 @@
int p2p_mgmt;
#ifdef CONFIG_P2P
+ struct wpa_supplicant *p2p_dev;
struct p2p_go_neg_results *go_params;
int create_p2p_iface;
u8 pending_interface_addr[ETH_ALEN];
@@ -755,6 +804,7 @@
unsigned int p2p_go_vht:1;
unsigned int user_initiated_pd:1;
unsigned int p2p_go_group_formation_completed:1;
+ unsigned int group_formation_reported:1;
unsigned int waiting_presence_resp;
int p2p_first_connection_timeout;
unsigned int p2p_nfc_tag_enabled:1;
@@ -775,6 +825,10 @@
* formation */
u8 p2p_peer_oob_pubkey_hash[WPS_OOB_PUBKEY_HASH_LEN];
u8 p2p_ip_addr_info[3 * 4];
+
+ /* group common frequencies */
+ int *p2p_group_common_freqs;
+ unsigned int p2p_group_common_freqs_num;
#endif /* CONFIG_P2P */
struct wpa_ssid *bgscan_ssid;
@@ -809,8 +863,10 @@
unsigned int network_select:1;
unsigned int auto_select:1;
unsigned int auto_network_select:1;
+ unsigned int interworking_fast_assoc_tried:1;
unsigned int fetch_all_anqp:1;
unsigned int fetch_osu_info:1;
+ unsigned int fetch_osu_waiting_scan:1;
unsigned int fetch_osu_icon_in_progress:1;
struct wpa_bss *interworking_gas_bss;
unsigned int osu_icon_id;
@@ -845,6 +901,23 @@
unsigned int no_keep_alive:1;
unsigned int ext_mgmt_frame_handling:1;
+ unsigned int ext_eapol_frame_io:1;
+ unsigned int wmm_ac_supported:1;
+ unsigned int ext_work_in_progress:1;
+
+#define MAC_ADDR_RAND_SCAN BIT(0)
+#define MAC_ADDR_RAND_SCHED_SCAN BIT(1)
+#define MAC_ADDR_RAND_PNO BIT(2)
+#define MAC_ADDR_RAND_ALL (MAC_ADDR_RAND_SCAN | \
+ MAC_ADDR_RAND_SCHED_SCAN | \
+ MAC_ADDR_RAND_PNO)
+ unsigned int mac_addr_rand_supported;
+ unsigned int mac_addr_rand_enable;
+
+ /* MAC Address followed by mask (2 * ETH_ALEN) */
+ u8 *mac_addr_scan;
+ u8 *mac_addr_sched_scan;
+ u8 *mac_addr_pno;
#ifdef CONFIG_WNM
u8 wnm_dialog_token;
@@ -852,9 +925,10 @@
u8 wnm_num_neighbor_report;
u8 wnm_mode;
u16 wnm_dissoc_timer;
- u8 wnm_validity_interval;
u8 wnm_bss_termination_duration[12];
struct neighbor_report *wnm_neighbor_report_elements;
+ struct os_reltime wnm_cand_valid_until;
+ u8 wnm_cand_from_bss[ETH_ALEN];
#endif /* CONFIG_WNM */
#ifdef CONFIG_TESTING_GET_GTK
@@ -868,6 +942,21 @@
unsigned int ext_work_id;
struct wpabuf *vendor_elem[NUM_VENDOR_ELEM_FRAMES];
+
+#ifdef CONFIG_TESTING_OPTIONS
+ struct l2_packet_data *l2_test;
+ unsigned int extra_roc_dur;
+ enum wpa_supplicant_test_failure test_failure;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ struct wmm_ac_assoc_data *wmm_ac_assoc_info;
+ struct wmm_tspec_element *tspecs[WMM_AC_NUM][TS_DIR_IDX_COUNT];
+ struct wmm_ac_addts_request *addts_request;
+ u8 wmm_ac_last_dialog_token;
+ struct wmm_tspec_element *last_tspecs;
+ u8 last_tspecs_count;
+
+ struct rrm_data rrm;
};
@@ -964,6 +1053,20 @@
int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen);
int wpas_update_random_addr(struct wpa_supplicant *wpa_s, int style);
int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s);
+void add_freq(int *freqs, int *num_freqs, int freq);
+
+void wpas_rrm_reset(struct wpa_supplicant *wpa_s);
+void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
+ const u8 *report, size_t report_len);
+int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
+ const struct wpa_ssid *ssid,
+ void (*cb)(void *ctx,
+ struct wpabuf *neighbor_rep),
+ void *cb_ctx);
+void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s,
+ const u8 *src,
+ const u8 *frame, size_t len,
+ int rssi);
/**
* wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
@@ -980,6 +1083,10 @@
const char *field,
const char *value);
+void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
+ const struct wpa_ssid *ssid,
+ struct hostapd_freq_params *freq);
+
/* events.c */
void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s);
int wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
@@ -991,8 +1098,6 @@
int wpa_supplicant_fast_associate(struct wpa_supplicant *wpa_s);
struct wpa_bss * wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
struct wpa_ssid **selected_ssid);
-int ht_supported(const struct hostapd_hw_modes *mode);
-int vht_supported(const struct hostapd_hw_modes *mode);
/* eap_register.c */
int eap_register_methods(void);
@@ -1008,6 +1113,7 @@
}
int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
int wpas_init_ext_pw(struct wpa_supplicant *wpa_s);
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 38279b1..99e7351 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - Glue code to setup EAPOL and RSN modules
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -96,11 +96,26 @@
static int wpa_ether_send(struct wpa_supplicant *wpa_s, const u8 *dest,
u16 proto, const u8 *buf, size_t len)
{
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->ext_eapol_frame_io && proto == ETH_P_EAPOL) {
+ size_t hex_len = 2 * len + 1;
+ char *hex = os_malloc(hex_len);
+
+ if (hex == NULL)
+ return -1;
+ wpa_snprintf_hex(hex, hex_len, buf, len);
+ wpa_msg(wpa_s, MSG_INFO, "EAPOL-TX " MACSTR " %s",
+ MAC2STR(dest), hex);
+ os_free(hex);
+ return 0;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
if (wpa_s->l2) {
return l2_packet_send(wpa_s->l2, dest, proto, buf, len);
}
- return wpa_drv_send_eapol(wpa_s, dest, proto, buf, len);
+ return -1;
}
#endif /* IEEE8021X_EAPOL || !CONFIG_NO_WPA */
@@ -528,7 +543,44 @@
const u8 *ies, size_t ies_len)
{
struct wpa_supplicant *wpa_s = ctx;
- return wpa_drv_send_ft_action(wpa_s, action, target_ap, ies, ies_len);
+ int ret;
+ u8 *data, *pos;
+ size_t data_len;
+
+ if (action != 1) {
+ wpa_printf(MSG_ERROR, "Unsupported send_ft_action action %d",
+ action);
+ return -1;
+ }
+
+ /*
+ * Action frame payload:
+ * Category[1] = 6 (Fast BSS Transition)
+ * Action[1] = 1 (Fast BSS Transition Request)
+ * STA Address
+ * Target AP Address
+ * FT IEs
+ */
+
+ data_len = 2 + 2 * ETH_ALEN + ies_len;
+ data = os_malloc(data_len);
+ if (data == NULL)
+ return -1;
+ pos = data;
+ *pos++ = 0x06; /* FT Action category */
+ *pos++ = action;
+ os_memcpy(pos, wpa_s->own_addr, ETH_ALEN);
+ pos += ETH_ALEN;
+ os_memcpy(pos, target_ap, ETH_ALEN);
+ pos += ETH_ALEN;
+ os_memcpy(pos, ies, ies_len);
+
+ ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0,
+ wpa_s->bssid, wpa_s->own_addr, wpa_s->bssid,
+ data, data_len, 0);
+ os_free(data);
+
+ return ret;
}
@@ -557,12 +609,14 @@
#ifdef CONFIG_TDLS
static int wpa_supplicant_tdls_get_capa(void *ctx, int *tdls_supported,
- int *tdls_ext_setup)
+ int *tdls_ext_setup,
+ int *tdls_chan_switch)
{
struct wpa_supplicant *wpa_s = ctx;
*tdls_supported = 0;
*tdls_ext_setup = 0;
+ *tdls_chan_switch = 0;
if (!wpa_s->drv_capa_known)
return -1;
@@ -573,6 +627,9 @@
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP)
*tdls_ext_setup = 1;
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH)
+ *tdls_chan_switch = 1;
+
return 0;
}
@@ -640,6 +697,25 @@
return wpa_drv_sta_add(wpa_s, ¶ms);
}
+
+static int wpa_supplicant_tdls_enable_channel_switch(
+ void *ctx, const u8 *addr, u8 oper_class,
+ const struct hostapd_freq_params *params)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ return wpa_drv_tdls_enable_channel_switch(wpa_s, addr, oper_class,
+ params);
+}
+
+
+static int wpa_supplicant_tdls_disable_channel_switch(void *ctx, const u8 *addr)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ return wpa_drv_tdls_disable_channel_switch(wpa_s, addr);
+}
+
#endif /* CONFIG_TDLS */
#endif /* CONFIG_NO_WPA */
@@ -748,7 +824,7 @@
len = os_snprintf(buf, buflen,
WPA_CTRL_REQ "%s-%d:%s needed for SSID ",
field_name, ssid->id, txt);
- if (len < 0 || (size_t) len >= buflen) {
+ if (os_snprintf_error(buflen, len)) {
os_free(buf);
return;
}
@@ -784,12 +860,14 @@
static void wpa_supplicant_cert_cb(void *ctx, int depth, const char *subject,
+ const char *altsubject[], int num_altsubject,
const char *cert_hash,
const struct wpabuf *cert)
{
struct wpa_supplicant *wpa_s = ctx;
- wpas_notify_certification(wpa_s, depth, subject, cert_hash, cert);
+ wpas_notify_certification(wpa_s, depth, subject, altsubject,
+ num_altsubject, cert_hash, cert);
}
@@ -866,11 +944,13 @@
ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path;
ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
+ ctx->openssl_ciphers = wpa_s->conf->openssl_ciphers;
ctx->wps = wpa_s->wps;
ctx->eap_param_needed = wpa_supplicant_eap_param_needed;
ctx->port_cb = wpa_supplicant_port_cb;
ctx->cb = wpa_supplicant_eapol_cb;
ctx->cert_cb = wpa_supplicant_cert_cb;
+ ctx->cert_in_cb = wpa_s->conf->cert_in_cb;
ctx->status_cb = wpa_supplicant_status_cb;
ctx->set_anon_id = wpa_supplicant_set_anon_id;
ctx->cb_ctx = wpa_s;
@@ -888,17 +968,31 @@
#ifndef CONFIG_NO_WPA
-static void wpa_supplicant_set_rekey_offload(void *ctx, const u8 *kek,
- const u8 *kck,
+static void wpa_supplicant_set_rekey_offload(void *ctx,
+ const u8 *kek, size_t kek_len,
+ const u8 *kck, size_t kck_len,
const u8 *replay_ctr)
{
struct wpa_supplicant *wpa_s = ctx;
- wpa_drv_set_rekey_info(wpa_s, kek, kck, replay_ctr);
+ wpa_drv_set_rekey_info(wpa_s, kek, kek_len, kck, kck_len, replay_ctr);
}
#endif /* CONFIG_NO_WPA */
+static int wpa_supplicant_key_mgmt_set_pmk(void *ctx, const u8 *pmk,
+ size_t pmk_len)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ if (wpa_s->conf->key_mgmt_offload)
+ return wpa_drv_set_key(wpa_s, WPA_ALG_PMK, NULL, 0, 0,
+ NULL, 0, pmk, pmk_len);
+ else
+ return 0;
+}
+
+
int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
{
#ifndef CONFIG_NO_WPA
@@ -938,13 +1032,19 @@
ctx->send_tdls_mgmt = wpa_supplicant_send_tdls_mgmt;
ctx->tdls_oper = wpa_supplicant_tdls_oper;
ctx->tdls_peer_addset = wpa_supplicant_tdls_peer_addset;
+ ctx->tdls_enable_channel_switch =
+ wpa_supplicant_tdls_enable_channel_switch;
+ ctx->tdls_disable_channel_switch =
+ wpa_supplicant_tdls_disable_channel_switch;
#endif /* CONFIG_TDLS */
ctx->set_rekey_offload = wpa_supplicant_set_rekey_offload;
+ ctx->key_mgmt_set_pmk = wpa_supplicant_key_mgmt_set_pmk;
wpa_s->wpa = wpa_sm_init(ctx);
if (wpa_s->wpa == NULL) {
wpa_printf(MSG_ERROR, "Failed to initialize WPA state "
"machine");
+ os_free(ctx);
return -1;
}
#endif /* CONFIG_NO_WPA */
diff --git a/wpa_supplicant/wpas_module_tests.c b/wpa_supplicant/wpas_module_tests.c
index e4c83b5..6af1678 100644
--- a/wpa_supplicant/wpas_module_tests.c
+++ b/wpa_supplicant/wpas_module_tests.c
@@ -98,5 +98,11 @@
ret = -1;
}
+ {
+ int crypto_module_tests(void);
+ if (crypto_module_tests() < 0)
+ ret = -1;
+ }
+
return ret;
}
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 40a5c69..b1266c6 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -286,7 +286,9 @@
/* compare security parameters */
if (ssid->auth_alg != new_ssid->auth_alg ||
ssid->key_mgmt != new_ssid->key_mgmt ||
- ssid->group_cipher != new_ssid->group_cipher)
+ (ssid->group_cipher != new_ssid->group_cipher &&
+ !(ssid->group_cipher & new_ssid->group_cipher &
+ WPA_CIPHER_CCMP)))
continue;
/*
@@ -337,6 +339,8 @@
/* Remove the duplicated older network entry. */
wpa_printf(MSG_DEBUG, "Remove duplicate network %d", ssid->id);
wpas_notify_network_removed(wpa_s, ssid);
+ if (wpa_s->current_ssid == ssid)
+ wpa_s->current_ssid = NULL;
wpa_config_remove_network(wpa_s->conf, ssid->id);
}
}
@@ -471,6 +475,11 @@
break;
case WPS_ENCR_AES:
ssid->pairwise_cipher = WPA_CIPHER_CCMP;
+ if (wpa_s->drv_capa_known &&
+ (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_GCMP)) {
+ ssid->pairwise_cipher |= WPA_CIPHER_GCMP;
+ ssid->group_cipher |= WPA_CIPHER_GCMP;
+ }
break;
}
@@ -1082,6 +1091,14 @@
int p2p_group)
{
struct wpa_ssid *ssid;
+
+#ifdef CONFIG_AP
+ if (wpa_s->ap_iface) {
+ wpa_printf(MSG_DEBUG,
+ "WPS: Reject request to start Registrar(as station) operation while AP mode is enabled");
+ return -1;
+ }
+#endif /* CONFIG_AP */
wpas_clear_wps(wpa_s);
ssid = wpas_wps_add_network(wpa_s, 0, NULL, bssid);
if (ssid == NULL)
@@ -1122,6 +1139,13 @@
unsigned int rpin = 0;
char hash[2 * WPS_OOB_PUBKEY_HASH_LEN + 10];
+#ifdef CONFIG_AP
+ if (wpa_s->ap_iface) {
+ wpa_printf(MSG_DEBUG,
+ "WPS: Reject request to start Registrar(as station) operation while AP mode is enabled");
+ return -1;
+ }
+#endif /* CONFIG_AP */
wpas_clear_wps(wpa_s);
if (bssid && is_zero_ether_addr(bssid))
bssid = NULL;
@@ -1235,6 +1259,13 @@
char *pos, *end;
int res;
+#ifdef CONFIG_AP
+ if (wpa_s->ap_iface) {
+ wpa_printf(MSG_DEBUG,
+ "WPS: Reject request to start Registrar(as station) operation while AP mode is enabled");
+ return -1;
+ }
+#endif /* CONFIG_AP */
if (!pin)
return -1;
wpas_clear_wps(wpa_s);
@@ -1245,7 +1276,7 @@
pos = val;
end = pos + sizeof(val);
res = os_snprintf(pos, end - pos, "\"pin=%s", pin);
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return -1;
pos += res;
if (settings) {
@@ -1253,12 +1284,12 @@
"new_encr=%s new_key=%s",
settings->ssid_hex, settings->auth,
settings->encr, settings->key_hex);
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return -1;
pos += res;
}
res = os_snprintf(pos, end - pos, "\"");
- if (res < 0 || res >= end - pos)
+ if (os_snprintf_error(end - pos, res))
return -1;
if (wpa_config_set(ssid, "phase1", val, 0) < 0)
return -1;
@@ -1309,7 +1340,7 @@
dev->model_number, dev->serial_number,
wps_dev_type_bin2str(dev->pri_dev_type, devtype,
sizeof(devtype)));
- if (len > 0 && len < (int) sizeof(txt))
+ if (!os_snprintf_error(sizeof(txt), len))
wpa_printf(MSG_INFO, "%s", txt);
}
@@ -1697,6 +1728,10 @@
uuid = wps_get_uuid_e(ie);
wpa_hexdump(MSG_DEBUG, "WPS: UUID of the other BSS",
uuid, UUID_LEN);
+ if (os_memcmp(selected->bssid, bss->bssid, ETH_ALEN) == 0) {
+ wpabuf_free(ie);
+ continue;
+ }
if (sel_uuid == NULL || uuid == NULL ||
os_memcmp(sel_uuid, uuid, UUID_LEN) != 0) {
ret = 1; /* PBC overlap */
@@ -1800,13 +1835,12 @@
}
-int wpas_wps_er_stop(struct wpa_supplicant *wpa_s)
+void wpas_wps_er_stop(struct wpa_supplicant *wpa_s)
{
#ifdef CONFIG_WPS_ER
wps_er_deinit(wpa_s->wps_er, NULL, NULL);
wpa_s->wps_er = NULL;
#endif /* CONFIG_WPS_ER */
- return 0;
}
@@ -1907,6 +1941,7 @@
u8 addr[ETH_ALEN], *use_addr = NULL;
struct wpa_ssid *ssid;
struct wps_credential cred;
+ int ret;
if (uuid_str2bin(uuid, u) == 0)
use_uuid = u;
@@ -1920,7 +1955,9 @@
if (wpas_wps_network_to_cred(ssid, &cred) < 0)
return -1;
- return wps_er_set_config(wpa_s->wps_er, use_uuid, use_addr, &cred);
+ ret = wps_er_set_config(wpa_s->wps_er, use_uuid, use_addr, &cred);
+ os_memset(&cred, 0, sizeof(cred));
+ return ret;
}
diff --git a/wpa_supplicant/wps_supplicant.h b/wpa_supplicant/wps_supplicant.h
index 2263512..683bd50 100644
--- a/wpa_supplicant/wps_supplicant.h
+++ b/wpa_supplicant/wps_supplicant.h
@@ -47,7 +47,7 @@
int wpas_wps_scan_result_text(const u8 *ies, size_t ies_len, char *pos,
char *end);
int wpas_wps_er_start(struct wpa_supplicant *wpa_s, const char *filter);
-int wpas_wps_er_stop(struct wpa_supplicant *wpa_s);
+void wpas_wps_er_stop(struct wpa_supplicant *wpa_s);
int wpas_wps_er_add_pin(struct wpa_supplicant *wpa_s, const u8 *addr,
const char *uuid, const char *pin);
int wpas_wps_er_pbc(struct wpa_supplicant *wpa_s, const char *uuid);