am 918cec2c: am 59c61501: Merge "Remove hardcoded ICU include paths."
* commit '918cec2c0c1cd4e104babb39af255b2885c39696':
Remove hardcoded ICU include paths.
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index edaf6fc..d6d04c5 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -95,6 +95,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 =
@@ -200,6 +201,17 @@
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_IEEE80211W
@@ -854,6 +866,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..e64c249 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
@@ -187,6 +190,17 @@
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_IEEE80211W
@@ -246,6 +260,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
@@ -755,6 +775,9 @@
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_DH_GROUPS
@@ -839,6 +862,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 +913,10 @@
Q=
E=true
endif
+ifeq ($(QUIET), 1)
+Q=@
+E=true
+endif
ifdef CONFIG_CODE_COVERAGE
%.o: %.c
@@ -901,9 +937,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 \
diff --git a/hostapd/README b/hostapd/README
index 50868ee..ea016cc 100644
--- a/hostapd/README
+++ b/hostapd/README
@@ -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..e30efbe 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -680,6 +680,8 @@
else if (os_strcmp(start, "FT-SAE") == 0)
val |= WPA_KEY_MGMT_FT_SAE;
#endif /* CONFIG_SAE */
+ else if (os_strcmp(start, "WPA-EAP-SUITE-B") == 0)
+ val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B;
else {
wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
line, start);
@@ -1865,6 +1867,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 +1989,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 +2052,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 +2073,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 +2420,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 +2498,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) {
@@ -2996,6 +3017,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 +3129,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..0e35aa6 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -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>
@@ -21,6 +26,7 @@
#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 +246,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 +584,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 +594,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 +605,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 +614,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 +863,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 +1067,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 +1076,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 +1084,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 +1096,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 +1104,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 +1145,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 +1159,20 @@
#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;
+ }
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 +1180,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 +1198,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 +1216,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 +1273,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 +1323,7 @@
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;
}
@@ -1249,6 +1450,248 @@
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;
+}
+
#endif /* CONFIG_TESTING_OPTIONS */
@@ -1366,7 +1809,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 +1820,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 +1972,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 +2001,18 @@
} 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;
#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 +2020,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 +2034,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 +2093,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 +2102,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 +2111,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 +2137,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 +2158,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,19 +2185,22 @@
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);
@@ -1782,6 +2259,11 @@
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 +2313,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 +2354,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 +2399,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 +2417,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 +2438,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 +2464,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..2f6126c 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
@@ -221,7 +224,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 +438,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 +696,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 +782,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 +852,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 +1471,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..7009184 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -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..3ecd009 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -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;
}
@@ -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/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..97cf26f 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -816,6 +816,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..58af6cb 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,11 @@
u8 bss_load_test[5];
u8 bss_load_test_set;
#endif /* CONFIG_TESTING_OPTIONS */
+
+#define MESH_ENABLED BIT(0)
+ int mesh;
+
+ int radio_measurements;
};
@@ -540,6 +577,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..4a8703a 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;
}
@@ -398,6 +427,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);
@@ -808,6 +839,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);
@@ -908,6 +943,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..2103747 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -35,6 +35,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 +256,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 +308,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 */
}
@@ -691,6 +705,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 +760,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 +897,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 +946,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 +1216,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 +1246,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,
@@ -1820,7 +1883,7 @@
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;
@@ -1882,11 +1945,19 @@
}
if (new_iface) {
- if (interfaces->driver_init(hapd_iface) ||
- hostapd_setup_interface(hapd_iface)) {
+ if (interfaces->driver_init(hapd_iface)) {
interfaces->count--;
goto fail;
}
+
+ if (hostapd_setup_interface(hapd_iface)) {
+ interfaces->count--;
+ hostapd_deinit_driver(
+ hapd_iface->bss[0]->driver,
+ hapd_iface->bss[0]->drv_priv,
+ hapd_iface);
+ goto fail;
+ }
} else {
/* Assign new BSS with bss[0]'s driver info */
hapd = hapd_iface->bss[hapd_iface->num_bss - 1];
@@ -1978,14 +2049,14 @@
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);
+ hostapd_cleanup_iface(hapd_iface);
}
return -1;
}
@@ -2367,6 +2438,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..f959215 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -107,7 +107,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 +119,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;
}
@@ -746,11 +746,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 +852,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;
@@ -871,7 +884,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 +959,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" : "");
}
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..97f98f2 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,8 @@
#ifdef CONFIG_SAE
-static struct wpabuf * auth_process_sae_commit(struct hostapd_data *hapd,
- struct sta_info *sta)
+static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
+ struct sta_info *sta, int update)
{
struct wpabuf *buf;
@@ -334,7 +338,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 +347,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 +372,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 +452,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 +469,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,15 +483,150 @@
}
+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.
+ */
+ }
+ } else {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "SAE confirm before commit");
+ }
+ break;
+ case SAE_COMMITTED:
+ 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;
+ } else if (hapd->conf->mesh & MESH_ENABLED) {
+ /*
+ * In mesh case, follow SAE finite state machine and
+ * send Commit now.
+ */
+ ret = auth_sae_send_commit(hapd, sta, bssid, 1);
+ if (ret)
+ return ret;
+ } 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:
+ if (auth_transaction == 1) {
+ 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;
+ } 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 {
+ 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)
@@ -457,11 +635,62 @@
}
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;
+ 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,67 +703,56 @@
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);
}
#endif /* CONFIG_SAE */
@@ -556,6 +774,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 +796,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 +805,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 +871,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 +994,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 */
}
@@ -1072,9 +1345,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);
@@ -1275,7 +1560,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 +1593,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 +1613,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 +1642,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 +1782,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 +1793,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 +1835,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 +1935,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 +2089,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_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_1x.c b/src/ap/ieee802_1x.c
index 2d09b67..2287b28 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
@@ -1972,12 +2033,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 +2081,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 +2116,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 +2151,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 +2173,8 @@
eapol_auth_deinit(hapd->eapol_auth);
hapd->eapol_auth = NULL;
+
+ ieee802_1x_erp_flush(hapd);
}
@@ -2252,7 +2365,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 +2393,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 +2423,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 +2461,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,7 +2483,7 @@
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;
@@ -2383,7 +2496,7 @@
name1 ? name1 : "",
sm->eap_type_supp,
name2 ? name2 : "");
- if (ret < 0 || (size_t) ret >= buflen - len)
+ 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..4270382 100644
--- a/src/ap/pmksa_cache_auth.c
+++ b/src/ap/pmksa_cache_auth.c
@@ -146,6 +146,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 +186,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 +233,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 +250,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 +260,19 @@
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 (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)
diff --git a/src/ap/pmksa_cache_auth.h b/src/ap/pmksa_cache_auth.h
index aa90024..519555f 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 *
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index efd2a72..debdc06 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);
@@ -596,6 +612,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 +623,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 +679,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 +718,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 +928,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 +981,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 +1001,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 +1025,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 +1032,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);
}
@@ -1087,6 +1120,8 @@
(flags & WLAN_STA_VHT ? "[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..588a9e2 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)
@@ -41,6 +48,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 +58,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;
@@ -138,6 +161,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 +196,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..7e8fb5c 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,78 @@
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)
+ 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..da2073c 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -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)
@@ -782,6 +796,51 @@
}
+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)
@@ -884,6 +943,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 +962,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 +1004,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;
}
@@ -1123,7 +1207,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 +1239,8 @@
*/
if (msg == SMK_ERROR) {
#ifdef CONFIG_PEERKEY
- wpa_smk_error(wpa_auth, sm, key);
+ wpa_smk_error(wpa_auth, sm, (const u8 *) (key + 1),
+ key_data_length);
#endif /* CONFIG_PEERKEY */
return;
} else if (key_info & WPA_KEY_INFO_ERROR) {
@@ -1167,7 +1255,8 @@
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, (const u8 *) (key + 1),
+ key_data_length);
#endif /* CONFIG_PEERKEY */
} else if (key_data_length > 0 &&
wpa_parse_kde_ies((const u8 *) (key + 1),
@@ -1209,7 +1298,8 @@
#ifdef CONFIG_PEERKEY
if (msg == SMK_M3) {
- wpa_smk_m3(wpa_auth, sm, key);
+ wpa_smk_m3(wpa_auth, sm, key, (const u8 *) (key + 1),
+ key_data_length);
return;
}
#endif /* CONFIG_PEERKEY */
@@ -1295,7 +1385,8 @@
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 +1411,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)
@@ -1361,6 +1453,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)
@@ -1389,6 +1483,7 @@
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,
@@ -1420,8 +1515,8 @@
os_free(hdr);
return;
}
- wpa_eapol_key_mic(sm->PTK.kck, version, (u8 *) hdr, len,
- key->key_mic);
+ wpa_eapol_key_mic(sm->PTK.kck, sm->wpa_key_mgmt, version,
+ (u8 *) hdr, len, key->key_mic);
#ifdef CONFIG_TESTING_OPTIONS
if (!pairwise &&
wpa_auth->conf.corrupt_gtk_rekey_mic_probability > 0.0 &&
@@ -1473,7 +1568,8 @@
}
-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;
@@ -1489,7 +1585,7 @@
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,
+ if (wpa_eapol_key_mic(PTK->kck, akmp, key_info & WPA_KEY_INFO_TYPE_MASK,
data, data_len, key->key_mic) ||
os_memcmp_const(mic, key->key_mic, 16) != 0)
ret = -1;
@@ -1520,6 +1616,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:
@@ -1773,6 +1877,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 +1900,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,8 +1922,8 @@
}
-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
@@ -1824,7 +1932,7 @@
#endif /* CONFIG_IEEE80211R */
wpa_pmk_to_ptk(pmk, PMK_LEN, "Pairwise key expansion",
- sm->wpa_auth->addr, sm->addr, sm->ANonce, sm->SNonce,
+ sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce,
(u8 *) ptk, ptk_len,
wpa_key_mgmt_sha256(sm->wpa_key_mgmt));
@@ -1854,9 +1962,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 +2118,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,
@@ -2331,7 +2442,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 +2479,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 +2972,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 +3022,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 +3032,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 +3074,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 +3084,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 +3168,7 @@
return -1;
if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, PMK_LEN,
+ sm->PTK.kck, sizeof(sm->PTK.kck),
sm->wpa_auth->addr, sm->addr, session_timeout,
eapol, sm->wpa_key_mgmt))
return 0;
@@ -3071,7 +3185,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 +3196,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)
{
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 929a253..757e49e 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);
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index 781f15f..e061b5e 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -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"
@@ -1310,7 +1311,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 +1321,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 +1337,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 +1447,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 +1471,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 +1516,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 +1526,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 +1542,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 +1724,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 +1748,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..8592b90 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -299,6 +299,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 +419,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..478bc95 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -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
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 1e4defc..c926765 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -200,6 +200,11 @@
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++;
+ }
#ifdef CONFIG_RSN_TESTING
if (rsn_testing) {
@@ -477,6 +482,8 @@
selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
if (0) {
}
+ 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 +562,8 @@
}
if (0) {
}
+ 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..e1bbd50 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -49,6 +49,7 @@
#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)
static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
{
@@ -56,7 +57,8 @@
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));
}
static inline int wpa_key_mgmt_wpa_psk(int akm)
@@ -85,7 +87,13 @@
{
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_suite_b(int akm)
+{
+ return !!(akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B);
}
static inline int wpa_key_mgmt_wpa(int akm)
@@ -300,4 +308,25 @@
/* Maximum number of EAP methods to store for EAP server user information */
#define EAP_MAX_METHODS 8
+/**
+ * enum ht_mode - channel width and offset
+ */
+enum ht_mode {
+ CHAN_UNDEFINED = 0,
+ CHAN_NO_HT,
+ CHAN_HT20,
+ CHAN_HT40PLUS,
+ CHAN_HT40MINUS,
+};
+
+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/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 173a400..e1d45cf 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -249,6 +249,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 +302,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 +537,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..2357afc 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -28,6 +28,9 @@
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;
@@ -42,6 +45,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,6 +65,9 @@
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;
@@ -71,6 +79,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 +105,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..dfe0faf 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -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,6 +1140,19 @@
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) */
@@ -1122,6 +1188,7 @@
#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_CCKM 0x00409600
#define WLAN_AKM_SUITE_OSEN 0x506f9a01
@@ -1247,4 +1314,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..89d74ab 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 {
@@ -60,5 +61,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..a573e11 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -14,7 +14,6 @@
#include "crypto/sha256.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"
@@ -23,6 +22,7 @@
/**
* wpa_eapol_key_mic - Calculate EAPOL-Key MIC
* @key: EAPOL-Key Key Confirmation Key (KCK)
+ * @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,10 +38,10 @@
* 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, int akmp, int ver, const u8 *buf,
+ size_t len, u8 *mic)
{
- u8 hash[SHA1_MAC_LEN];
+ u8 hash[SHA256_MAC_LEN];
switch (ver) {
#ifndef CONFIG_FIPS
@@ -57,11 +57,23 @@
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, 16, buf, len, hash))
+ return -1;
+ os_memcpy(mic, hash, MD5_MAC_LEN);
+ break;
+#endif /* CONFIG_SUITEB */
+ default:
+ return -1;
+ }
+ break;
default:
return -1;
}
@@ -399,6 +411,8 @@
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;
return 0;
}
@@ -496,7 +510,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 +538,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 +561,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 +688,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 +709,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;
@@ -928,6 +942,39 @@
}
+#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 */
+
+
/**
* wpa_cipher_txt - Convert cipher suite to a text string
* @cipher: Cipher suite (WPA_CIPHER_* enum)
@@ -997,6 +1044,16 @@
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";
default:
return "UNKNOWN";
}
@@ -1023,6 +1080,8 @@
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;
return 0;
}
@@ -1417,56 +1476,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 +1556,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..17bed34 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -327,8 +327,8 @@
#endif /* _MSC_VER */
-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, int akmp, 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,
@@ -374,6 +374,16 @@
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 */
const char * wpa_cipher_txt(int cipher);
const char * wpa_key_mgmt_txt(int key_mgmt, int proto);
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..1f747eb 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -58,6 +58,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 +120,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 "
@@ -187,6 +200,9 @@
#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 +220,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 +235,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 +259,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 */
@@ -383,8 +406,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 +423,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-omac1.c b/src/crypto/aes-omac1.c
index 27895eb..c2b0686 100644
--- a/src/crypto/aes-omac1.c
+++ b/src/crypto/aes-omac1.c
@@ -65,6 +65,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 +90,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];
diff --git a/src/crypto/aes-siv.c b/src/crypto/aes-siv.c
new file mode 100644
index 0000000..ff4b823
--- /dev/null
+++ b/src/crypto/aes-siv.c
@@ -0,0 +1,187 @@
+/*
+ * 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"
+
+
+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;
+}
+
+
+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);
+ os_free(buf);
+ 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/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/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.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/tls.h b/src/crypto/tls.h
index 65e0f79..345ebc7 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -74,6 +74,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 +88,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
@@ -123,6 +125,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
@@ -161,6 +164,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;
diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c
index cb23eb9..20d0a31 100644
--- a/src/crypto/tls_gnutls.c
+++ b/src/crypto/tls_gnutls.c
@@ -81,7 +81,7 @@
};
struct tls_connection {
- gnutls_session session;
+ gnutls_session_t session;
char *subject_match, *altsubject_match;
int read_alerts, write_alerts, failed;
@@ -199,7 +199,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 +228,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;
@@ -286,7 +286,7 @@
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);
return 0;
@@ -563,16 +563,29 @@
}
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_PEM, 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);
+#endif
if (ret < 0) {
wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
"in PEM 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_DER,
+ 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);
+#endif
if (ret < 0) {
wpa_printf(MSG_DEBUG, "Failed to read client "
"cert/key in DER format: %s",
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index e153422..c72134a 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;
@@ -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 */
@@ -2852,7 +2866,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 +2921,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,20 +3209,64 @@
{
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;
}
@@ -3224,9 +3276,9 @@
params->suffix_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 +3286,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 +3314,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 +3388,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 +3500,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 +3525,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 +3541,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;
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 6af7294..eeaba66 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -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 */
@@ -213,6 +225,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 +244,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 +381,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 +431,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 +773,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 +801,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 +1011,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 +1034,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;
+};
+
+struct wpa_driver_mesh_join_params {
+ const u8 *meshid;
+ int meshid_len;
+ const int *basic_rates;
+ const u8 *ies;
+ int ie_len;
+ int freq;
+ int beacon_int;
+ int max_peer_links;
+ enum ht_mode ht_mode;
+ 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 +1073,7 @@
#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
+ /** Bitfield of supported key management suites */
unsigned int key_mgmt;
#define WPA_DRIVER_CAPA_ENC_WEP40 0x00000001
@@ -937,94 +1089,121 @@
#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
+ 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 +1221,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 +1248,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 +1295,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 +1360,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 +1401,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 +1516,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 +1541,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 +1847,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 +1921,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 +2752,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
@@ -2751,6 +2995,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 +3316,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 +3538,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 +3577,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 +3604,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 +3811,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 +3944,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 +4209,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 +4292,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 +4471,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 +4496,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 +4582,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..c377970 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;
}
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..8527e90 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -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 */
@@ -181,374 +147,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 +201,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 +222,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 +236,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 +251,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 +281,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 +311,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 +342,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 +365,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 +400,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 +517,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 +525,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 +542,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 +558,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 +569,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 +764,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 +790,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 +850,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 +941,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 +1029,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 +1117,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 +1153,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 +1211,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 +1273,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 +1326,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 +1375,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 +1461,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 +1567,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;
@@ -4418,11 +1601,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 +1620,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 +1669,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 +1680,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 +1834,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 +1893,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 +1997,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 +2043,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 +2065,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 +2135,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 +2153,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 +2174,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 +2212,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 +2233,6 @@
nl80211_mgmt_unsubscribe(bss, "deinit");
nl80211_del_p2pdev(bss);
}
- nl_cb_put(drv->nl_cb);
nl80211_destroy_bss(drv->first_bss);
@@ -5064,720 +2250,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 +2341,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 +2398,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 +2443,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 +2468,28 @@
!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 ?
+ 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 +2501,8 @@
"err=%d %s)", ret, strerror(-ret));
return ret;
-nla_put_failure:
+fail:
+ nl80211_nlmsg_clear(msg);
nlmsg_free(msg);
return -ENOBUFS;
}
@@ -6008,26 +2517,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 +2560,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 +2646,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 +2710,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 +2740,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 +2760,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 +2778,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 +2822,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 +2897,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 +2946,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 +2969,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");
@@ -7287,22 +3077,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_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 (!(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)))
+ goto fail;
if (basic_rates) {
u8 rates[NL80211_MAX_SUPP_RATES];
@@ -7313,13 +3099,13 @@
i++)
rates[rates_len++] = basic_rates[i] / 5;
- NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
+ if (nla_put(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len,
+ rates))
+ goto fail;
}
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
-
return send_and_recv_msgs(drv, msg, NULL, NULL);
- nla_put_failure:
+fail:
nlmsg_free(msg);
return -ENOBUFS;
}
@@ -7333,7 +3119,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,40 +3127,33 @@
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;
}
@@ -7388,75 +3167,81 @@
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) ||
+ nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL,
+ 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 +3249,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 +3260,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 +3373,67 @@
}
}
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);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq))
+ return -ENOBUFS;
+
if (freq->vht_enabled) {
+ enum nl80211_chan_width cw;
+
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);
+
+ 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;
+
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;
}
+
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, ct))
+ return -ENOBUFS;
}
return 0;
-
-nla_put_failure:
- return -ENOBUFS;
}
@@ -7634,27 +3448,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 +3481,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 +3528,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 +3586,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 +3662,7 @@
strerror(-ret));
if (ret == -EEXIST)
ret = 0;
- nla_put_failure:
+fail:
nlmsg_free(msg);
return ret;
}
@@ -7850,21 +3705,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 +3737,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 +3752,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 +3802,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 +3871,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 +3909,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 +4078,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 +4087,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,36 +4153,29 @@
}
-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;
}
@@ -8778,20 +4196,14 @@
}
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;
@@ -8804,22 +4216,24 @@
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;
+ goto fail;
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 (nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL,
+ 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,15 +4241,17 @@
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;
}
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -8847,17 +4263,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 +4282,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 +4347,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 +4369,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 +4380,8 @@
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) {
int mgmt = WLAN_AKM_SUITE_PSK;
switch (params->key_mgmt_suite) {
@@ -8981,47 +4406,67 @@
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_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->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;
+ }
+
+ 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);
- 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 (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");
- NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_VHT);
+ 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);
- 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);
+ 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 */
@@ -9029,8 +4474,6 @@
wpa_printf(MSG_DEBUG, " * P2P group");
return 0;
-nla_put_failure:
- return -1;
}
@@ -9043,16 +4486,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 +4527,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 +4591,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 +4613,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 +4638,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 +4658,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 +4728,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 +4769,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 +4793,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 +4807,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 +4827,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 +4837,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 +4861,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 +4871,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 +4936,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 +4956,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 +4984,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 +5010,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 +5088,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 +5110,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 +5157,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 +5168,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;
}
@@ -9869,8 +5221,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 +5248,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 +5280,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 +5429,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 +5446,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 +5493,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 +5503,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 +5519,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 +5603,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 +5624,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 +5641,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 +5734,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 +5749,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 +5765,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 +5929,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 +5952,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 +6020,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 +6044,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 +6064,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 +6085,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 +6161,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 +6181,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 +6198,7 @@
return ret;
-nla_put_failure:
+fail:
nlmsg_free(msg);
return -1;
}
@@ -10875,6 +6211,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 +6263,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 +6319,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 +6409,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 +6519,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 +6697,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 +6706,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,16 +6719,12 @@
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;
}
@@ -11492,29 +6737,20 @@
struct nlattr *replay_nested;
struct nl_msg *msg;
- msg = nlmsg_alloc();
- if (!msg)
+ 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, 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)) {
+ nl80211_nlmsg_clear(msg);
+ nlmsg_free(msg);
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);
+ }
nla_nest_end(msg, replay_nested);
- send_and_recv_msgs(drv, msg, NULL, NULL);
- return;
- nla_put_failure:
- nlmsg_free(msg);
+ send_and_recv_msgs(drv, msg, NULL, (void *) -1);
}
@@ -11568,19 +6804,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 +6818,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 +6871,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 +6902,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 +6915,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 +6966,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 +7098,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 +7148,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 +7163,6 @@
}
return ret;
-
-nla_put_failure:
- nlmsg_free(msg);
- return -ENOBUFS;
}
@@ -12103,14 +7231,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 +7260,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 +7296,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 +7306,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 +7316,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 +7332,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 +7346,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 +7408,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 +7424,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 +7445,7 @@
}
return ret;
-nla_put_failure:
+fail:
ret = -ENOBUFS;
error:
nlmsg_free(msg);
@@ -12335,6 +7454,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 +7576,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 +7594,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 +7607,7 @@
ret);
return ret;
-nla_put_failure:
+fail:
nlmsg_free(msg);
return -ENOBUFS;
}
@@ -12443,26 +7621,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 +7647,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 +7677,6 @@
wpa_printf(MSG_DEBUG, "nl80211: Setting wowlan failed");
return ret;
-
-nla_put_failure:
- nlmsg_free(msg);
- return -ENOBUFS;
}
@@ -12532,32 +7695,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 +7754,502 @@
}
+#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
+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 = 0;
+
+ wpa_printf(MSG_DEBUG, "nl80211: mesh join (ifindex=%d)", drv->ifindex);
+ msg = nl80211_drv_msg(drv, 0, NL80211_CMD_JOIN_MESH);
+ if (!msg)
+ goto fail;
+ if (params->freq) {
+ wpa_printf(MSG_DEBUG, " * freq=%d", params->freq);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq))
+ goto fail;
+ }
+
+ if (params->ht_mode) {
+ unsigned int ht_value;
+ char *ht_mode = "";
+
+ switch (params->ht_mode) {
+ default:
+ case CHAN_NO_HT:
+ ht_value = NL80211_CHAN_NO_HT;
+ ht_mode = "NOHT";
+ break;
+ case CHAN_HT20:
+ ht_value = NL80211_CHAN_HT20;
+ ht_mode = "HT20";
+ break;
+ case CHAN_HT40PLUS:
+ ht_value = NL80211_CHAN_HT40PLUS;
+ ht_mode = "HT40+";
+ break;
+ case CHAN_HT40MINUS:
+ ht_value = NL80211_CHAN_HT40MINUS;
+ ht_mode = "HT40-";
+ break;
+ }
+ wpa_printf(MSG_DEBUG, " * ht_mode=%s", ht_mode);
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, ht_value))
+ goto fail;
+ }
+
+ if (params->basic_rates) {
+ u8 rates[NL80211_MAX_SUPP_RATES];
+ u8 rates_len = 0;
+ int i;
+
+ for (i = 0; i < NL80211_MAX_SUPP_RATES; i++) {
+ if (params->basic_rates[i] < 0)
+ break;
+ rates[rates_len++] = params->basic_rates[i] / 5;
+ }
+
+ if (nla_put(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len,
+ rates))
+ goto fail;
+ }
+
+ if (params->meshid) {
+ wpa_hexdump_ascii(MSG_DEBUG, " * SSID",
+ params->meshid, params->meshid_len);
+ if (nla_put(msg, NL80211_ATTR_MESH_ID, params->meshid_len,
+ params->meshid))
+ goto fail;
+ }
+
+ if (params->beacon_int > 0) {
+ wpa_printf(MSG_DEBUG, " * beacon_int=%d", params->beacon_int);
+ if (nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL,
+ 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;
+ 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;
+ 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 +8277,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 +8306,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 +8323,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 +8344,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..6892b31
--- /dev/null
+++ b/src/drivers/driver_nl80211.h
@@ -0,0 +1,271 @@
+/*
+ * 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;
+
+ 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..6661a89
--- /dev/null
+++ b/src/drivers/driver_nl80211_capa.c
@@ -0,0 +1,1519 @@
+/*
+ * Driver interaction with Linux nl80211/cfg80211 - Capabilities
+ * 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 "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;
+}
+
+
+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;
+ 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;
+ 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..85769d8
--- /dev/null
+++ b/src/drivers/driver_nl80211_event.c
@@ -0,0 +1,1948 @@
+/*
+ * 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 int 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) {
+ wpa_printf(MSG_DEBUG, "nl80211: WMM data missing");
+ return -1;
+ }
+
+ if (nla_parse_nested(wmm_info, NL80211_STA_WME_MAX, wmm_attr,
+ wme_policy)) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to parse nested attributes");
+ return -1;
+ }
+
+ if (!wmm_info[NL80211_STA_WME_UAPSD_QUEUES])
+ return -1;
+
+ wmm_params->uapsd_queues =
+ nla_get_u8(wmm_info[NL80211_STA_WME_UAPSD_QUEUES]);
+ wmm_params->info_bitmap |= WMM_PARAMS_UAPSD_QUEUES_INFO;
+
+ return 0;
+}
+
+
+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)
+ return;
+
+ if (!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])
+ 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 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))
+ return;
+
+ if (!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))
+ return;
+ if (!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..7538d60
--- /dev/null
+++ b/src/drivers/driver_nl80211_scan.c
@@ -0,0 +1,796 @@
+/*
+ * 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, drv->nlmode);
+ 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_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;
+ 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%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);
+}
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..31c1a29 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);
@@ -1413,11 +1903,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 +1951,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 +2100,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 +2119,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 +2140,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..bc207e7 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
};
/**
@@ -268,6 +275,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 +336,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..3584bdb 100644
--- a/src/eap_peer/eap_config.h
+++ b/src/eap_peer/eap_config.h
@@ -686,6 +686,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..3641a2c 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -147,6 +147,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 +169,8 @@
return -1;
}
+ params->openssl_ciphers = config->openssl_ciphers;
+
return 0;
}
@@ -377,15 +381,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 +396,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 +794,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..6fbc27b 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,
@@ -1567,7 +1571,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 +1596,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 +1649,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 +1688,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..56ac7f4 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) {
@@ -1017,7 +1016,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 +1589,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 +1620,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_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..941a269 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;
}
}
@@ -2026,6 +2040,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 +2121,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..e089e88 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.
@@ -305,6 +316,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 +417,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..fc61081 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;
@@ -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..6eba2eb 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) {
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..1382c53 100644
--- a/src/radius/radius_client.c
+++ b/src/radius/radius_client.c
@@ -1039,6 +1039,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_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..aca8f54 100644
--- a/src/rsn_supp/peerkey.c
+++ b/src/rsn_supp/peerkey.c
@@ -242,7 +242,8 @@
peerkey->cipher = cipher;
#ifdef CONFIG_IEEE80211W
if (ie.key_mgmt & (WPA_KEY_MGMT_IEEE8021X_SHA256 |
- WPA_KEY_MGMT_PSK_SHA256))
+ WPA_KEY_MGMT_PSK_SHA256 |
+ WPA_KEY_MGMT_IEEE8021X_SUITE_B))
peerkey->use_sha256 = 1;
#endif /* CONFIG_IEEE80211W */
@@ -927,8 +928,8 @@
os_memcpy(mic, key->key_mic, 16);
if (peerkey->tstk_set) {
os_memset(key->key_mic, 0, 16);
- wpa_eapol_key_mic(peerkey->tstk.kck, ver, buf, len,
- key->key_mic);
+ wpa_eapol_key_mic(peerkey->tstk.kck, sm->key_mgmt, ver, buf,
+ len, key->key_mic);
if (os_memcmp_const(mic, key->key_mic, 16) != 0) {
wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC "
"when using TSTK - ignoring TSTK");
@@ -943,7 +944,7 @@
if (!ok && peerkey->stk_set) {
os_memset(key->key_mic, 0, 16);
- wpa_eapol_key_mic(peerkey->stk.kck, ver, buf, len,
+ wpa_eapol_key_mic(peerkey->stk.kck, sm->key_mgmt, ver, buf, len,
key->key_mic);
if (os_memcmp_const(mic, key->key_mic, 16) != 0) {
wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC "
diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c
index 885291a..8af04d0 100644
--- a/src/rsn_supp/pmksa_cache.c
+++ b/src/rsn_supp/pmksa_cache.c
@@ -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,19 @@
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 (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 +342,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 +482,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 +491,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 +499,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..af0e108 100644
--- a/src/rsn_supp/preauth.c
+++ b/src/rsn_supp/preauth.c
@@ -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,8 @@
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)) {
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 +393,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 +501,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..4baeb3b 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;
}
@@ -2830,39 +2846,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 +2915,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..8ea54bb 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -56,10 +56,10 @@
}
}
if (key_mic &&
- wpa_eapol_key_mic(kck, ver, msg, msg_len, key_mic)) {
+ wpa_eapol_key_mic(kck, 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);
@@ -89,7 +89,8 @@
int key_info, ver;
u8 bssid[ETH_ALEN], *rbuf;
- 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))
@@ -138,6 +139,24 @@
}
+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 */
+}
+
+
static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
const unsigned char *src_addr,
const u8 *pmkid)
@@ -198,10 +217,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 +257,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. */
@@ -586,6 +609,10 @@
return -1;
}
+ /* TK is not needed anymore in supplicant */
+ os_memset(sm->ptk.tk1, 0, sizeof(sm->ptk.tk1));
+ os_memset(sm->ptk.u.tk2, 0, sizeof(sm->ptk.u.tk2));
+
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,
@@ -1178,6 +1205,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, sizeof(sm->ptk.kck),
+ sm->bssid, sm->own_addr,
+ sm->network_ctx, sm->key_mgmt);
+ if (!sm->cur_pmksa)
+ sm->cur_pmksa = sa;
+ }
+
return;
failed:
@@ -1242,8 +1280,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,11 +1294,13 @@
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) {
@@ -1385,6 +1426,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,6 +1445,7 @@
return;
failed:
+ os_memset(&gd, 0, sizeof(gd));
wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
}
@@ -1418,7 +1461,7 @@
os_memcpy(mic, key->key_mic, 16);
if (sm->tptk_set) {
os_memset(key->key_mic, 0, 16);
- wpa_eapol_key_mic(sm->tptk.kck, ver, buf, len,
+ wpa_eapol_key_mic(sm->tptk.kck, sm->key_mgmt, ver, buf, len,
key->key_mic);
if (os_memcmp_const(mic, key->key_mic, 16) != 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
@@ -1435,7 +1478,7 @@
if (!ok && sm->ptk_set) {
os_memset(key->key_mic, 0, 16);
- wpa_eapol_key_mic(sm->ptk.kck, ver, buf, len,
+ wpa_eapol_key_mic(sm->ptk.kck, sm->key_mgmt, ver, buf, len,
key->key_mic);
if (os_memcmp_const(mic, key->key_mic, 16) != 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
@@ -1489,7 +1532,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,
@@ -1687,6 +1731,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 +1747,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 +1768,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 +1778,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 +1798,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 "
@@ -1870,7 +1926,7 @@
ret = 1;
out:
- os_free(tmp);
+ bin_clear_free(tmp, data_len);
return ret;
}
@@ -1906,6 +1962,8 @@
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;
default:
return 0;
}
@@ -1963,7 +2021,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 +2048,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 +2146,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 +2235,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 +2246,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 +2264,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 +2494,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 +2507,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 +2710,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 +2718,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 +2856,30 @@
}
#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,
+ const u8 *ptk_kek)
+{
+ if (ptk_kck) {
+ os_memcpy(sm->ptk.kck, ptk_kck, 16);
+ wpa_printf(MSG_DEBUG, "Updated PTK KCK");
+ }
+ if (ptk_kek) {
+ os_memcpy(sm->ptk.kek, ptk_kek, 16);
+ 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..cc12893 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -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,14 @@
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,
const u8 *replay_ctr);
+ int (*key_mgmt_set_pmk)(void *ctx, const u8 *pmk, size_t pmk_len);
};
@@ -105,7 +111,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 +154,10 @@
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,
+ const u8 *ptk_kek);
+
#else /* CONFIG_NO_WPA */
static inline struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx)
@@ -301,6 +312,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 +409,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_i.h b/src/rsn_supp/wpa_i.h
index 839b545..07f3692 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -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
@@ -257,11 +261,12 @@
#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,8 +315,38 @@
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 */
+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,
int ver, const u8 *dest, u16 proto,
u8 *msg, size_t msg_len, u8 *key_mic);
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index 93e8cf6..51876ed 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -173,6 +173,8 @@
} 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) {
+ 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..182c6a8 100644
--- a/src/utils/common.c
+++ b/src/utils/common.c
@@ -183,6 +183,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 +224,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 +607,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 +740,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 +880,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..7eca409 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -329,6 +329,9 @@
#ifndef ETH_ALEN
#define ETH_ALEN 6
#endif
+#ifndef ETH_HLEN
+#define ETH_HLEN 14
+#endif
#ifndef IFNAMSIZ
#define IFNAMSIZ 16
#endif
@@ -474,6 +477,7 @@
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);
@@ -493,7 +497,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 +537,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/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/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..7403c08 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';
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/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_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 43c3eed..7d7f1b6 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
@@ -85,6 +83,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
@@ -184,6 +183,12 @@
L_CFLAGS += -DCONFIG_NO_SCAN_PROCESSING
endif
+ifdef CONFIG_SUITEB
+L_CFLAGS += -DCONFIG_SUITEB
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
ifdef CONFIG_IEEE80211W
L_CFLAGS += -DCONFIG_IEEE80211W
NEED_SHA256=y
@@ -193,11 +198,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
@@ -263,7 +281,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
@@ -329,6 +346,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)
@@ -635,7 +658,6 @@
NEED_DH_GROUPS=y
NEED_SHA256=y
NEED_BASE64=y
-NEED_80211_COMMON=y
NEED_AES_CBC=y
NEED_MODEXP=y
@@ -744,7 +766,6 @@
endif
ifdef CONFIG_AP
-NEED_80211_COMMON=y
NEED_EAP_COMMON=y
NEED_RSN_AUTHENTICATOR=y
L_CFLAGS += -DCONFIG_AP
@@ -768,6 +789,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
@@ -1149,6 +1171,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
@@ -1224,6 +1249,9 @@
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
@@ -1368,14 +1396,11 @@
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
ifdef NEED_EAP_COMMON
OBJS += src/eap_common/eap_common.c
@@ -1500,26 +1525,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..06ba18f 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,12 @@
CFLAGS += -DCONFIG_NO_SCAN_PROCESSING
endif
+ifdef CONFIG_SUITEB
+CFLAGS += -DCONFIG_SUITEB
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
ifdef CONFIG_IEEE80211W
CFLAGS += -DCONFIG_IEEE80211W
NEED_SHA256=y
@@ -194,11 +201,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 +284,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 +348,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 +660,6 @@
NEED_DH_GROUPS=y
NEED_SHA256=y
NEED_BASE64=y
-NEED_80211_COMMON=y
NEED_AES_CBC=y
NEED_MODEXP=y
@@ -757,7 +781,6 @@
endif
ifdef CONFIG_AP
-NEED_80211_COMMON=y
NEED_EAP_COMMON=y
NEED_RSN_AUTHENTICATOR=y
CFLAGS += -DCONFIG_AP
@@ -781,6 +804,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
@@ -1149,6 +1173,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,6 +1262,9 @@
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
@@ -1386,14 +1416,11 @@
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
ifdef NEED_EAP_COMMON
OBJS += ../src/eap_common/eap_common.o
@@ -1539,26 +1566,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 +1595,10 @@
Q=
E=true
endif
+ifeq ($(QUIET), 1)
+Q=@
+E=true
+endif
dynamic_eap_methods: $(EAPDYN)
@@ -1680,10 +1691,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/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..2ebc7f6 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 */
@@ -155,6 +141,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 +225,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 +325,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 +564,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 +639,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 +812,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 +909,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 +994,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 +1078,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..4ebf684 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -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;
}
@@ -270,7 +270,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;
}
@@ -358,9 +358,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 +452,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 +460,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 +468,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 +541,8 @@
else if (os_strcmp(start, "OSEN") == 0)
val |= WPA_KEY_MGMT_OSEN;
#endif /* CONFIG_HS20 */
+ else if (os_strcmp(start, "WPA-EAP-SUITE-B") == 0)
+ val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B;
else {
wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
line, start);
@@ -574,7 +582,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 +592,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 +602,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 +612,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 +622,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 +633,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 +643,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 +655,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 +665,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 +677,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 +685,50 @@
}
#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 */
+
+ 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;
+ }
+
if (pos == buf) {
os_free(buf);
buf = NULL;
@@ -846,7 +898,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 +908,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 +918,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 +1039,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 +1162,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 +1316,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 +1439,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;
}
@@ -1472,7 +1524,7 @@
res = os_snprintf(pos, end - pos, MACSTR " ",
MAC2STR(ssid->p2p_client_list +
(i - 1) * ETH_ALEN));
- if (res < 0 || res >= end - pos) {
+ if (os_snprintf_error(end - pos, res)) {
os_free(value);
return NULL;
}
@@ -1542,6 +1594,97 @@
#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_MESH
+
+static int wpa_config_parse_mesh_ht_mode(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ int htval = 0;
+
+ if (os_strcmp(value, "NOHT") == 0)
+ htval = CHAN_NO_HT;
+ else if (os_strcmp(value, "HT20") == 0)
+ htval = CHAN_HT20;
+ else if (os_strcmp(value, "HT40-") == 0)
+ htval = CHAN_HT40MINUS;
+ else if (os_strcmp(value, "HT40+") == 0)
+ htval = CHAN_HT40PLUS;
+ else {
+ wpa_printf(MSG_ERROR,
+ "Line %d: no ht_mode configured.", line);
+ return -1;
+ }
+
+ wpa_printf(MSG_MSGDUMP, "mesh_ht_mode: 0x%x", htval);
+ ssid->mesh_ht_mode = htval;
+ return 0;
+}
+
+
+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_ht_mode(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ char *val;
+
+ switch (ssid->mesh_ht_mode) {
+ default:
+ val = NULL;
+ break;
+ case CHAN_NO_HT:
+ val = "NOHT";
+ break;
+ case CHAN_HT20:
+ val = "HT20";
+ break;
+ case CHAN_HT40MINUS:
+ val = "HT40-";
+ break;
+ case CHAN_HT40PLUS:
+ val = "HT40+";
+ break;
+ }
+ return val ? os_strdup(val) : NULL;
+}
+
+
+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
@@ -1682,6 +1825,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 +1840,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 +1855,14 @@
{ INT_RANGE(peerkey, 0, 1) },
{ INT_RANGE(mixed_cell, 0, 1) },
{ INT_RANGE(frequency, 0, 65000) },
+#ifdef CONFIG_MESH
+ { FUNC(mesh_ht_mode) },
+ { 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) },
@@ -1903,6 +2061,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 +2078,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
@@ -1933,12 +2091,15 @@
#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 +2161,7 @@
{
struct wpa_ssid *ssid, *prev = NULL;
struct wpa_cred *cred, *cprev;
+ int i;
ssid = config->ssid;
while (ssid) {
@@ -2018,11 +2180,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);
@@ -2181,6 +2346,13 @@
ssid->eap.fragment_size = DEFAULT_FRAGMENT_SIZE;
ssid->eap.sim_num = DEFAULT_USER_SELECTED_SIM;
#endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_MESH
+ ssid->mesh_ht_mode = DEFAULT_MESH_HT_MODE;
+ 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 +3003,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 +3085,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 +3097,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 +3166,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 +3231,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 +3261,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 +3451,8 @@
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->fast_reauth = DEFAULT_FAST_REAUTH;
config->p2p_go_intent = DEFAULT_P2P_GO_INTENT;
config->p2p_intra_bss = DEFAULT_P2P_INTRA_BSS;
@@ -3290,6 +3470,7 @@
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;
if (ctrl_interface)
config->ctrl_interface = os_strdup(ctrl_interface);
@@ -3818,11 +3999,16 @@
#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 },
+#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 +4101,7 @@
{ INT(mac_addr), 0 },
{ INT(rand_addr_lifetime), 0 },
{ INT(preassoc_mac_addr), 0 },
+ { INT(key_mgmt_offload), 0},
};
#undef FUNC
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 3fd4192..b3f7eef 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -15,6 +15,8 @@
#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_FAST_REAUTH 1
#define DEFAULT_P2P_GO_INTENT 7
#define DEFAULT_P2P_INTRA_BSS 1
@@ -28,6 +30,7 @@
#define DEFAULT_SCAN_CUR_FREQ 0
#define DEFAULT_P2P_SEARCH_DELAY 500
#define DEFAULT_RAND_ADDR_LIFETIME 60
+#define DEFAULT_KEY_MGMT_OFFLOAD 1
#include "config_ssid.h"
#include "wps/wps.h"
@@ -517,6 +520,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 +1091,34 @@
* 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;
};
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 5c8f045..5c8b24b 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -143,6 +143,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;
}
@@ -599,7 +608,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) {
@@ -707,6 +716,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);
@@ -743,6 +753,14 @@
INT(update_identifier);
#endif /* CONFIG_HS20 */
write_int(f, "mac_addr", ssid->mac_addr, -1);
+#ifdef CONFIG_MESH
+ STR(mesh_ht_mode);
+ 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
@@ -938,6 +956,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)
@@ -1190,6 +1210,15 @@
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);
}
#endif /* CONFIG_NO_CONFIG_WRITE */
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index f50b2d4..c5cd6e7 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -27,6 +27,11 @@
#define DEFAULT_FRAGMENT_SIZE 1398
#define DEFAULT_BG_SCAN_PERIOD -1
+#define DEFAULT_MESH_HT_MODE CHAN_UNDEFINED /* undefined */
+#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
@@ -317,6 +322,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 +338,7 @@
WPAS_MODE_AP = 2,
WPAS_MODE_P2P_GO = 3,
WPAS_MODE_P2P_GROUP_FORMATION = 4,
+ WPAS_MODE_MESH = 5,
} mode;
/**
@@ -400,6 +408,29 @@
*/
int frequency;
+ /**
+ * mesh_ht_mode - definition of HT mode in mesh mode
+ *
+ * Use the given HT mode for mesh networks. The driver will
+ * adapt to other stations if neccesary, but advertise the
+ * configured HT mode (HT20/HT40-/HT40+/NOHT).
+ */
+ int mesh_ht_mode;
+
+ /**
+ * 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 +697,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..acdc90d 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -7,6 +7,10 @@
*/
#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,7 @@
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
+#include "ap/hostapd.h"
#include "eap_peer/eap.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "rsn_supp/wpa.h"
@@ -42,6 +47,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 +426,30 @@
#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);
#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 +484,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) {
@@ -473,7 +495,7 @@
#endif /* CONFIG_TESTING_GET_GTK */
}
- if (res < 0 || (unsigned int) res >= buflen)
+ if (os_snprintf_error(buflen, res))
return -1;
return res;
}
@@ -626,14 +648,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 +917,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 +929,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 +966,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 +1707,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 +1730,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 +1741,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 +1749,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 +1780,7 @@
ret = 0;
break;
}
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -1632,21 +1802,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 +1825,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 +1833,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 +1849,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 +1868,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 +1891,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 +1911,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 +1937,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 +2025,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 +2107,6 @@
char *pos, *end, *stamp;
int ret;
- if (cmd == NULL) {
- return -1;
- }
-
/* cmd: "LOG_LEVEL [<level>]" */
if (*cmd == '\0') {
pos = buf;
@@ -1949,7 +2115,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 +2158,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 +2179,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 +2188,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 +2199,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 +2218,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 +2237,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 +2253,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 +2282,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 +2305,38 @@
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 */
+ 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;
+ }
+
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 +2364,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 +2393,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 +2409,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 +2454,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 +2488,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 +2512,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 +2528,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 +2770,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 +2893,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 +3021,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 +3052,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 +3063,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 +3089,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 +3119,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
@@ -3042,7 +3355,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 +3391,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;
}
@@ -3110,14 +3423,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,14 +3438,14 @@
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;
}
@@ -3165,7 +3478,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 +3487,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;
}
@@ -3206,7 +3519,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 +3527,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,7 +3535,7 @@
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;
}
@@ -3254,7 +3567,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,7 +3575,7 @@
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;
}
@@ -3299,7 +3612,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 +3620,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 +3663,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 +3672,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;
}
@@ -3443,6 +3756,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 +3785,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 +3820,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 +3828,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 +3843,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 +3851,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 +3880,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 +3891,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 +3933,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 +3958,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 +3978,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 +4000,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 +4033,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 +4045,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 +4083,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 +4115,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 +4224,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 +4278,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 +4287,6 @@
wpa_bss_flush(wpa_s);
else
wpa_bss_flush_by_age(wpa_s, flush_age);
- return 0;
}
@@ -4173,7 +4512,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 +4627,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 +5063,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 +5074,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 +5082,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 +5094,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 +5103,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 +5346,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);
}
@@ -5180,6 +5520,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 +5701,8 @@
if (used < 0)
return -1;
pos = dst + used;
+ if (*pos == ' ')
+ pos++;
for (;;) {
int num = atoi(pos);
if (num <= 0 || num > 31)
@@ -5471,14 +5815,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 +5930,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 +5946,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 +5954,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 +5975,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 +6000,8 @@
}
}
ret = os_snprintf(buf, buflen, "%s\n", "OK");
+ if (os_snprintf_error(buflen, ret))
+ ret = -1;
}
return ret;
}
@@ -5753,6 +6091,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;
@@ -5792,12 +6131,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 +6149,14 @@
#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;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ wpa_s->disconnected = 0;
+ os_free(wpa_s->next_scan_freqs);
+ wpa_s->next_scan_freqs = NULL;
}
@@ -5829,7 +6180,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 +6198,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 +6220,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 +6276,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 +6300,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 +6357,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 +6381,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 +6470,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 +6495,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 +6637,228 @@
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;
+}
+
#endif /* CONFIG_TESTING_OPTIONS */
@@ -6268,8 +6871,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 +7071,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 +7288,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 +7411,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 +7450,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 +7748,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 +7757,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 +7768,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);
@@ -7032,6 +7829,18 @@
} 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;
#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 +7851,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 +8009,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 +8035,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;
}
@@ -7433,12 +8250,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 +8264,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 +8273,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 +8367,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..2c1c6a0 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;
};
@@ -270,7 +272,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 +342,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 +560,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 +671,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) {
@@ -870,6 +884,7 @@
}
wpa_printf(MSG_DEBUG, "Using Android control socket '%s'",
ctrl + 9);
+ priv->android_control_socket = 1;
goto havesock;
}
@@ -884,6 +899,7 @@
wpa_printf(MSG_DEBUG,
"Using Android control socket '%s'",
ctrl);
+ priv->android_control_socket = 1;
goto havesock;
}
}
@@ -1064,6 +1080,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..317661a 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;
}
@@ -753,10 +711,9 @@
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;
@@ -768,6 +725,8 @@
entry->array_len = ++count;
dbus_message_iter_next(iter);
}
+ 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) {
@@ -812,10 +771,9 @@
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");
+ wpa_printf(MSG_ERROR,
+ "dbus: %s out of memory trying to retrieve the string array",
+ __func__);
goto done;
}
buffer = nbuffer;
@@ -823,17 +781,21 @@
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");
+ wpa_printf(MSG_ERROR,
+ "dbus: %s out of memory trying to duplicate the string array",
+ __func__);
goto done;
}
entry->strarray_value[count] = str;
entry->array_len = ++count;
dbus_message_iter_next(iter);
}
+ wpa_printf(MSG_MSGDUMP, "%s: string_array length %u",
+ __func__, entry->array_len);
/* Zero-length arrays are valid. */
if (entry->array_len == 0) {
@@ -856,15 +818,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 +862,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 +875,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 +897,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 +915,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 +931,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 +1027,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;
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..b21b7a8 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",
@@ -804,29 +768,20 @@
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) ||
+ (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 +807,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 +898,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 +977,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 +994,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 +1066,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 +1195,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 +1211,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 +1262,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 +1283,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 +1293,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 +1331,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 +1379,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 +1390,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 +1420,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 +1431,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 +1449,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 +1475,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 +1486,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 +1504,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 +1537,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 +1564,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 +1576,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 +1603,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 +1630,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 +1639,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 +1671,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 +1687,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 +1754,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 +1778,7 @@
dbus_message_unref(msg);
}
-#endif /*CONFIG_P2P*/
+#endif /* CONFIG_P2P */
/**
@@ -2047,7 +1972,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 +1980,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 +2045,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 +2071,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 +2186,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 +2401,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 +2442,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 +2470,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 +2512,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 +2520,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 +2528,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 +2537,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 +2546,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 +2556,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 +2598,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 +2606,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 +2667,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 +2717,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 +2738,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 +2997,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 +3157,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 +3191,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;
}
@@ -3415,6 +3334,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 +3356,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 +3417,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 +3428,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 +3479,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 +3504,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 +3612,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 +3650,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 +3713,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 +3732,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 +3744,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 +3795,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_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 9f6c4a3..166db5d 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -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;
@@ -306,27 +296,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 +373,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 +381,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 +415,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 +429,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 +475,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 +490,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,29 +531,29 @@
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)) {
+ } 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)) {
+ } 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)) {
+ } 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);
@@ -608,28 +573,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.");
}
}
@@ -672,8 +639,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 +674,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 +721,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 +777,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 +928,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 +958,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 +981,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 +1020,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 +1030,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 +1062,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 +1094,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 +1121,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 +1134,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 +1150,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 +1166,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 +1188,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 +1203,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 +1219,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 +1257,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 +1286,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 +1296,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 +1320,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 +1333,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 +1383,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 +1414,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 +1464,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 +1477,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 +1494,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 +1573,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 +1583,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 +1613,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 +1643,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 +1687,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 +1696,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 +1723,6 @@
out:
os_free(iface);
- os_free(net_id);
return reply;
}
@@ -1809,20 +1741,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 +1786,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 +1831,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 +1887,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 +1983,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 +2248,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 +2281,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 +2290,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 +2299,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 +2330,7 @@
const char *args[] = {
"ccmp", "tkip", "wep104", "wep40"
};
+
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "Group", args,
ARRAY_SIZE(args)))
@@ -2454,52 +2339,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 +2385,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 +2412,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 +2427,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 +2449,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 +2458,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 +2477,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 +2489,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 +2514,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 +2540,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 +2602,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 +2724,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 +2979,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 +3100,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 +3175,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 +3191,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 +3230,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 +3255,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 +3333,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 +3574,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[8]; /* max 8 key managements may be supported */
int n;
if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
@@ -3799,6 +3598,8 @@
key_mgmt[n++] = "wpa-ft-eap";
if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
key_mgmt[n++] = "wpa-eap-sha256";
+ if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
+ key_mgmt[n++] = "wpa-eap-suite-b";
if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE)
key_mgmt[n++] = "wpa-none";
@@ -3872,9 +3673,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 +3708,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 +3741,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 +3776,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 +3787,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 +4016,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 +4096,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..e0dd9e2 100644
--- a/wpa_supplicant/dbus/dbus_new_introspect.c
+++ b/wpa_supplicant/dbus/dbus_new_introspect.c
@@ -96,6 +96,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 +111,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 +126,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 +157,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 +232,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 +274,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..2899132 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,14 +280,14 @@
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);
}
@@ -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;
}
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..504de2a 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,19 +1131,19 @@
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);
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);
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);
if (pkcs11_module_path == NULL)
@@ -1304,8 +1223,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 +1297,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 +1336,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 +1347,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..3cf9dc3 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,
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/wpa_supplicant.sgml b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
index 182060d..e7bf4e0 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>
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 649de9b..8dc48d3 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -65,6 +65,28 @@
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)
{
@@ -222,16 +244,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 +300,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)
{
@@ -587,6 +589,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..aa9ab50 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;
}
@@ -568,6 +568,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 +929,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..8464ed4 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -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);
}
@@ -582,42 +579,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;
@@ -1136,7 +1097,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;
}
}
@@ -1346,6 +1308,9 @@
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 +1381,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 +2039,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 +2782,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 +2802,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 +2864,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 +2937,24 @@
}
+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_kek);
+}
+
+
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data)
{
@@ -2974,6 +2995,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,
@@ -3084,10 +3107,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 +3265,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 +3278,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;
}
@@ -3475,6 +3520,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..9eb5064 100644
--- a/wpa_supplicant/hs20_supplicant.c
+++ b/wpa_supplicant/hs20_supplicant.c
@@ -562,6 +562,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 +586,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 +608,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 +650,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 +661,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 +675,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 +721,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 +732,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 +808,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 +831,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 +883,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 +895,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/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..116df05 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -508,20 +508,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;
}
@@ -2525,6 +2530,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);
@@ -2808,7 +2814,9 @@
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;
}
@@ -2816,7 +2824,8 @@
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;
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..7a4f3de
--- /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->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;
+ params.freq = ssid->frequency;
+ 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;
+#ifdef CONFIG_IEEE80211N
+ params.ht_mode = ssid->mesh_ht_mode;
+#endif /* CONFIG_IEEE80211N */
+
+ 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;
+ }
+
+ 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..e7c53ea
--- /dev/null
+++ b/wpa_supplicant/mesh_mpm.c
@@ -0,0 +1,1030 @@
+/*
+ * 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->current_ssid->mesh_ht_mode > CHAN_NO_HT) {
+ 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->current_ssid->mesh_ht_mode > CHAN_NO_HT) {
+ 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..e6ae7c3
--- /dev/null
+++ b/wpa_supplicant/mesh_rsn.c
@@ -0,0 +1,615 @@
+/*
+ * 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 "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;
+}
+
+
+struct wpabuf *
+mesh_rsn_build_sae_commit(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid, struct sta_info *sta)
+{
+ struct wpabuf *buf;
+ int len;
+
+ if (ssid->passphrase == NULL) {
+ wpa_msg(wpa_s, MSG_DEBUG, "SAE: No password available");
+ return NULL;
+ }
+
+ if (mesh_rsn_sae_group(wpa_s, sta->sae) < 0) {
+ wpa_msg(wpa_s, MSG_DEBUG, "SAE: Failed to select group");
+ return NULL;
+ }
+
+ if (sae_prepare_commit(wpa_s->own_addr, sta->addr,
+ (u8 *) ssid->passphrase,
+ os_strlen(ssid->passphrase), sta->sae) < 0) {
+ wpa_msg(wpa_s, MSG_DEBUG, "SAE: Could not pick PWE");
+ return NULL;
+ }
+
+ len = wpa_s->mesh_rsn->sae_token ?
+ wpabuf_len(wpa_s->mesh_rsn->sae_token) : 0;
+ buf = wpabuf_alloc(4 + SAE_COMMIT_MAX_LEN + len);
+ if (buf == NULL)
+ return NULL;
+
+ sae_write_commit(sta->sae, buf, wpa_s->mesh_rsn->sae_token);
+
+ return buf;
+}
+
+
+static void mesh_rsn_send_auth(struct wpa_supplicant *wpa_s,
+ const u8 *dst, const u8 *src,
+ u16 auth_transaction, u16 resp,
+ struct wpabuf *data)
+{
+ struct ieee80211_mgmt *auth;
+ u8 *buf;
+ size_t len, ielen = 0;
+
+ if (data)
+ ielen = wpabuf_len(data);
+ len = IEEE80211_HDRLEN + sizeof(auth->u.auth) + ielen;
+ buf = os_zalloc(len);
+ if (buf == NULL)
+ return;
+
+ auth = (struct ieee80211_mgmt *) buf;
+ auth->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_AUTH);
+ os_memcpy(auth->da, dst, ETH_ALEN);
+ os_memcpy(auth->sa, src, ETH_ALEN);
+ os_memcpy(auth->bssid, src, ETH_ALEN);
+
+ auth->u.auth.auth_alg = host_to_le16(WLAN_AUTH_SAE);
+ auth->u.auth.auth_transaction = host_to_le16(auth_transaction);
+ auth->u.auth.status_code = host_to_le16(resp);
+
+ if (data)
+ os_memcpy(auth->u.auth.variable, wpabuf_head(data), ielen);
+
+ wpa_msg(wpa_s, MSG_DEBUG, "authentication frame: STA=" MACSTR
+ " auth_transaction=%d resp=%d (IE len=%lu)",
+ MAC2STR(dst), auth_transaction, resp, (unsigned long) ielen);
+ if (wpa_drv_send_mlme(wpa_s, buf, len, 0) < 0)
+ wpa_printf(MSG_INFO, "send_auth_reply: send_mlme failed: %s",
+ strerror(errno));
+
+ os_free(buf);
+}
+
+
+/* initiate new SAE authentication with sta */
+int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s,
+ struct sta_info *sta)
+{
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ struct wpabuf *buf;
+ unsigned int rnd;
+
+ 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;
+ }
+
+ buf = mesh_rsn_build_sae_commit(wpa_s, ssid, sta);
+ if (!buf)
+ return -1;
+
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "AUTH: started authentication with SAE peer: " MACSTR,
+ MAC2STR(sta->addr));
+
+ sta->sae->state = SAE_COMMITTED;
+ wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING);
+
+ mesh_rsn_send_auth(wpa_s, sta->addr, wpa_s->own_addr,
+ 1, WLAN_STATUS_SUCCESS, buf);
+
+ rnd = rand() % MESH_AUTH_TIMEOUT;
+ eloop_register_timeout(MESH_AUTH_TIMEOUT + rnd, 0, mesh_auth_timer,
+ wpa_s, sta);
+ wpabuf_free(buf);
+
+ 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..df1ce9e 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 */
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..42e5014 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");
@@ -882,6 +945,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 +1233,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 +1304,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 +1345,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 +1359,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 +1443,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 +1464,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) {
@@ -1443,8 +1557,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 +1839,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 +1847,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 +1909,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 +1934,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 +2952,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 +2971,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 +3017,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)
@@ -3369,6 +3504,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 +3576,7 @@
enum chan_allowed {
- NOT_ALLOWED, PASSIVE_ONLY, ALLOWED
+ NOT_ALLOWED, NO_IR, ALLOWED
};
static int has_channel(struct wpa_global *global,
@@ -3461,10 +3598,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 +3688,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 +3727,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 +3757,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 +3772,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 +3932,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 +3972,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 +4219,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 +4981,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 +5153,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 +5165,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 +5175,7 @@
break;
}
- return wpas_p2p_disconnect(wpa_s);
+ return wpas_p2p_disconnect_safely(wpa_s, calling_wpa_s);
}
@@ -5438,13 +5585,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 +5633,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 +5914,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 +5946,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);
}
@@ -6100,11 +6282,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 +6733,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;
@@ -6885,6 +7073,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 +7775,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 +7791,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 +8123,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..cb2c8d6 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)
@@ -175,6 +176,8 @@
if (ret) {
wpa_supplicant_notify_scanning(wpa_s, 0);
wpas_notify_scan_done(wpa_s, 0);
+ wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_FAILED "ret=%d",
+ ret);
radio_work_done(work);
return;
}
@@ -291,7 +294,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 +322,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 +346,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 +372,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 +384,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 +463,8 @@
}
#endif /* CONFIG_P2P */
+ wpa_supplicant_mesh_add_scan_ie(wpa_s, &extra_ie);
+
#endif /* CONFIG_WPS */
#ifdef CONFIG_HS20
@@ -528,7 +533,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,7 +605,7 @@
{
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;
@@ -653,7 +658,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;
@@ -810,7 +816,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) {
@@ -930,6 +938,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:
@@ -1145,7 +1161,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 +1289,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 +1943,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 +1980,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 +2091,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 +2126,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..80c280a 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 */
@@ -390,7 +449,18 @@
os_memcpy(pos, ext_capab, ext_capab_len);
}
+ 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 +468,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 +615,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 +624,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 +673,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 +762,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 +870,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 +978,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 +1099,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 +1122,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 +1264,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 +1345,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 +1370,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;
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..d2face0 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -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;
}
@@ -1625,7 +1626,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 +1752,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 +1940,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 +1988,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 +2015,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 +2237,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 +2258,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 +2405,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 +2524,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 +2861,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 +3012,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 +3063,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 +3368,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 +3725,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;
}
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..e5dc43f 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -52,6 +52,7 @@
#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"
@@ -105,9 +106,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 +132,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 +176,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 +301,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 +411,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 +438,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 +488,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 +529,8 @@
wpabuf_free(wpa_s->vendor_elem[i]);
wpa_s->vendor_elem[i] = NULL;
}
+
+ wmm_ac_notify_disassoc(wpa_s);
}
@@ -736,6 +763,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 +875,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)) {
/*
@@ -982,7 +1012,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 +1030,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 +1137,10 @@
sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE);
#endif /* CONFIG_SAE */
if (0) {
+ } 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");
#ifdef CONFIG_IEEE80211R
} else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) {
wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
@@ -1163,7 +1231,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 +1240,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 +1277,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 +1289,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 +1532,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 +1588,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),
@@ -1593,7 +1696,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 */
@@ -1856,8 +1960,9 @@
params.fixed_bssid = 1;
}
- if (ssid->mode == WPAS_MODE_IBSS && ssid->frequency > 0 &&
- params.freq.freq == 0) {
+ /* Initial frequency for IBSS/mesh */
+ if ((ssid->mode == WPAS_MODE_IBSS || ssid->mode == WPAS_MODE_MESH) &&
+ ssid->frequency > 0 && params.freq.freq == 0) {
enum hostapd_hw_mode hw_mode;
u8 channel;
@@ -1906,6 +2011,23 @@
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.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
@@ -2050,6 +2172,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 +2225,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 +2398,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 +2878,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 +2984,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 +3259,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 +3276,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 +3392,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;
@@ -3430,6 +3561,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 +3721,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 +3851,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 +3870,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 +3952,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 +3976,8 @@
if (wpas_init_ext_pw(wpa_s) < 0)
return -1;
+ wpas_rrm_reset(wpa_s);
+
return 0;
}
@@ -3835,6 +3985,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 +4034,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 +4100,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 +4117,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 +4147,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 +4166,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 +4274,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 +4355,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 +4493,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 +4514,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;
@@ -4681,6 +4895,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;
@@ -4785,3 +5000,261 @@
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;
+}
+
+
+/**
+ * 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..e78c0dd 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -114,6 +114,19 @@
# 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
+
# 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 +145,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
@@ -932,6 +955,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 +1339,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={
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index ae9dddd..c541ccb 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;
@@ -376,6 +378,31 @@
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;
+};
+
/**
* struct wpa_supplicant - Internal data for wpa_supplicant interface
*
@@ -417,6 +444,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;
@@ -573,8 +601,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 +676,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 +686,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 +698,13 @@
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;
+#endif /* CONFIG_MESH */
+
unsigned int off_channel_freq;
struct wpabuf *pending_action_tx;
u8 pending_action_src[ETH_ALEN];
@@ -685,6 +726,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 +797,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 +818,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;
@@ -811,6 +858,7 @@
unsigned int auto_network_select: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 +893,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 +917,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 +934,20 @@
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;
+#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 +1044,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
@@ -991,8 +1085,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);
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 38279b1..3098058 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -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;
}
@@ -866,6 +942,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->wps = wpa_s->wps;
ctx->eap_param_needed = wpa_supplicant_eap_param_needed;
ctx->port_cb = wpa_supplicant_port_cb;
@@ -899,6 +976,19 @@
#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,8 +1028,13 @@
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) {
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);