am 499d6840: Merge "Remove obsolete keystore path"
* commit '499d68402f55bd1b8aa1a0d9c6966c7392704fba':
Remove obsolete keystore path
diff --git a/Android.mk b/Android.mk
index 1fd458c..76afb77 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,5 +1,8 @@
LOCAL_PATH:= $(call my-dir)
+ifndef WPA_SUPPLICANT_VERSION
+WPA_SUPPLICANT_VERSION := VER_0_8_X
+endif
ifeq ($(WPA_SUPPLICANT_VERSION),VER_0_8_X)
# The order of the 2 Android.mks does matter!
# TODO: Clean up the Android.mks, reset all the temporary variables at the
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index 4571002..1c2e1f5 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -29,7 +29,6 @@
endif
ifeq ($(BOARD_WLAN_DEVICE), qcwcn)
-L_CFLAGS += -DANDROID_QCOM_WCN
L_CFLAGS += -DANDROID_P2P
endif
@@ -87,6 +86,7 @@
OBJS += src/ap/authsrv.c
OBJS += src/ap/ieee802_1x.c
OBJS += src/ap/ap_config.c
+OBJS += src/ap/eap_user_db.c
OBJS += src/ap/ieee802_11_auth.c
OBJS += src/ap/sta_info.c
OBJS += src/ap/wpa_auth.c
@@ -215,8 +215,15 @@
NEED_AES_UNWRAP=y
endif
-ifdef CONFIG_IEEE80211V
-L_CFLAGS += -DCONFIG_IEEE80211V
+ifdef CONFIG_SAE
+L_CFLAGS += -DCONFIG_SAE
+OBJS += src/common/sae.c
+NEED_ECC=y
+NEED_DH_GROUPS=y
+endif
+
+ifdef CONFIG_WNM
+L_CFLAGS += -DCONFIG_WNM
OBJS += src/ap/wnm_ap.c
endif
@@ -224,10 +231,6 @@
L_CFLAGS += -DCONFIG_IEEE80211N
endif
-ifdef CONFIG_WNM
-L_CFLAGS += -DCONFIG_WNM
-endif
-
ifdef CONFIG_IEEE80211AC
L_CFLAGS += -DCONFIG_IEEE80211AC
endif
@@ -402,25 +405,10 @@
NEED_MODEXP=y
CONFIG_EAP=y
-ifdef CONFIG_WPS_UFD
-L_CFLAGS += -DCONFIG_WPS_UFD
-OBJS += src/wps/wps_ufd.c
-NEED_WPS_OOB=y
-endif
-
ifdef CONFIG_WPS_NFC
L_CFLAGS += -DCONFIG_WPS_NFC
OBJS += src/wps/ndef.c
-OBJS += src/wps/wps_nfc.c
NEED_WPS_OOB=y
-ifdef CONFIG_WPS_NFC_PN531
-PN531_PATH ?= /usr/local/src/nfc
-L_CFLAGS += -DCONFIG_WPS_NFC_PN531
-L_CFLAGS += -I${PN531_PATH}/inc
-OBJS += src/wps/wps_nfc_pn531.c
-LIBS += ${PN531_PATH}/lib/wpsnfc.dll
-LIBS += ${PN531_PATH}/lib/libnfc_mapping_pn53x.dll
-endif
endif
ifdef NEED_WPS_OOB
@@ -794,6 +782,10 @@
endif
endif
+ifdef NEED_ECC
+L_CFLAGS += -DCONFIG_ECC
+endif
+
ifdef CONFIG_NO_RANDOM_POOL
L_CFLAGS += -DCONFIG_NO_RANDOM_POOL
else
@@ -890,7 +882,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE := hostapd_cli
LOCAL_MODULE_TAGS := debug
-LOCAL_SHARED_LIBRARIES := libc libcutils
+LOCAL_SHARED_LIBRARIES := libc libcutils liblog
LOCAL_CFLAGS := $(L_CFLAGS)
LOCAL_SRC_FILES := $(OBJS_c)
LOCAL_C_INCLUDES := $(INCLUDES)
@@ -906,7 +898,7 @@
ifneq ($(BOARD_HOSTAPD_PRIVATE_LIB),)
LOCAL_STATIC_LIBRARIES += $(BOARD_HOSTAPD_PRIVATE_LIB)
endif
-LOCAL_SHARED_LIBRARIES := libc libcutils libcrypto libssl
+LOCAL_SHARED_LIBRARIES := libc libcutils liblog libcrypto libssl
ifdef CONFIG_DRIVER_NL80211
LOCAL_STATIC_LIBRARIES += libnl_2
endif
diff --git a/hostapd/ChangeLog b/hostapd/ChangeLog
index 9fc05f7..1a4e566 100644
--- a/hostapd/ChangeLog
+++ b/hostapd/ChangeLog
@@ -1,5 +1,104 @@
ChangeLog for hostapd
+????-??-?? - v2.1
+ * added support for simulataneous authentication of equals (SAE) for
+ stronger password-based authentication with WPA2-Personal
+
+2013-01-12 - v2.0
+ * added AP-STA-DISCONNECTED ctrl_iface event
+ * improved debug logging (human readable event names, interface name
+ included in more entries)
+ * added number of small changes to make it easier for static analyzers
+ to understand the implementation
+ * added a workaround for Windows 7 Michael MIC failure reporting and
+ use of the Secure bit in EAPOL-Key msg 3/4
+ * fixed number of small bugs (see git logs for more details)
+ * changed OpenSSL to read full certificate chain from server_cert file
+ * nl80211: number of updates to use new cfg80211/nl80211 functionality
+ - replace monitor interface with nl80211 commands
+ - additional information for driver-based AP SME
+ * EAP-pwd:
+ - fix KDF for group 21 and zero-padding
+ - added support for fragmentation
+ - increased maximum number of hunting-and-pecking iterations
+ * avoid excessive Probe Response retries for broadcast Probe Request
+ frames (only with drivers using hostapd SME/MLME)
+ * added preliminary support for using TLS v1.2 (CONFIG_TLSV12=y)
+ * fixed WPS operation stopping on dual concurrent AP
+ * added wps_rf_bands configuration parameter for overriding RF Bands
+ value for WPS
+ * added support for getting per-device PSK from RADIUS Tunnel-Password
+ * added support for libnl 3.2 and newer
+ * increased initial group key handshake retransmit timeout to 500 ms
+ * added a workaround for 4-way handshake to update SNonce even after
+ having sent EAPOL-Key 3/4 to avoid issues with some supplicant
+ implementations that can change SNonce for each EAP-Key 2/4
+ * added a workaround for EAPOL-Key 4/4 using incorrect type value in
+ WPA2 mode (some deployed stations use WPA type in that message)
+ * added a WPS workaround for mixed mode AP Settings with Windows 7
+ * changed WPS AP PIN disabling mechanism to disable the PIN after 10
+ consecutive failures in addition to using the exponential lockout
+ period
+ * added support for WFA Hotspot 2.0
+ - GAS/ANQP advertisement of network information
+ - disable_dgaf parameter to disable downstream group-addressed
+ forwarding
+ * simplified licensing terms by selecting the BSD license as the only
+ alternative
+ * EAP-SIM: fixed re-authentication not to update pseudonym
+ * EAP-SIM: use Notification round before EAP-Failure
+ * EAP-AKA: added support for AT_COUNTER_TOO_SMALL
+ * EAP-AKA: skip AKA/Identity exchange if EAP identity is recognized
+ * EAP-AKA': fixed identity for MK derivation
+ * EAP-AKA': updated to RFC 5448 (username prefixes changed); note: this
+ breaks interoperability with older versions
+ * EAP-SIM/AKA: allow pseudonym to be used after unknown reauth id
+ * changed ANonce to be a random number instead of Counter-based
+ * added support for canceling WPS operations with hostapd_cli wps_cancel
+ * fixed EAP/WPS to PSK transition on reassociation in cases where
+ deauthentication is missed
+ * hlr_auc_gw enhancements:
+ - a new command line parameter -u can be used to enable updating of
+ SQN in Milenage file
+ - use 5 bit IND for SQN updates
+ - SQLite database can now be used to store Milenage information
+ * EAP-SIM/AKA DB: added optional use of SQLite database for pseudonyms
+ and reauth data
+ * added support for Chargeable-User-Identity (RFC 4372)
+ * added radius_auth_req_attr and radius_acct_req_attr configuration
+ parameters to allow adding/overriding of RADIUS attributes in
+ Access-Request and Accounting-Request packets
+ * added support for RADIUS dynamic authorization server (RFC 5176)
+ * added initial support for WNM operations
+ - BSS max idle period
+ - WNM-Sleep Mode
+ * added new WPS NFC ctrl_iface mechanism
+ - removed obsoleted WPS_OOB command (including support for deprecated
+ UFD config_method)
+ * added FT support for drivers that implement MLME internally
+ * added SA Query support for drivers that implement MLME internally
+ * removed default ACM=1 from AC_VO and AC_VI
+ * changed VENDOR-TEST EAP method to use proper private enterprise number
+ (this will not interoperate with older versions)
+ * added hostapd.conf parameter vendor_elements to allow arbitrary vendor
+ specific elements to be added to the Beacon and Probe Response frames
+ * added support for configuring GCMP cipher for IEEE 802.11ad
+ * added support for 256-bit AES with internal TLS implementation
+ * changed EAPOL transmission to use AC_VO if WMM is active
+ * fixed EAP-TLS/PEAP/TTLS/FAST server to validate TLS Message Length
+ correctly; invalid messages could have caused the hostapd process to
+ terminate before this fix [CVE-2012-4445]
+ * limit number of active wildcard PINs for WPS Registrar to one to avoid
+ confusing behavior with multiple wildcard PINs
+ * added a workaround for WPS PBC session overlap detection to avoid
+ interop issues with deployed station implementations that do not
+ remove active PBC indication from Probe Request frames properly
+ * added support for using SQLite for the eap_user database
+ * added Acct-Session-Id attribute into Access-Request messages
+ * fixed EAPOL frame transmission to non-QoS STAs with nl80211
+ (do not send QoS frames if the STA did not negotiate use of QoS for
+ this association)
+
2012-05-10 - v1.0
* Add channel selection support in hostapd. See hostapd.conf.
* Add support for IEEE 802.11v Time Advertisement mechanism with UTC
diff --git a/hostapd/Makefile b/hostapd/Makefile
index f5dfce0..8404e0c 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -43,6 +43,7 @@
OBJS += ../src/ap/authsrv.o
OBJS += ../src/ap/ieee802_1x.o
OBJS += ../src/ap/ap_config.o
+OBJS += ../src/ap/eap_user_db.o
OBJS += ../src/ap/ieee802_11_auth.o
OBJS += ../src/ap/sta_info.o
OBJS += ../src/ap/wpa_auth.o
@@ -171,8 +172,15 @@
NEED_AES_UNWRAP=y
endif
-ifdef CONFIG_IEEE80211V
-CFLAGS += -DCONFIG_IEEE80211V
+ifdef CONFIG_SAE
+CFLAGS += -DCONFIG_SAE
+OBJS += ../src/common/sae.o
+NEED_ECC=y
+NEED_DH_GROUPS=y
+endif
+
+ifdef CONFIG_WNM
+CFLAGS += -DCONFIG_WNM
OBJS += ../src/ap/wnm_ap.o
endif
@@ -180,10 +188,6 @@
CFLAGS += -DCONFIG_IEEE80211N
endif
-ifdef CONFIG_WNM
-CFLAGS += -DCONFIG_WNM
-endif
-
ifdef CONFIG_IEEE80211AC
CFLAGS += -DCONFIG_IEEE80211AC
endif
@@ -357,25 +361,10 @@
NEED_MODEXP=y
CONFIG_EAP=y
-ifdef CONFIG_WPS_UFD
-CFLAGS += -DCONFIG_WPS_UFD
-OBJS += ../src/wps/wps_ufd.o
-NEED_WPS_OOB=y
-endif
-
ifdef CONFIG_WPS_NFC
CFLAGS += -DCONFIG_WPS_NFC
OBJS += ../src/wps/ndef.o
-OBJS += ../src/wps/wps_nfc.o
NEED_WPS_OOB=y
-ifdef CONFIG_WPS_NFC_PN531
-PN531_PATH ?= /usr/local/src/nfc
-CFLAGS += -DCONFIG_WPS_NFC_PN531
-CFLAGS += -I${PN531_PATH}/inc
-OBJS += ../src/wps/wps_nfc_pn531.o
-LIBS += ${PN531_PATH}/lib/wpsnfc.dll
-LIBS += ${PN531_PATH}/lib/libnfc_mapping_pn53x.dll
-endif
endif
ifdef NEED_WPS_OOB
@@ -744,6 +733,10 @@
endif
endif
+ifdef NEED_ECC
+CFLAGS += -DCONFIG_ECC
+endif
+
ifdef CONFIG_NO_RANDOM_POOL
CFLAGS += -DCONFIG_NO_RANDOM_POOL
else
diff --git a/hostapd/README b/hostapd/README
index 34dad30..39b70ca 100644
--- a/hostapd/README
+++ b/hostapd/README
@@ -2,7 +2,7 @@
Authenticator and RADIUS authentication server
================================================================
-Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
This program is licensed under the BSD license (the one with
diff --git a/hostapd/README-WPS b/hostapd/README-WPS
index 87a6f91..654b5bc 100644
--- a/hostapd/README-WPS
+++ b/hostapd/README-WPS
@@ -338,3 +338,17 @@
internal Registrar. This allows station Enrollee from which the password
token was received to run through WPS protocol to provision the
credential.
+
+"nfc_get_handover_sel <NDEF> <WPS>" command can be used to build the
+contents of a Handover Select Message for connection handover when this
+does not depend on the contents of the Handover Request Message. The
+first argument selects the format of the output data and the second
+argument selects which type of connection handover is requested (WPS =
+Wi-Fi handover as specified in WSC 2.0).
+
+"nfc_report_handover <INIT/RESP> WPS <carrier from handover request>
+<carrier from handover select>" is used to report completed NFC
+connection handover. The first parameter indicates whether the local
+device initiated or responded to the connection handover and the carrier
+records are the selected carrier from the handover request and select
+messages as a hexdump.
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 0a24ec3..12d627a 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -1,6 +1,6 @@
/*
* hostapd / Configuration file parser
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -200,6 +200,12 @@
if (!fname)
return 0;
+ if (os_strncmp(fname, "sqlite:", 7) == 0) {
+ os_free(conf->eap_user_sqlite);
+ conf->eap_user_sqlite = os_strdup(fname + 7);
+ return 0;
+ }
+
f = fopen(fname, "r");
if (!f) {
wpa_printf(MSG_ERROR, "EAP user file '%s' not found.", fname);
@@ -624,6 +630,12 @@
else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+ else if (os_strcmp(start, "SAE") == 0)
+ val |= WPA_KEY_MGMT_SAE;
+ else if (os_strcmp(start, "FT-SAE") == 0)
+ val |= WPA_KEY_MGMT_FT_SAE;
+#endif /* CONFIG_SAE */
else {
wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
line, start);
@@ -649,49 +661,12 @@
static int hostapd_config_parse_cipher(int line, const char *value)
{
- int val = 0, last;
- char *start, *end, *buf;
-
- buf = os_strdup(value);
- if (buf == NULL)
+ int val = wpa_parse_cipher(value);
+ if (val < 0) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
+ line, value);
return -1;
- start = buf;
-
- while (*start != '\0') {
- while (*start == ' ' || *start == '\t')
- start++;
- if (*start == '\0')
- break;
- end = start;
- while (*end != ' ' && *end != '\t' && *end != '\0')
- end++;
- last = *end == '\0';
- *end = '\0';
- if (os_strcmp(start, "CCMP") == 0)
- val |= WPA_CIPHER_CCMP;
- else if (os_strcmp(start, "GCMP") == 0)
- val |= WPA_CIPHER_GCMP;
- else if (os_strcmp(start, "TKIP") == 0)
- val |= WPA_CIPHER_TKIP;
- else if (os_strcmp(start, "WEP104") == 0)
- val |= WPA_CIPHER_WEP104;
- else if (os_strcmp(start, "WEP40") == 0)
- val |= WPA_CIPHER_WEP40;
- else if (os_strcmp(start, "NONE") == 0)
- val |= WPA_CIPHER_NONE;
- else {
- wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
- line, start);
- os_free(buf);
- return -1;
- }
-
- if (last)
- break;
- start = end + 1;
}
- os_free(buf);
-
if (val == 0) {
wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.",
line);
@@ -1768,6 +1743,8 @@
bss->ssid.ssid_set = 1;
}
os_free(str);
+ } else if (os_strcmp(buf, "utf8_ssid") == 0) {
+ bss->ssid.utf8_ssid = atoi(pos) > 0;
} else if (os_strcmp(buf, "macaddr_acl") == 0) {
bss->macaddr_acl = atoi(pos);
if (bss->macaddr_acl != ACCEPT_UNLESS_DENIED &&
@@ -2299,6 +2276,8 @@
conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
else if (os_strcmp(pos, "g") == 0)
conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
+ else if (os_strcmp(pos, "ad") == 0)
+ conf->hw_mode = HOSTAPD_MODE_IEEE80211AD;
else {
wpa_printf(MSG_ERROR, "Line %d: unknown "
"hw_mode '%s'", line, pos);
@@ -2512,6 +2491,9 @@
} else if (os_strcmp(buf, "vht_oper_centr_freq_seg0_idx") == 0)
{
conf->vht_oper_centr_freq_seg0_idx = atoi(pos);
+ } else if (os_strcmp(buf, "vht_oper_centr_freq_seg1_idx") == 0)
+ {
+ conf->vht_oper_centr_freq_seg1_idx = atoi(pos);
#endif /* CONFIG_IEEE80211AC */
} else if (os_strcmp(buf, "max_listen_interval") == 0) {
bss->max_listen_interval = atoi(pos);
@@ -2527,6 +2509,8 @@
"wps_state", line);
errors++;
}
+ } else if (os_strcmp(buf, "wps_independent") == 0) {
+ bss->wps_independent = atoi(pos);
} else if (os_strcmp(buf, "ap_setup_locked") == 0) {
bss->ap_setup_locked = atoi(pos);
} else if (os_strcmp(buf, "uuid") == 0) {
@@ -2645,15 +2629,19 @@
"wps_nfc_dev_pw_id value", line);
errors++;
}
+ bss->wps_nfc_pw_from_config = 1;
} else if (os_strcmp(buf, "wps_nfc_dh_pubkey") == 0) {
wpabuf_free(bss->wps_nfc_dh_pubkey);
bss->wps_nfc_dh_pubkey = hostapd_parse_bin(pos);
+ bss->wps_nfc_pw_from_config = 1;
} else if (os_strcmp(buf, "wps_nfc_dh_privkey") == 0) {
wpabuf_free(bss->wps_nfc_dh_privkey);
bss->wps_nfc_dh_privkey = hostapd_parse_bin(pos);
+ bss->wps_nfc_pw_from_config = 1;
} else if (os_strcmp(buf, "wps_nfc_dev_pw") == 0) {
wpabuf_free(bss->wps_nfc_dev_pw);
bss->wps_nfc_dev_pw = hostapd_parse_bin(pos);
+ bss->wps_nfc_pw_from_config = 1;
#endif /* CONFIG_WPS_NFC */
#endif /* CONFIG_WPS */
#ifdef CONFIG_P2P_MANAGER
@@ -2702,6 +2690,12 @@
bss->time_zone = os_strdup(pos);
if (bss->time_zone == NULL)
errors++;
+#ifdef CONFIG_WNM
+ } else if (os_strcmp(buf, "wnm_sleep_mode") == 0) {
+ bss->wnm_sleep_mode = atoi(pos);
+ } else if (os_strcmp(buf, "bss_transition") == 0) {
+ bss->bss_transition = atoi(pos);
+#endif /* CONFIG_WNM */
#ifdef CONFIG_INTERWORKING
} else if (os_strcmp(buf, "interworking") == 0) {
bss->interworking = atoi(pos);
@@ -2910,6 +2904,14 @@
wpabuf_free(bss->vendor_elements);
bss->vendor_elements = elems;
+ } else if (os_strcmp(buf, "sae_anti_clogging_threshold") == 0) {
+ bss->sae_anti_clogging_threshold = atoi(pos);
+ } else if (os_strcmp(buf, "sae_groups") == 0) {
+ if (hostapd_parse_rates(&bss->sae_groups, pos)) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid "
+ "sae_groups value '%s'", line, pos);
+ return 1;
+ }
} else {
wpa_printf(MSG_ERROR, "Line %d: unknown configuration "
"item '%s'", line, buf);
@@ -2923,31 +2925,16 @@
static void hostapd_set_security_params(struct hostapd_bss_config *bss)
{
- int pairwise;
-
if (bss->individual_wep_key_len == 0) {
/* individual keys are not use; can use key idx0 for
* broadcast keys */
bss->broadcast_key_idx_min = 0;
}
- /* Select group cipher based on the enabled pairwise cipher
- * suites */
- pairwise = 0;
- if (bss->wpa & 1)
- pairwise |= bss->wpa_pairwise;
- if (bss->wpa & 2) {
- if (bss->rsn_pairwise == 0)
- bss->rsn_pairwise = bss->wpa_pairwise;
- pairwise |= bss->rsn_pairwise;
- }
- if (pairwise & WPA_CIPHER_TKIP)
- bss->wpa_group = WPA_CIPHER_TKIP;
- else if ((pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) ==
- WPA_CIPHER_GCMP)
- bss->wpa_group = WPA_CIPHER_GCMP;
- else
- bss->wpa_group = WPA_CIPHER_CCMP;
+ if ((bss->wpa & 2) && bss->rsn_pairwise == 0)
+ bss->rsn_pairwise = bss->wpa_pairwise;
+ bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa, bss->wpa_pairwise,
+ bss->rsn_pairwise);
bss->radius->auth_server = bss->radius->auth_servers;
bss->radius->acct_server = bss->radius->acct_servers;
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 1b8bede..2153329 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -250,30 +250,6 @@
}
-#ifdef CONFIG_WPS_OOB
-static int hostapd_ctrl_iface_wps_oob(struct hostapd_data *hapd, char *txt)
-{
- char *path, *method, *name;
-
- path = os_strchr(txt, ' ');
- if (path == NULL)
- return -1;
- *path++ = '\0';
-
- method = os_strchr(path, ' ');
- if (method == NULL)
- return -1;
- *method++ = '\0';
-
- name = os_strchr(method, ' ');
- if (name != NULL)
- *name++ = '\0';
-
- return hostapd_wps_start_oob(hapd, txt, path, method, name);
-}
-#endif /* CONFIG_WPS_OOB */
-
-
#ifdef CONFIG_WPS_NFC
static int hostapd_ctrl_iface_wps_nfc_tag_read(struct hostapd_data *hapd,
char *pos)
@@ -376,6 +352,59 @@
return -1;
}
+
+
+static int hostapd_ctrl_iface_nfc_get_handover_sel(struct hostapd_data *hapd,
+ char *cmd, char *reply,
+ size_t max_len)
+{
+ struct wpabuf *buf;
+ int res;
+ char *pos;
+ int ndef;
+
+ pos = os_strchr(cmd, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ if (os_strcmp(cmd, "WPS") == 0)
+ ndef = 0;
+ else if (os_strcmp(cmd, "NDEF") == 0)
+ ndef = 1;
+ else
+ return -1;
+
+ if (os_strcmp(pos, "WPS-CR") == 0)
+ buf = hostapd_wps_nfc_hs_cr(hapd, ndef);
+ else
+ buf = NULL;
+ if (buf == NULL)
+ return -1;
+
+ res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+ wpabuf_len(buf));
+ reply[res++] = '\n';
+ reply[res] = '\0';
+
+ wpabuf_free(buf);
+
+ return res;
+}
+
+
+static int hostapd_ctrl_iface_nfc_report_handover(struct hostapd_data *hapd,
+ char *cmd)
+{
+ /*
+ * Since NFC connection handover provided full WPS Credential, there is
+ * no need for additional operations within hostapd. Just report this in
+ * debug log.
+ */
+ wpa_printf(MSG_DEBUG, "NFC: Connection handover reported: %s", cmd);
+ return 0;
+}
+
#endif /* CONFIG_WPS_NFC */
@@ -460,6 +489,50 @@
#endif /* CONFIG_WPS */
+#ifdef CONFIG_WNM
+
+static int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
+ const char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ u8 buf[1000], *pos;
+ struct ieee80211_mgmt *mgmt;
+ int disassoc_timer;
+
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+ if (cmd[17] != ' ')
+ return -1;
+ disassoc_timer = atoi(cmd + 17);
+
+ os_memset(buf, 0, sizeof(buf));
+ mgmt = (struct ieee80211_mgmt *) buf;
+ mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_ACTION);
+ os_memcpy(mgmt->da, 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 =
+ WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
+ mgmt->u.action.u.bss_tm_req.disassoc_timer =
+ host_to_le16(disassoc_timer);
+ mgmt->u.action.u.bss_tm_req.validity_interval = 0;
+
+ pos = mgmt->u.action.u.bss_tm_req.variable;
+
+ if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+ wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
+ "Management Request frame");
+ return -1;
+ }
+
+ return 0;
+}
+
+
static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
const char *cmd)
{
@@ -510,6 +583,8 @@
return 0;
}
+#endif /* CONFIG_WNM */
+
static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
char *buf, size_t buflen)
@@ -613,20 +688,9 @@
pos += ret;
}
- if (hapd->conf->wpa && hapd->conf->wpa_group == WPA_CIPHER_CCMP) {
- ret = os_snprintf(pos, end - pos, "group_cipher=CCMP\n");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- } else if (hapd->conf->wpa &&
- hapd->conf->wpa_group == WPA_CIPHER_GCMP) {
- ret = os_snprintf(pos, end - pos, "group_cipher=GCMP\n");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- } else if (hapd->conf->wpa &&
- hapd->conf->wpa_group == WPA_CIPHER_TKIP) {
- ret = os_snprintf(pos, end - pos, "group_cipher=TKIP\n");
+ 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)
return pos - buf;
pos += ret;
@@ -638,24 +702,11 @@
return pos - buf;
pos += ret;
- if (hapd->conf->rsn_pairwise & WPA_CIPHER_CCMP) {
- ret = os_snprintf(pos, end - pos, "CCMP ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- }
- if (hapd->conf->rsn_pairwise & WPA_CIPHER_GCMP) {
- ret = os_snprintf(pos, end - pos, "GCMP ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- }
- if (hapd->conf->rsn_pairwise & WPA_CIPHER_TKIP) {
- ret = os_snprintf(pos, end - pos, "TKIP ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- }
+ ret = wpa_write_ciphers(pos, end, hapd->conf->rsn_pairwise,
+ " ");
+ if (ret < 0)
+ return pos - buf;
+ pos += ret;
ret = os_snprintf(pos, end - pos, "\n");
if (ret < 0 || ret >= end - pos)
@@ -669,24 +720,11 @@
return pos - buf;
pos += ret;
- if (hapd->conf->wpa_pairwise & WPA_CIPHER_CCMP) {
- ret = os_snprintf(pos, end - pos, "CCMP ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- }
- if (hapd->conf->wpa_pairwise & WPA_CIPHER_GCMP) {
- ret = os_snprintf(pos, end - pos, "GCMP ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- }
- if (hapd->conf->wpa_pairwise & WPA_CIPHER_TKIP) {
- ret = os_snprintf(pos, end - pos, "TKIP ");
- if (ret < 0 || ret >= end - pos)
- return pos - buf;
- pos += ret;
- }
+ ret = wpa_write_ciphers(pos, end, hapd->conf->rsn_pairwise,
+ " ");
+ if (ret < 0)
+ return pos - buf;
+ pos += ret;
ret = os_snprintf(pos, end - pos, "\n");
if (ret < 0 || ret >= end - pos)
@@ -912,11 +950,6 @@
} else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
if (hostapd_wps_cancel(hapd))
reply_len = -1;
-#ifdef CONFIG_WPS_OOB
- } else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) {
- if (hostapd_ctrl_iface_wps_oob(hapd, buf + 8))
- reply_len = -1;
-#endif /* CONFIG_WPS_OOB */
} else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11,
reply, reply_size);
@@ -933,11 +966,22 @@
} else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
reply_len = hostapd_ctrl_iface_wps_nfc_token(
hapd, buf + 14, reply, reply_size);
+ } else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
+ reply_len = hostapd_ctrl_iface_nfc_get_handover_sel(
+ hapd, buf + 21, reply, reply_size);
+ } else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) {
+ if (hostapd_ctrl_iface_nfc_report_handover(hapd, buf + 20))
+ reply_len = -1;
#endif /* CONFIG_WPS_NFC */
#endif /* CONFIG_WPS */
+#ifdef CONFIG_WNM
+ } else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) {
+ if (hostapd_ctrl_iface_disassoc_imminent(hapd, buf + 18))
+ reply_len = -1;
} else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) {
if (hostapd_ctrl_iface_ess_disassoc(hapd, buf + 13))
reply_len = -1;
+#endif /* CONFIG_WNM */
} else if (os_strcmp(buf, "GET_CONFIG") == 0) {
reply_len = hostapd_ctrl_iface_get_config(hapd, reply,
reply_size);
@@ -1026,12 +1070,35 @@
}
if (hapd->conf->ctrl_interface_gid_set &&
- chown(hapd->conf->ctrl_interface, 0,
+ chown(hapd->conf->ctrl_interface, -1,
hapd->conf->ctrl_interface_gid) < 0) {
perror("chown[ctrl_interface]");
return -1;
}
+ if (!hapd->conf->ctrl_interface_gid_set &&
+ hapd->iface->interfaces->ctrl_iface_group &&
+ chown(hapd->conf->ctrl_interface, -1,
+ hapd->iface->interfaces->ctrl_iface_group) < 0) {
+ perror("chown[ctrl_interface]");
+ return -1;
+ }
+
+#ifdef ANDROID
+ /*
+ * Android is using umask 0077 which would leave the control interface
+ * directory without group access. This breaks things since Wi-Fi
+ * framework assumes that this directory can be accessed by other
+ * applications in the wifi group. Fix this by adding group access even
+ * if umask value would prevent this.
+ */
+ if (chmod(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
+ wpa_printf(MSG_ERROR, "CTRL: Could not chmod directory: %s",
+ strerror(errno));
+ /* Try to continue anyway */
+ }
+#endif /* ANDROID */
+
if (os_strlen(hapd->conf->ctrl_interface) + 1 +
os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
goto fail;
@@ -1084,7 +1151,14 @@
}
if (hapd->conf->ctrl_interface_gid_set &&
- chown(fname, 0, hapd->conf->ctrl_interface_gid) < 0) {
+ chown(fname, -1, hapd->conf->ctrl_interface_gid) < 0) {
+ perror("chown[ctrl_interface/ifname]");
+ 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]");
goto fail;
}
@@ -1257,6 +1331,11 @@
perror("mkdir[ctrl_interface]");
goto fail;
}
+ } else if (interface->ctrl_iface_group &&
+ chown(interface->global_iface_path, -1,
+ interface->ctrl_iface_group) < 0) {
+ perror("chown[ctrl_interface]");
+ goto fail;
}
if (os_strlen(interface->global_iface_path) + 1 +
@@ -1310,6 +1389,12 @@
}
}
+ if (interface->ctrl_iface_group &&
+ chown(fname, -1, interface->ctrl_iface_group) < 0) {
+ perror("chown[ctrl_interface]");
+ goto fail;
+ }
+
if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
perror("chmod[ctrl_interface/ifname]");
goto fail;
diff --git a/hostapd/defconfig b/hostapd/defconfig
index 204aa76..b5ddca3 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -265,5 +265,5 @@
# Hotspot 2.0
#CONFIG_HS20=y
-# Enable SQLite database support in hlr_auc_gw
+# Enable SQLite database support in hlr_auc_gw, EAP-SIM DB, and eap_user_file
#CONFIG_SQLITE=y
diff --git a/hostapd/dump_state.c b/hostapd/dump_state.c
index d33e05f..fcd9890 100644
--- a/hostapd/dump_state.c
+++ b/hostapd/dump_state.c
@@ -19,6 +19,7 @@
#include "ap/ap_config.h"
#include "ap/sta_info.h"
#include "dump_state.h"
+#include "ap/ap_drv_ops.h"
static void fprint_char(FILE *f, char c)
@@ -72,6 +73,7 @@
#ifndef CONFIG_NO_RADIUS
char *buf;
#endif /* CONFIG_NO_RADIUS */
+ struct hostap_sta_driver_data data;
if (!hapd->conf->dump_log_name) {
wpa_printf(MSG_DEBUG, "Dump file not defined - ignoring dump "
@@ -139,6 +141,13 @@
"DEAUTH")));
ieee802_1x_dump_state(f, " ", sta);
+
+ if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) == 0) {
+ fprintf(f, " rx_pkt=%lu tx_pkt=%lu\n"
+ " rx_byte=%lu tx_byte=%lu\n",
+ data.rx_packets, data.tx_packets,
+ data.rx_bytes, data.tx_bytes);
+ }
}
#ifndef CONFIG_NO_RADIUS
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index edbd772..17bb7ed 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -90,6 +90,9 @@
#ssid2=74657374
#ssid2=P"hello\nthere"
+# UTF-8 SSID: Whether the SSID is to be interpreted using UTF-8 encoding
+#utf8_ssid=1
+
# Country code (ISO/IEC 3166-1). Used to set regulatory domain.
# Set as needed to indicate country in which device is operating.
# This can limit available channels and transmit power.
@@ -103,6 +106,8 @@
#ieee80211d=1
# Operation mode (a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g,
+# ad = IEEE 802.11ad (60 GHz); a/g options are used with IEEE 802.11n, too, to
+# specify band)
# Default: IEEE 802.11b
hw_mode=g
@@ -572,6 +577,12 @@
# which is channel 42 in 5G band
#
#vht_oper_centr_freq_seg0_idx=42
+#
+# center freq = 5 GHz + (5 * index)
+# So index 159 gives center freq 5.795 GHz
+# which is channel 159 in 5G band
+#
+#vht_oper_centr_freq_seg1_idx=159
##### IEEE 802.1X-2004 related configuration ##################################
@@ -629,6 +640,8 @@
eap_server=0
# Path for EAP server user database
+# If SQLite support is included, this can be set to "sqlite:/path/to/sqlite.db"
+# to use SQLite database instead of a text file.
#eap_user_file=/etc/hostapd.eap_user
# CA certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS
@@ -1024,6 +1037,19 @@
# 1 = enabled
#okc=1
+# SAE threshold for anti-clogging mechanism (dot11RSNASAEAntiCloggingThreshold)
+# This parameter defines how many open SAE instances can be in progress at the
+# same time before the anti-clogging mechanism is taken into use.
+#sae_anti_clogging_threshold=5
+
+# Enabled SAE finite cyclic groups
+# SAE implementation are required to support group 19 (ECC group defined over a
+# 256-bit prime order field). All groups that are supported by the
+# implementation are enabled by default. This configuration parameter can be
+# used to specify a limited set of allowed groups. The group values are listed
+# in the IANA registry:
+# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-9
+#sae_groups=19 20 21 25 26
##### IEEE 802.11r configuration ##############################################
@@ -1098,6 +1124,14 @@
# 2 = WPS enabled, configured
#wps_state=2
+# Whether to manage this interface independently from other WPS interfaces
+# By default, a single hostapd process applies WPS operations to all configured
+# interfaces. This parameter can be used to disable that behavior for a subset
+# of interfaces. If this is set to non-zero for an interface, WPS commands
+# issued on that interface do not apply to other interfaces and WPS operations
+# performed on other interfaces do not affect this interface.
+#wps_independent=0
+
# AP can be configured into a locked state where new WPS Registrar are not
# accepted, but previously authorized Registrars (including the internal one)
# can continue to add new Enrollees.
@@ -1292,6 +1326,16 @@
# stdoffset[dst[offset][,start[/time],end[/time]]]
#time_zone=EST5
+# WNM-Sleep Mode (extended sleep mode for stations)
+# 0 = disabled (default)
+# 1 = enabled (allow stations to use WNM-Sleep Mode)
+#wnm_sleep_mode=1
+
+# BSS Transition Management
+# 0 = disabled (default)
+# 1 = enabled
+#bss_transition=1
+
##### IEEE 802.11u-2011 #######################################################
# Enable Interworking service
diff --git a/hostapd/hostapd.eap_user_sqlite b/hostapd/hostapd.eap_user_sqlite
new file mode 100644
index 0000000..f688327
--- /dev/null
+++ b/hostapd/hostapd.eap_user_sqlite
@@ -0,0 +1,17 @@
+CREATE TABLE users(
+ identity TEXT PRIMARY KEY,
+ methods TEXT,
+ password TEXT,
+ phase2 INTEGER
+);
+
+CREATE TABLE wildcards(
+ identity TEXT PRIMARY KEY,
+ methods TEXT
+);
+
+INSERT INTO users(identity,methods,password,phase2) VALUES ('user','TTLS-MSCHAPV2','password',1);
+INSERT INTO users(identity,methods,password,phase2) VALUES ('DOMAIN\mschapv2 user','TTLS-MSCHAPV2','password',1);
+
+INSERT INTO wildcards(identity,methods) VALUES ('','TTLS,TLS');
+INSERT INTO wildcards(identity,methods) VALUES ('0','AKA');
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index 27bea2a..1537275 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -18,7 +18,7 @@
static const char *hostapd_cli_version =
"hostapd_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi> and contributors";
static const char *hostapd_cli_license =
@@ -72,9 +72,6 @@
" wps_check_pin <PIN> verify PIN checksum\n"
" wps_pbc indicate button pushed to initiate PBC\n"
" wps_cancel cancel the pending WPS operation\n"
-#ifdef CONFIG_WPS_OOB
-" wps_oob <type> <path> <method> use WPS with out-of-band (UFD)\n"
-#endif /* CONFIG_WPS_OOB */
#ifdef CONFIG_WPS_NFC
" wps_nfc_tag_read <hexdump> report read NFC tag with WPS data\n"
" wps_nfc_config_token <WPS/NDEF> build NFC configuration token\n"
@@ -410,40 +407,6 @@
}
-#ifdef CONFIG_WPS_OOB
-static int hostapd_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc,
- char *argv[])
-{
- char cmd[256];
- int res;
-
- if (argc != 3 && argc != 4) {
- printf("Invalid WPS_OOB command: need three or four "
- "arguments:\n"
- "- DEV_TYPE: use 'ufd' or 'nfc'\n"
- "- PATH: path of OOB device like '/mnt'\n"
- "- METHOD: OOB method 'pin-e' or 'pin-r', "
- "'cred'\n"
- "- DEV_NAME: (only for NFC) device name like "
- "'pn531'\n");
- return -1;
- }
-
- if (argc == 3)
- res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s",
- argv[0], argv[1], argv[2]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s %s",
- argv[0], argv[1], argv[2], argv[3]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_OOB command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
-}
-#endif /* CONFIG_WPS_OOB */
-
-
#ifdef CONFIG_WPS_NFC
static int hostapd_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc,
char *argv[])
@@ -512,6 +475,29 @@
}
return wpa_ctrl_command(ctrl, cmd);
}
+
+
+static int hostapd_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl,
+ int argc, char *argv[])
+{
+ char cmd[64];
+ int res;
+
+ if (argc != 2) {
+ printf("Invalid 'nfc_get_handover_sel' command - two arguments "
+ "are required.\n");
+ return -1;
+ }
+
+ 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) {
+ printf("Too long NFC_GET_HANDOVER_SEL command.\n");
+ return -1;
+ }
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
#endif /* CONFIG_WPS_NFC */
@@ -581,6 +567,26 @@
#endif /* CONFIG_WPS */
+static int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char buf[300];
+ int res;
+
+ if (argc < 2) {
+ printf("Invalid 'disassoc_imminent' command - two arguments "
+ "(STA addr and Disassociation Timer) are needed\n");
+ return -1;
+ }
+
+ res = os_snprintf(buf, sizeof(buf), "DISASSOC_IMMINENT %s %s",
+ argv[0], argv[1]);
+ if (res < 0 || res >= (int) sizeof(buf))
+ return -1;
+ return wpa_ctrl_command(ctrl, buf);
+}
+
+
static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -809,17 +815,16 @@
{ "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
{ "wps_pbc", hostapd_cli_cmd_wps_pbc },
{ "wps_cancel", hostapd_cli_cmd_wps_cancel },
-#ifdef CONFIG_WPS_OOB
- { "wps_oob", hostapd_cli_cmd_wps_oob },
-#endif /* CONFIG_WPS_OOB */
#ifdef CONFIG_WPS_NFC
{ "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read },
{ "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token },
{ "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token },
+ { "nfc_get_handover_sel", hostapd_cli_cmd_nfc_get_handover_sel },
#endif /* CONFIG_WPS_NFC */
{ "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
{ "wps_config", hostapd_cli_cmd_wps_config },
#endif /* CONFIG_WPS */
+ { "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent },
{ "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
{ "get_config", hostapd_cli_cmd_get_config },
{ "help", hostapd_cli_cmd_help },
diff --git a/hostapd/main.c b/hostapd/main.c
index 56f0002..d2ec1a5 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -9,6 +9,7 @@
#include "utils/includes.h"
#ifndef CONFIG_NATIVE_WINDOWS
#include <syslog.h>
+#include <grp.h>
#endif /* CONFIG_NATIVE_WINDOWS */
#include "utils/common.h"
@@ -273,6 +274,9 @@
hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) {
iface->drv_flags = capa.flags;
iface->probe_resp_offloads = capa.probe_resp_offloads;
+ iface->extended_capa = capa.extended_capa;
+ iface->extended_capa_mask = capa.extended_capa_mask;
+ iface->extended_capa_len = capa.extended_capa_len;
}
return 0;
@@ -468,7 +472,7 @@
"hostapd v" VERSION_STR "\n"
"User space daemon for IEEE 802.11 AP management,\n"
"IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
- "Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> "
+ "Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi> "
"and contributors\n");
}
@@ -480,7 +484,8 @@
"\n"
"usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] "
"\\\n"
- " [-g <global ctrl_iface>] <configuration file(s)>\n"
+ " [-g <global ctrl_iface>] [-G <group>] \\\n"
+ " <configuration file(s)>\n"
"\n"
"options:\n"
" -h show this usage\n"
@@ -488,6 +493,7 @@
" -B run daemon in the background\n"
" -e entropy file\n"
" -g global control interface path\n"
+ " -G group for control interfaces\n"
" -P PID file\n"
" -K include key data in debug messages\n"
#ifdef CONFIG_DEBUG_FILE
@@ -519,6 +525,8 @@
return -1;
pos = os_strrchr(interfaces->global_iface_path, '/');
if (pos == NULL) {
+ wpa_printf(MSG_ERROR, "No '/' in the global control interface "
+ "file");
os_free(interfaces->global_iface_path);
interfaces->global_iface_path = NULL;
return -1;
@@ -531,6 +539,22 @@
}
+static int hostapd_get_ctrl_iface_group(struct hapd_interfaces *interfaces,
+ const char *group)
+{
+#ifndef CONFIG_NATIVE_WINDOWS
+ struct group *grp;
+ grp = getgrnam(group);
+ if (grp == NULL) {
+ wpa_printf(MSG_ERROR, "Unknown group '%s'", group);
+ return -1;
+ }
+ interfaces->ctrl_iface_group = grp->gr_gid;
+#endif /* CONFIG_NATIVE_WINDOWS */
+ return 0;
+}
+
+
int main(int argc, char *argv[])
{
struct hapd_interfaces interfaces;
@@ -556,7 +580,7 @@
interfaces.global_ctrl_sock = -1;
for (;;) {
- c = getopt(argc, argv, "Bde:f:hKP:tvg:");
+ c = getopt(argc, argv, "Bde:f:hKP:tvg:G:");
if (c < 0)
break;
switch (c) {
@@ -592,9 +616,13 @@
exit(1);
break;
case 'g':
- hostapd_get_global_ctrl_iface(&interfaces, optarg);
+ if (hostapd_get_global_ctrl_iface(&interfaces, optarg))
+ return -1;
break;
-
+ case 'G':
+ if (hostapd_get_ctrl_iface_group(&interfaces, optarg))
+ return -1;
+ break;
default:
usage();
break;
diff --git a/hostapd/wps-ap-nfc.py b/hostapd/wps-ap-nfc.py
new file mode 100755
index 0000000..61b5519
--- /dev/null
+++ b/hostapd/wps-ap-nfc.py
@@ -0,0 +1,273 @@
+#!/usr/bin/python
+#
+# Example nfcpy to hostapd wrapper for WPS NFC operations
+# Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import os
+import sys
+import time
+
+import nfc
+import nfc.ndef
+import nfc.llcp
+import nfc.handover
+
+import logging
+logging.basicConfig()
+
+import wpaspy
+
+wpas_ctrl = '/var/run/hostapd'
+
+def wpas_connect():
+ ifaces = []
+ if os.path.isdir(wpas_ctrl):
+ try:
+ ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
+ except OSError, error:
+ print "Could not find hostapd: ", error
+ return None
+
+ if len(ifaces) < 1:
+ print "No hostapd control interface found"
+ return None
+
+ for ctrl in ifaces:
+ try:
+ wpas = wpaspy.Ctrl(ctrl)
+ return wpas
+ except Exception, e:
+ pass
+ return None
+
+
+def wpas_tag_read(message):
+ wpas = wpas_connect()
+ if (wpas == None):
+ return
+ print wpas.request("WPS_NFC_TAG_READ " + message.encode("hex"))
+
+
+def wpas_get_config_token():
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ return wpas.request("WPS_NFC_CONFIG_TOKEN NDEF").rstrip().decode("hex")
+
+
+def wpas_get_password_token():
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ return wpas.request("WPS_NFC_TOKEN NDEF").rstrip().decode("hex")
+
+
+def wpas_get_handover_sel():
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ return wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR").rstrip().decode("hex")
+
+
+def wpas_report_handover(req, sel):
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ return wpas.request("NFC_REPORT_HANDOVER RESP WPS " +
+ str(req).encode("hex") + " " +
+ str(sel).encode("hex"))
+
+
+class HandoverServer(nfc.handover.HandoverServer):
+ def __init__(self):
+ super(HandoverServer, self).__init__()
+
+ def process_request(self, request):
+ print "HandoverServer - request received"
+ print "Parsed handover request: " + request.pretty()
+
+ sel = nfc.ndef.HandoverSelectMessage(version="1.2")
+
+ for carrier in request.carriers:
+ print "Remote carrier type: " + carrier.type
+ if carrier.type == "application/vnd.wfa.wsc":
+ print "WPS carrier type match - add WPS carrier record"
+ self.received_carrier = carrier.record
+ data = wpas_get_handover_sel()
+ if data is None:
+ print "Could not get handover select carrier record from hostapd"
+ continue
+ print "Handover select carrier record from hostapd:"
+ print data.encode("hex")
+ self.sent_carrier = data
+
+ message = nfc.ndef.Message(data);
+ sel.add_carrier(message[0], "active", message[1:])
+
+ print "Handover select:"
+ print sel.pretty()
+ print str(sel).encode("hex")
+
+ print "Sending handover select"
+ return sel
+
+
+def wps_handover_resp(peer):
+ print "Trying to handle WPS handover"
+
+ srv = HandoverServer()
+ srv.sent_carrier = None
+
+ nfc.llcp.activate(peer);
+
+ try:
+ print "Trying handover";
+ srv.start()
+ print "Wait for disconnect"
+ while nfc.llcp.connected():
+ time.sleep(0.1)
+ print "Disconnected after handover"
+ except nfc.llcp.ConnectRefused:
+ print "Handover connection refused"
+ nfc.llcp.shutdown()
+ return
+
+ if srv.sent_carrier:
+ wpas_report_handover(srv.received_carrier, srv.sent_carrier)
+
+ print "Remove peer"
+ nfc.llcp.shutdown()
+ print "Done with handover"
+
+
+def wps_tag_read(tag):
+ if len(tag.ndef.message):
+ message = nfc.ndef.Message(tag.ndef.message)
+ print "message type " + message.type
+
+ for record in message:
+ print "record type " + record.type
+ if record.type == "application/vnd.wfa.wsc":
+ print "WPS tag - send to hostapd"
+ wpas_tag_read(tag.ndef.message)
+ break
+ else:
+ print "Empty tag"
+
+ print "Remove tag"
+ while tag.is_present:
+ time.sleep(0.1)
+
+
+def wps_write_config_tag(clf):
+ print "Write WPS config token"
+ data = wpas_get_config_token()
+ if (data == None):
+ print "Could not get WPS config token from hostapd"
+ return
+
+ print "Touch an NFC tag"
+ while True:
+ tag = clf.poll()
+ if tag == None:
+ time.sleep(0.1)
+ continue
+ break
+
+ print "Tag found - writing"
+ tag.ndef.message = data
+ print "Done - remove tag"
+ while tag.is_present:
+ time.sleep(0.1)
+
+
+def wps_write_password_tag(clf):
+ print "Write WPS password token"
+ data = wpas_get_password_token()
+ if (data == None):
+ print "Could not get WPS password token from hostapd"
+ return
+
+ print "Touch an NFC tag"
+ while True:
+ tag = clf.poll()
+ if tag == None:
+ time.sleep(0.1)
+ continue
+ break
+
+ print "Tag found - writing"
+ tag.ndef.message = data
+ print "Done - remove tag"
+ while tag.is_present:
+ time.sleep(0.1)
+
+
+def find_peer(clf):
+ while True:
+ if nfc.llcp.connected():
+ print "LLCP connected"
+ general_bytes = nfc.llcp.startup({})
+ peer = clf.listen(ord(os.urandom(1)) + 250, general_bytes)
+ if isinstance(peer, nfc.DEP):
+ print "listen -> DEP";
+ if peer.general_bytes.startswith("Ffm"):
+ print "Found DEP"
+ return peer
+ print "mismatch in general_bytes"
+ print peer.general_bytes
+
+ peer = clf.poll(general_bytes)
+ if isinstance(peer, nfc.DEP):
+ print "poll -> DEP";
+ if peer.general_bytes.startswith("Ffm"):
+ print "Found DEP"
+ return peer
+ print "mismatch in general_bytes"
+ print peer.general_bytes
+
+ if peer:
+ print "Found tag"
+ return peer
+
+
+def main():
+ clf = nfc.ContactlessFrontend()
+
+ try:
+ if len(sys.argv) > 1 and sys.argv[1] == "write-config":
+ wps_write_config_tag(clf)
+ raise SystemExit
+
+ if len(sys.argv) > 1 and sys.argv[1] == "write-password":
+ wps_write_password_tag(clf)
+ raise SystemExit
+
+ while True:
+ print "Waiting for a tag or peer to be touched"
+
+ tag = find_peer(clf)
+ if isinstance(tag, nfc.DEP):
+ wps_handover_resp(tag)
+ continue
+
+ if tag.ndef:
+ wps_tag_read(tag)
+ continue
+
+ print "Not an NDEF tag - remove tag"
+ while tag.is_present:
+ time.sleep(0.1)
+
+ except KeyboardInterrupt:
+ raise SystemExit
+ finally:
+ clf.close()
+
+ raise SystemExit
+
+if __name__ == '__main__':
+ main()
diff --git a/src/ap/accounting.c b/src/ap/accounting.c
index 7563b52..9540531 100644
--- a/src/ap/accounting.c
+++ b/src/ap/accounting.c
@@ -26,8 +26,6 @@
* input/output octets and updates Acct-{Input,Output}-Gigawords. */
#define ACCT_DEFAULT_UPDATE_INTERVAL 300
-static void accounting_sta_get_id(struct hostapd_data *hapd,
- struct sta_info *sta);
static void accounting_sta_interim(struct hostapd_data *hapd,
struct sta_info *sta);
@@ -210,7 +208,6 @@
if (sta->acct_session_started)
return;
- accounting_sta_get_id(hapd, sta);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
"starting accounting session %08X-%08X",
@@ -377,7 +374,7 @@
}
-static void accounting_sta_get_id(struct hostapd_data *hapd,
+void accounting_sta_get_id(struct hostapd_data *hapd,
struct sta_info *sta)
{
sta->acct_session_id_lo = hapd->acct_session_id_lo++;
diff --git a/src/ap/accounting.h b/src/ap/accounting.h
index 9d13d01..dcc54ee 100644
--- a/src/ap/accounting.h
+++ b/src/ap/accounting.h
@@ -10,6 +10,11 @@
#define ACCOUNTING_H
#ifdef CONFIG_NO_ACCOUNTING
+static inline void accounting_sta_get_id(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+}
+
static inline void accounting_sta_start(struct hostapd_data *hapd,
struct sta_info *sta)
{
@@ -29,6 +34,7 @@
{
}
#else /* CONFIG_NO_ACCOUNTING */
+void accounting_sta_get_id(struct hostapd_data *hapd, struct sta_info *sta);
void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta);
void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta);
int accounting_init(struct hostapd_data *hapd);
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 31e1c19..922f564 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -89,6 +89,8 @@
#endif /* CONFIG_IEEE80211R */
bss->radius_das_time_window = 300;
+
+ bss->sae_anti_clogging_threshold = 5;
}
@@ -158,6 +160,9 @@
conf->ht_capab = HT_CAP_INFO_SMPS_DISABLED;
+ conf->ap_table_max_size = 255;
+ conf->ap_table_expiration_time = 60;
+
return conf;
}
@@ -408,6 +413,7 @@
user = user->next;
hostapd_config_free_eap_user(prev_user);
}
+ os_free(conf->eap_user_sqlite);
os_free(conf->dump_log_name);
os_free(conf->eap_req_id_text);
@@ -515,6 +521,8 @@
#endif /* CONFIG_HS20 */
wpabuf_free(conf->vendor_elements);
+
+ os_free(conf->sae_groups);
}
@@ -619,57 +627,3 @@
return NULL;
}
-
-
-const struct hostapd_eap_user *
-hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity,
- size_t identity_len, int phase2)
-{
- struct hostapd_eap_user *user = conf->eap_user;
-
-#ifdef CONFIG_WPS
- if (conf->wps_state && identity_len == WSC_ID_ENROLLEE_LEN &&
- os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0) {
- static struct hostapd_eap_user wsc_enrollee;
- os_memset(&wsc_enrollee, 0, sizeof(wsc_enrollee));
- wsc_enrollee.methods[0].method = eap_server_get_type(
- "WSC", &wsc_enrollee.methods[0].vendor);
- return &wsc_enrollee;
- }
-
- if (conf->wps_state && identity_len == WSC_ID_REGISTRAR_LEN &&
- os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0) {
- static struct hostapd_eap_user wsc_registrar;
- os_memset(&wsc_registrar, 0, sizeof(wsc_registrar));
- wsc_registrar.methods[0].method = eap_server_get_type(
- "WSC", &wsc_registrar.methods[0].vendor);
- wsc_registrar.password = (u8 *) conf->ap_pin;
- wsc_registrar.password_len = conf->ap_pin ?
- os_strlen(conf->ap_pin) : 0;
- return &wsc_registrar;
- }
-#endif /* CONFIG_WPS */
-
- while (user) {
- if (!phase2 && user->identity == NULL) {
- /* Wildcard match */
- break;
- }
-
- if (user->phase2 == !!phase2 && user->wildcard_prefix &&
- identity_len >= user->identity_len &&
- os_memcmp(user->identity, identity, user->identity_len) ==
- 0) {
- /* Wildcard prefix match */
- break;
- }
-
- if (user->phase2 == !!phase2 &&
- user->identity_len == identity_len &&
- os_memcmp(user->identity, identity, identity_len) == 0)
- break;
- user = user->next;
- }
-
- return user;
-}
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index f5e4a6a..d9ef984 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -51,7 +51,8 @@
struct hostapd_ssid {
u8 ssid[HOSTAPD_MAX_SSID_LEN];
size_t ssid_len;
- int ssid_set;
+ unsigned int ssid_set:1;
+ unsigned int utf8_ssid:1;
char vlan[IFNAMSIZ + 1];
secpolicy security_policy;
@@ -96,6 +97,11 @@
};
#define PMK_LEN 32
+struct hostapd_sta_wpa_psk_short {
+ struct hostapd_sta_wpa_psk_short *next;
+ u8 psk[PMK_LEN];
+};
+
struct hostapd_wpa_psk {
struct hostapd_wpa_psk *next;
int group;
@@ -192,6 +198,7 @@
int eap_server; /* Use internal EAP server instead of external
* RADIUS server */
struct hostapd_eap_user *eap_user;
+ char *eap_user_sqlite;
char *eap_sim_db;
struct hostapd_ip_addr own_ip_addr;
char *nas_identifier;
@@ -333,6 +340,7 @@
int wps_state;
#ifdef CONFIG_WPS
+ int wps_independent;
int ap_setup_locked;
u8 uuid[16];
char *wps_pin_requests;
@@ -358,6 +366,7 @@
char *model_url;
char *upc;
struct wpabuf *wps_vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
+ int wps_nfc_pw_from_config;
int wps_nfc_dev_pw_id;
struct wpabuf *wps_nfc_dh_pubkey;
struct wpabuf *wps_nfc_dh_privkey;
@@ -384,6 +393,8 @@
/* IEEE 802.11v */
int time_advertisement;
char *time_zone;
+ int wnm_sleep_mode;
+ int bss_transition;
/* IEEE 802.11u - Interworking */
int interworking;
@@ -446,6 +457,9 @@
#endif /* CONFIG_RADIUS_TEST */
struct wpabuf *vendor_elements;
+
+ unsigned int sae_anti_clogging_threshold;
+ int *sae_groups;
};
@@ -505,6 +519,7 @@
int require_vht;
u8 vht_oper_chwidth;
u8 vht_oper_centr_freq_seg0_idx;
+ u8 vht_oper_centr_freq_seg1_idx;
};
@@ -523,9 +538,6 @@
int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf);
const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan,
int vlan_id);
-const struct hostapd_eap_user *
-hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity,
- size_t identity_len, int phase2);
struct hostapd_radius_attr *
hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type);
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 02da25b..8205d13 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -173,6 +173,14 @@
}
#endif /* CONFIG_HS20 */
+ if (hapd->conf->vendor_elements) {
+ size_t add = wpabuf_len(hapd->conf->vendor_elements);
+ if (wpabuf_resize(&beacon, add) == 0)
+ wpabuf_put_buf(beacon, hapd->conf->vendor_elements);
+ if (wpabuf_resize(&proberesp, add) == 0)
+ wpabuf_put_buf(proberesp, hapd->conf->vendor_elements);
+ }
+
*beacon_ret = beacon;
*proberesp_ret = proberesp;
*assocresp_ret = assocresp;
@@ -338,6 +346,7 @@
const u8 *supp_rates, size_t supp_rates_len,
u16 listen_interval,
const struct ieee80211_ht_capabilities *ht_capab,
+ const struct ieee80211_vht_capabilities *vht_capab,
u32 flags, u8 qosinfo)
{
struct hostapd_sta_add_params params;
@@ -355,6 +364,7 @@
params.supp_rates_len = supp_rates_len;
params.listen_interval = listen_interval;
params.ht_capabilities = ht_capab;
+ params.vht_capabilities = vht_capab;
params.flags = hostapd_sta_flags_to_drv(flags);
params.qosinfo = qosinfo;
return hapd->driver->sta_add(hapd->drv_priv, ¶ms);
@@ -454,19 +464,76 @@
int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq,
- int channel, int ht_enabled, int sec_channel_offset)
+ int channel, int ht_enabled, int vht_enabled,
+ int sec_channel_offset, int vht_oper_chwidth,
+ int center_segment0, int center_segment1)
{
struct hostapd_freq_params data;
- if (hapd->driver == NULL)
- return 0;
- if (hapd->driver->set_freq == NULL)
- return 0;
+ int tmp;
+
os_memset(&data, 0, sizeof(data));
data.mode = mode;
data.freq = freq;
data.channel = channel;
data.ht_enabled = ht_enabled;
+ data.vht_enabled = vht_enabled;
data.sec_channel_offset = sec_channel_offset;
+ data.center_freq1 = freq + sec_channel_offset * 10;
+ data.center_freq2 = 0;
+ data.bandwidth = sec_channel_offset ? 40 : 20;
+
+ /*
+ * This validation code is probably misplaced, maybe it should be
+ * in src/ap/hw_features.c and check the hardware support as well.
+ */
+ if (data.vht_enabled) switch (vht_oper_chwidth) {
+ case VHT_CHANWIDTH_USE_HT:
+ if (center_segment1)
+ return -1;
+ if (5000 + center_segment0 * 5 != data.center_freq1)
+ return -1;
+ break;
+ case VHT_CHANWIDTH_80P80MHZ:
+ if (center_segment1 == center_segment0 + 4 ||
+ center_segment1 == center_segment0 - 4)
+ return -1;
+ data.center_freq2 = 5000 + center_segment1 * 5;
+ /* fall through */
+ case VHT_CHANWIDTH_80MHZ:
+ data.bandwidth = 80;
+ if (vht_oper_chwidth == 1 && center_segment1)
+ return -1;
+ if (vht_oper_chwidth == 3 && !center_segment1)
+ return -1;
+ if (!sec_channel_offset)
+ return -1;
+ /* primary 40 part must match the HT configuration */
+ tmp = (30 + freq - 5000 - center_segment0 * 5)/20;
+ tmp /= 2;
+ if (data.center_freq1 != 5000 +
+ center_segment0 * 5 - 20 + 40 * tmp)
+ return -1;
+ data.center_freq1 = 5000 + center_segment0 * 5;
+ break;
+ case VHT_CHANWIDTH_160MHZ:
+ data.bandwidth = 160;
+ if (center_segment1)
+ return -1;
+ if (!sec_channel_offset)
+ return -1;
+ /* primary 40 part must match the HT configuration */
+ tmp = (70 + freq - 5000 - center_segment0 * 5)/20;
+ tmp /= 2;
+ if (data.center_freq1 != 5000 +
+ center_segment0 * 5 - 60 + 40 * tmp)
+ return -1;
+ data.center_freq1 = 5000 + center_segment0 * 5;
+ break;
+ }
+ if (hapd->driver == NULL)
+ return 0;
+ if (hapd->driver->set_freq == NULL)
+ return 0;
return hapd->driver->set_freq(hapd->drv_priv, &data);
}
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 9c53b99..ceb7e68 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -13,6 +13,7 @@
struct wpa_bss_params;
struct wpa_driver_scan_params;
struct ieee80211_ht_capabilities;
+struct ieee80211_vht_capabilities;
u32 hostapd_sta_flags_to_drv(u32 flags);
int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
@@ -37,6 +38,7 @@
const u8 *supp_rates, size_t supp_rates_len,
u16 listen_interval,
const struct ieee80211_ht_capabilities *ht_capab,
+ const struct ieee80211_vht_capabilities *vht_capab,
u32 flags, u8 qosinfo);
int hostapd_set_privacy(struct hostapd_data *hapd, int enabled);
int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem,
@@ -55,7 +57,9 @@
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 sec_channel_offset);
+ 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);
int hostapd_set_frag(struct hostapd_data *hapd, int frag);
int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
diff --git a/src/ap/ap_list.c b/src/ap/ap_list.c
index 18090ca..9f02151 100644
--- a/src/ap/ap_list.c
+++ b/src/ap/ap_list.c
@@ -50,7 +50,7 @@
}
-struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *ap)
+static struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *ap)
{
struct ap_info *s;
@@ -87,34 +87,6 @@
}
-static void ap_ap_iter_list_add(struct hostapd_iface *iface,
- struct ap_info *ap)
-{
- if (iface->ap_iter_list) {
- ap->iter_prev = iface->ap_iter_list->iter_prev;
- iface->ap_iter_list->iter_prev = ap;
- } else
- ap->iter_prev = ap;
- ap->iter_next = iface->ap_iter_list;
- iface->ap_iter_list = ap;
-}
-
-
-static void ap_ap_iter_list_del(struct hostapd_iface *iface,
- struct ap_info *ap)
-{
- if (iface->ap_iter_list == ap)
- iface->ap_iter_list = ap->iter_next;
- else
- ap->iter_prev->iter_next = ap->iter_next;
-
- if (ap->iter_next)
- ap->iter_next->iter_prev = ap->iter_prev;
- else if (iface->ap_iter_list)
- iface->ap_iter_list->iter_prev = ap->iter_prev;
-}
-
-
static void ap_ap_hash_add(struct hostapd_iface *iface, struct ap_info *ap)
{
ap->hnext = iface->ap_hash[STA_HASH(ap->addr)];
@@ -148,7 +120,6 @@
{
ap_ap_hash_del(iface, ap);
ap_ap_list_del(iface, ap);
- ap_ap_iter_list_del(iface, ap);
iface->num_ap--;
os_free(ap);
@@ -171,25 +142,6 @@
}
-int ap_ap_for_each(struct hostapd_iface *iface,
- int (*func)(struct ap_info *s, void *data), void *data)
-{
- struct ap_info *s;
- int ret = 0;
-
- s = iface->ap_list;
-
- while (s) {
- ret = func(s, data);
- if (ret)
- break;
- s = s->next;
- }
-
- return ret;
-}
-
-
static struct ap_info * ap_ap_add(struct hostapd_iface *iface, const u8 *addr)
{
struct ap_info *ap;
@@ -203,7 +155,6 @@
ap_ap_list_add(iface, ap);
iface->num_ap++;
ap_ap_hash_add(iface, ap);
- ap_ap_iter_list_add(iface, ap);
if (iface->num_ap > iface->conf->ap_table_max_size && ap != ap->prev) {
wpa_printf(MSG_DEBUG, "Removing the least recently used AP "
@@ -223,7 +174,6 @@
struct ap_info *ap;
struct os_time now;
int new_ap = 0;
- size_t len;
int set_beacon = 0;
if (iface->conf->ap_table_max_size < 1)
@@ -239,24 +189,10 @@
new_ap = 1;
}
- ap->beacon_int = le_to_host16(mgmt->u.beacon.beacon_int);
- ap->capability = le_to_host16(mgmt->u.beacon.capab_info);
-
- if (elems->ssid) {
- len = elems->ssid_len;
- if (len >= sizeof(ap->ssid))
- len = sizeof(ap->ssid) - 1;
- os_memcpy(ap->ssid, elems->ssid, len);
- ap->ssid[len] = '\0';
- ap->ssid_len = len;
- }
-
merge_byte_arrays(ap->supported_rates, WLAN_SUPP_RATES_MAX,
elems->supp_rates, elems->supp_rates_len,
elems->ext_supp_rates, elems->ext_supp_rates_len);
- ap->wpa = elems->wpa_ie != NULL;
-
if (elems->erp_info && elems->erp_info_len == 1)
ap->erp = elems->erp_info[0];
else
@@ -264,6 +200,8 @@
if (elems->ds_params && elems->ds_params_len == 1)
ap->channel = elems->ds_params[0];
+ else if (elems->ht_operation && elems->ht_operation_len >= 1)
+ ap->channel = elems->ht_operation[0];
else if (fi)
ap->channel = fi->channel;
@@ -272,11 +210,8 @@
else
ap->ht_support = 0;
- ap->num_beacons++;
os_get_time(&now);
ap->last_beacon = now.sec;
- if (fi)
- ap->datarate = fi->datarate;
if (!new_ap && ap != iface->ap_list) {
/* move AP entry into the beginning of the list so that the
@@ -288,17 +223,23 @@
if (!iface->olbc &&
ap_list_beacon_olbc(iface, ap)) {
iface->olbc = 1;
- wpa_printf(MSG_DEBUG, "OLBC AP detected: " MACSTR " - enable "
- "protection", MAC2STR(ap->addr));
+ wpa_printf(MSG_DEBUG, "OLBC AP detected: " MACSTR
+ " (channel %d) - enable protection",
+ MAC2STR(ap->addr), ap->channel);
set_beacon++;
}
#ifdef CONFIG_IEEE80211N
- if (!iface->olbc_ht && !ap->ht_support) {
+ if (!iface->olbc_ht && !ap->ht_support &&
+ (ap->channel == 0 ||
+ ap->channel == iface->conf->channel ||
+ ap->channel == iface->conf->channel +
+ iface->conf->secondary_channel * 4)) {
iface->olbc_ht = 1;
hostapd_ht_operation_update(iface);
wpa_printf(MSG_DEBUG, "OLBC HT AP detected: " MACSTR
- " - enable protection", MAC2STR(ap->addr));
+ " (channel %d) - enable protection",
+ MAC2STR(ap->addr), ap->channel);
set_beacon++;
}
#endif /* CONFIG_IEEE80211N */
diff --git a/src/ap/ap_list.h b/src/ap/ap_list.h
index f0b4125..d0529a1 100644
--- a/src/ap/ap_list.h
+++ b/src/ap/ap_list.h
@@ -14,42 +14,24 @@
struct ap_info {
/* Note: next/prev pointers are updated whenever a new beacon is
* received because these are used to find the least recently used
- * entries. iter_next/iter_prev are updated only when adding new BSSes
- * and when removing old ones. These should be used when iterating
- * through the table in a manner that allows beacons to be received
- * during the iteration. */
+ * entries. */
struct ap_info *next; /* next entry in AP list */
struct ap_info *prev; /* previous entry in AP list */
struct ap_info *hnext; /* next entry in hash table list */
- struct ap_info *iter_next; /* next entry in AP iteration list */
- struct ap_info *iter_prev; /* previous entry in AP iteration list */
u8 addr[6];
- u16 beacon_int;
- u16 capability;
u8 supported_rates[WLAN_SUPP_RATES_MAX];
- u8 ssid[33];
- size_t ssid_len;
- int wpa;
int erp; /* ERP Info or -1 if ERP info element not present */
int channel;
- int datarate; /* in 100 kbps */
int ht_support;
- unsigned int num_beacons; /* number of beacon frames received */
os_time_t last_beacon;
-
- int already_seen; /* whether API call AP-NEW has already fetched
- * information about this AP */
};
struct ieee802_11_elems;
struct hostapd_frame_info;
-struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *sta);
-int ap_ap_for_each(struct hostapd_iface *iface,
- int (*func)(struct ap_info *s, void *data), void *data);
void ap_list_process_beacon(struct hostapd_iface *iface,
const struct ieee80211_mgmt *mgmt,
struct ieee802_11_elems *elems,
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index 5c03f45..d66d97e 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -92,7 +92,7 @@
os_memset(&srv, 0, sizeof(srv));
srv.client_file = conf->radius_server_clients;
srv.auth_port = conf->radius_server_auth_port;
- srv.conf_ctx = conf;
+ srv.conf_ctx = hapd;
srv.eap_sim_db_priv = hapd->eap_sim_db_priv;
srv.ssl_ctx = hapd->ssl_ctx;
srv.msg_ctx = hapd->msg_ctx;
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index f761bf5..4c47c75 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -2,7 +2,7 @@
* hostapd / IEEE 802.11 Management: Beacon and Probe Request/Response
* Copyright (c) 2002-2004, Instant802 Networks, Inc.
* Copyright (c) 2005-2006, Devicescape Software, Inc.
- * Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -310,6 +310,46 @@
}
+enum ssid_match_result {
+ NO_SSID_MATCH,
+ EXACT_SSID_MATCH,
+ WILDCARD_SSID_MATCH
+};
+
+static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
+ const u8 *ssid, size_t ssid_len,
+ const u8 *ssid_list,
+ size_t ssid_list_len)
+{
+ const u8 *pos, *end;
+ int wildcard = 0;
+
+ if (ssid_len == 0)
+ wildcard = 1;
+ if (ssid_len == hapd->conf->ssid.ssid_len &&
+ os_memcmp(ssid, hapd->conf->ssid.ssid, ssid_len) == 0)
+ return EXACT_SSID_MATCH;
+
+ if (ssid_list == NULL)
+ return wildcard ? WILDCARD_SSID_MATCH : NO_SSID_MATCH;
+
+ pos = ssid_list;
+ end = ssid_list + ssid_list_len;
+ while (pos + 1 <= end) {
+ if (pos + 2 + pos[1] > end)
+ break;
+ if (pos[1] == 0)
+ wildcard = 1;
+ if (pos[1] == hapd->conf->ssid.ssid_len &&
+ os_memcmp(pos + 2, hapd->conf->ssid.ssid, pos[1]) == 0)
+ return EXACT_SSID_MATCH;
+ pos += 2 + pos[1];
+ }
+
+ return wildcard ? WILDCARD_SSID_MATCH : NO_SSID_MATCH;
+}
+
+
void handle_probe_req(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len,
int ssi_signal)
@@ -321,6 +361,7 @@
struct sta_info *sta = NULL;
size_t i, resp_len;
int noack;
+ enum ssid_match_result res;
ie = mgmt->u.probe_req.variable;
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
@@ -376,7 +417,8 @@
}
#endif /* CONFIG_P2P */
- if (hapd->conf->ignore_broadcast_ssid && elems.ssid_len == 0) {
+ if (hapd->conf->ignore_broadcast_ssid && elems.ssid_len == 0 &&
+ elems.ssid_list_len == 0) {
wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for "
"broadcast SSID ignored", MAC2STR(mgmt->sa));
return;
@@ -394,10 +436,9 @@
}
#endif /* CONFIG_P2P */
- if (elems.ssid_len == 0 ||
- (elems.ssid_len == hapd->conf->ssid.ssid_len &&
- os_memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) ==
- 0)) {
+ res = ssid_match(hapd, elems.ssid, elems.ssid_len,
+ elems.ssid_list, elems.ssid_list_len);
+ if (res != NO_SSID_MATCH) {
if (sta)
sta->ssid_probe = &hapd->conf->ssid;
} else {
@@ -406,9 +447,10 @@
ieee802_11_print_ssid(ssid_txt, elems.ssid,
elems.ssid_len);
wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
- " for foreign SSID '%s' (DA " MACSTR ")",
+ " for foreign SSID '%s' (DA " MACSTR ")%s",
MAC2STR(mgmt->sa), ssid_txt,
- MAC2STR(mgmt->da));
+ MAC2STR(mgmt->da),
+ elems.ssid_list ? " (SSID list)" : "");
}
return;
}
@@ -455,7 +497,8 @@
* If this is a broadcast probe request, apply no ack policy to avoid
* excessive retries.
*/
- noack = !!(elems.ssid_len == 0 && is_broadcast_ether_addr(mgmt->da));
+ noack = !!(res == WILDCARD_SSID_MATCH &&
+ is_broadcast_ether_addr(mgmt->da));
if (hostapd_drv_send_mlme(hapd, resp, resp_len, noack) < 0)
perror("handle_probe_req: send");
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index ab9c83e..1cb7e73 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -21,6 +21,28 @@
#include "ap_drv_ops.h"
+static int hostapd_get_sta_conn_time(struct sta_info *sta,
+ char *buf, size_t buflen)
+{
+ struct os_time now, age;
+ int len = 0, ret;
+
+ if (!sta->connected_time.sec)
+ return 0;
+
+ os_get_time(&now);
+ os_time_sub(&now, &sta->connected_time, &age);
+
+ ret = os_snprintf(buf + len, buflen - len, "connected_time=%u\n",
+ (unsigned int) age.sec);
+ if (ret < 0 || (size_t) ret >= buflen - len)
+ return len;
+ len += ret;
+
+ return len;
+}
+
+
static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
struct sta_info *sta,
char *buf, size_t buflen)
@@ -58,6 +80,10 @@
if (res >= 0)
len += res;
+ res = hostapd_get_sta_conn_time(sta, buf + len, buflen - len);
+ if (res >= 0)
+ len += res;
+
return len;
}
@@ -163,6 +189,7 @@
u8 addr[ETH_ALEN];
struct sta_info *sta;
const char *pos;
+ u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s",
txtaddr);
@@ -202,11 +229,14 @@
}
#endif /* CONFIG_P2P_MANAGER */
- hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
+ pos = os_strstr(txtaddr, " reason=");
+ if (pos)
+ reason = atoi(pos + 8);
+
+ hostapd_drv_sta_deauth(hapd, addr, reason);
sta = ap_get_sta(hapd, addr);
if (sta)
- ap_sta_deauthenticate(hapd, sta,
- WLAN_REASON_PREV_AUTH_NOT_VALID);
+ ap_sta_deauthenticate(hapd, sta, reason);
else if (addr[0] == 0xff)
hostapd_free_stas(hapd);
@@ -220,6 +250,7 @@
u8 addr[ETH_ALEN];
struct sta_info *sta;
const char *pos;
+ u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s",
txtaddr);
@@ -259,11 +290,14 @@
}
#endif /* CONFIG_P2P_MANAGER */
- hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
+ pos = os_strstr(txtaddr, " reason=");
+ if (pos)
+ reason = atoi(pos + 8);
+
+ hostapd_drv_sta_disassoc(hapd, addr, reason);
sta = ap_get_sta(hapd, addr);
if (sta)
- ap_sta_disassociate(hapd, sta,
- WLAN_REASON_PREV_AUTH_NOT_VALID);
+ ap_sta_disassociate(hapd, sta, reason);
else if (addr[0] == 0xff)
hostapd_free_stas(hapd);
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 23fa241..6d22d49 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -13,6 +13,7 @@
#include "drivers/driver.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
+#include "common/wpa_ctrl.h"
#include "crypto/random.h"
#include "p2p/p2p.h"
#include "wps/wps.h"
@@ -109,6 +110,15 @@
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_HS20
+ wpabuf_free(sta->hs20_ie);
+ if (elems.hs20 && elems.hs20_len > 4) {
+ sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4,
+ elems.hs20_len - 4);
+ } else
+ sta->hs20_ie = NULL;
+#endif /* CONFIG_HS20 */
+
if (hapd->conf->wpa) {
if (ie == NULL || ielen == 0) {
#ifdef CONFIG_WPS
@@ -384,6 +394,22 @@
}
+void hostapd_event_connect_failed_reason(struct hostapd_data *hapd,
+ const u8 *addr, int reason_code)
+{
+ switch (reason_code) {
+ case MAX_CLIENT_REACHED:
+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_REJECTED_MAX_STA MACSTR,
+ MAC2STR(addr));
+ break;
+ case BLOCKED_CLIENT:
+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_REJECTED_BLOCKED_STA MACSTR,
+ MAC2STR(addr));
+ break;
+ }
+}
+
+
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)
@@ -503,13 +529,13 @@
action->data + 2);
}
#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_IEEE80211V
+#ifdef CONFIG_WNM
if (action->category == WLAN_ACTION_WNM) {
wpa_printf(MSG_DEBUG, "%s: WNM_ACTION length %d",
__func__, (int) action->len);
ieee802_11_rx_wnm_action_ap(hapd, action);
}
-#endif /* CONFIG_IEEE80211V */
+#endif /* CONFIG_WNM */
}
@@ -672,12 +698,15 @@
const u8 *data, size_t data_len)
{
struct hostapd_iface *iface = hapd->iface;
+ struct sta_info *sta;
size_t j;
for (j = 0; j < iface->num_bss; j++) {
- if (ap_get_sta(iface->bss[j], src)) {
- hapd = iface->bss[j];
- break;
+ if ((sta = ap_get_sta(iface->bss[j], src))) {
+ if (sta->flags & WLAN_STA_ASSOC) {
+ hapd = iface->bss[j];
+ break;
+ }
}
}
@@ -816,6 +845,13 @@
data->ch_switch.ht_enabled,
data->ch_switch.ch_offset);
break;
+ case EVENT_CONNECT_FAILED_REASON:
+ if (!data)
+ break;
+ hostapd_event_connect_failed_reason(
+ hapd, data->connect_failed_reason.addr,
+ data->connect_failed_reason.code);
+ break;
default:
wpa_printf(MSG_DEBUG, "Unknown event %d", event);
break;
diff --git a/src/ap/eap_user_db.c b/src/ap/eap_user_db.c
new file mode 100644
index 0000000..79d50e5
--- /dev/null
+++ b/src/ap/eap_user_db.c
@@ -0,0 +1,270 @@
+/*
+ * hostapd / EAP user database
+ * Copyright (c) 2012, 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"
+#ifdef CONFIG_SQLITE
+#include <sqlite3.h>
+#endif /* CONFIG_SQLITE */
+
+#include "common.h"
+#include "eap_common/eap_wsc_common.h"
+#include "eap_server/eap_methods.h"
+#include "eap_server/eap.h"
+#include "ap_config.h"
+#include "hostapd.h"
+
+#ifdef CONFIG_SQLITE
+
+static void set_user_methods(struct hostapd_eap_user *user, const char *methods)
+{
+ char *buf, *start;
+ int num_methods;
+
+ buf = os_strdup(methods);
+ if (buf == NULL)
+ return;
+
+ os_memset(&user->methods, 0, sizeof(user->methods));
+ num_methods = 0;
+ start = buf;
+ while (*start) {
+ char *pos3 = os_strchr(start, ',');
+ if (pos3)
+ *pos3++ = '\0';
+ user->methods[num_methods].method =
+ eap_server_get_type(start,
+ &user->methods[num_methods].vendor);
+ if (user->methods[num_methods].vendor == EAP_VENDOR_IETF &&
+ user->methods[num_methods].method == EAP_TYPE_NONE) {
+ if (os_strcmp(start, "TTLS-PAP") == 0) {
+ user->ttls_auth |= EAP_TTLS_AUTH_PAP;
+ goto skip_eap;
+ }
+ if (os_strcmp(start, "TTLS-CHAP") == 0) {
+ user->ttls_auth |= EAP_TTLS_AUTH_CHAP;
+ goto skip_eap;
+ }
+ if (os_strcmp(start, "TTLS-MSCHAP") == 0) {
+ user->ttls_auth |= EAP_TTLS_AUTH_MSCHAP;
+ goto skip_eap;
+ }
+ if (os_strcmp(start, "TTLS-MSCHAPV2") == 0) {
+ user->ttls_auth |= EAP_TTLS_AUTH_MSCHAPV2;
+ goto skip_eap;
+ }
+ wpa_printf(MSG_INFO, "DB: Unsupported EAP type '%s'",
+ start);
+ os_free(buf);
+ return;
+ }
+
+ num_methods++;
+ if (num_methods >= EAP_MAX_METHODS)
+ break;
+ skip_eap:
+ if (pos3 == NULL)
+ break;
+ start = pos3;
+ }
+
+ os_free(buf);
+}
+
+
+static int get_user_cb(void *ctx, int argc, char *argv[], char *col[])
+{
+ struct hostapd_eap_user *user = ctx;
+ int i;
+
+ for (i = 0; i < argc; i++) {
+ if (os_strcmp(col[i], "password") == 0 && argv[i]) {
+ os_free(user->password);
+ user->password_len = os_strlen(argv[i]);
+ user->password = (u8 *) os_strdup(argv[i]);
+ user->next = (void *) 1;
+ } else if (os_strcmp(col[i], "methods") == 0 && argv[i]) {
+ set_user_methods(user, argv[i]);
+ }
+ }
+
+ return 0;
+}
+
+
+static int get_wildcard_cb(void *ctx, int argc, char *argv[], char *col[])
+{
+ struct hostapd_eap_user *user = ctx;
+ int i, id = -1, methods = -1;
+ size_t len;
+
+ for (i = 0; i < argc; i++) {
+ if (os_strcmp(col[i], "identity") == 0 && argv[i])
+ id = i;
+ else if (os_strcmp(col[i], "methods") == 0 && argv[i])
+ methods = i;
+ }
+
+ if (id < 0 || methods < 0)
+ return 0;
+
+ len = os_strlen(argv[id]);
+ if (len <= user->identity_len &&
+ os_memcmp(argv[id], user->identity, len) == 0 &&
+ (user->password == NULL || len > user->password_len)) {
+ os_free(user->password);
+ user->password_len = os_strlen(argv[id]);
+ user->password = (u8 *) os_strdup(argv[id]);
+ user->next = (void *) 1;
+ set_user_methods(user, argv[methods]);
+ }
+
+ return 0;
+}
+
+
+static const struct hostapd_eap_user *
+eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity,
+ size_t identity_len, int phase2)
+{
+ sqlite3 *db;
+ struct hostapd_eap_user *user = NULL;
+ char id_str[256], cmd[300];
+ size_t i;
+
+ if (identity_len >= sizeof(id_str))
+ return NULL;
+ os_memcpy(id_str, identity, identity_len);
+ id_str[identity_len] = '\0';
+ for (i = 0; i < identity_len; i++) {
+ if (id_str[i] >= 'a' && id_str[i] <= 'z')
+ continue;
+ if (id_str[i] >= 'A' && id_str[i] <= 'Z')
+ continue;
+ if (id_str[i] >= '0' && id_str[i] <= '9')
+ continue;
+ if (id_str[i] == '-' || id_str[i] == '_' || id_str[i] == '.' ||
+ id_str[i] == ',' || id_str[i] == '@' || id_str[i] == '\\' ||
+ id_str[i] == '!' || id_str[i] == '#' || id_str[i] == '%' ||
+ id_str[i] == '=' || id_str[i] == ' ')
+ continue;
+ wpa_printf(MSG_INFO, "DB: Unsupported character in identity");
+ return NULL;
+ }
+
+ os_free(hapd->tmp_eap_user.identity);
+ os_free(hapd->tmp_eap_user.password);
+ os_memset(&hapd->tmp_eap_user, 0, sizeof(hapd->tmp_eap_user));
+ hapd->tmp_eap_user.phase2 = phase2;
+ hapd->tmp_eap_user.identity = os_zalloc(identity_len + 1);
+ if (hapd->tmp_eap_user.identity == NULL)
+ return NULL;
+ os_memcpy(hapd->tmp_eap_user.identity, identity, identity_len);
+
+ if (sqlite3_open(hapd->conf->eap_user_sqlite, &db)) {
+ wpa_printf(MSG_INFO, "DB: Failed to open database %s: %s",
+ hapd->conf->eap_user_sqlite, sqlite3_errmsg(db));
+ sqlite3_close(db);
+ return NULL;
+ }
+
+ os_snprintf(cmd, sizeof(cmd),
+ "SELECT password,methods FROM users WHERE "
+ "identity='%s' AND phase2=%d;", id_str, phase2);
+ wpa_printf(MSG_DEBUG, "DB: %s", cmd);
+ if (sqlite3_exec(db, cmd, get_user_cb, &hapd->tmp_eap_user, NULL) !=
+ SQLITE_OK) {
+ wpa_printf(MSG_DEBUG, "DB: Failed to complete SQL operation");
+ } else if (hapd->tmp_eap_user.next)
+ user = &hapd->tmp_eap_user;
+
+ if (user == NULL && !phase2) {
+ os_snprintf(cmd, sizeof(cmd),
+ "SELECT identity,methods FROM wildcards;");
+ wpa_printf(MSG_DEBUG, "DB: %s", cmd);
+ if (sqlite3_exec(db, cmd, get_wildcard_cb, &hapd->tmp_eap_user,
+ NULL) != SQLITE_OK) {
+ wpa_printf(MSG_DEBUG, "DB: Failed to complete SQL "
+ "operation");
+ } else if (hapd->tmp_eap_user.next) {
+ user = &hapd->tmp_eap_user;
+ os_free(user->identity);
+ user->identity = user->password;
+ user->identity_len = user->password_len;
+ user->password = NULL;
+ user->password_len = 0;
+ }
+ }
+
+ sqlite3_close(db);
+
+ return user;
+}
+
+#endif /* CONFIG_SQLITE */
+
+
+const struct hostapd_eap_user *
+hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
+ size_t identity_len, int phase2)
+{
+ const struct hostapd_bss_config *conf = hapd->conf;
+ struct hostapd_eap_user *user = conf->eap_user;
+
+#ifdef CONFIG_WPS
+ if (conf->wps_state && identity_len == WSC_ID_ENROLLEE_LEN &&
+ os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0) {
+ static struct hostapd_eap_user wsc_enrollee;
+ os_memset(&wsc_enrollee, 0, sizeof(wsc_enrollee));
+ wsc_enrollee.methods[0].method = eap_server_get_type(
+ "WSC", &wsc_enrollee.methods[0].vendor);
+ return &wsc_enrollee;
+ }
+
+ if (conf->wps_state && identity_len == WSC_ID_REGISTRAR_LEN &&
+ os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0) {
+ static struct hostapd_eap_user wsc_registrar;
+ os_memset(&wsc_registrar, 0, sizeof(wsc_registrar));
+ wsc_registrar.methods[0].method = eap_server_get_type(
+ "WSC", &wsc_registrar.methods[0].vendor);
+ wsc_registrar.password = (u8 *) conf->ap_pin;
+ wsc_registrar.password_len = conf->ap_pin ?
+ os_strlen(conf->ap_pin) : 0;
+ return &wsc_registrar;
+ }
+#endif /* CONFIG_WPS */
+
+ while (user) {
+ if (!phase2 && user->identity == NULL) {
+ /* Wildcard match */
+ break;
+ }
+
+ if (user->phase2 == !!phase2 && user->wildcard_prefix &&
+ identity_len >= user->identity_len &&
+ os_memcmp(user->identity, identity, user->identity_len) ==
+ 0) {
+ /* Wildcard prefix match */
+ break;
+ }
+
+ if (user->phase2 == !!phase2 &&
+ user->identity_len == identity_len &&
+ os_memcmp(user->identity, identity, identity_len) == 0)
+ break;
+ user = user->next;
+ }
+
+#ifdef CONFIG_SQLITE
+ if (user == NULL && conf->eap_user_sqlite) {
+ return eap_user_sqlite_get(hapd, identity, identity_len,
+ phase2);
+ }
+#endif /* CONFIG_SQLITE */
+
+ return user;
+}
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
index 851c183..b3574ba 100644
--- a/src/ap/gas_serv.c
+++ b/src/ap/gas_serv.c
@@ -1158,8 +1158,8 @@
int gas_serv_init(struct hostapd_data *hapd)
{
- hapd->public_action_cb = gas_serv_rx_public_action;
- hapd->public_action_cb_ctx = hapd;
+ hapd->public_action_cb2 = gas_serv_rx_public_action;
+ hapd->public_action_cb2_ctx = hapd;
hapd->gas_frag_limit = 1400;
if (hapd->conf->gas_frag_limit > 0)
hapd->gas_frag_limit = hapd->conf->gas_frag_limit;
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 3429258..a0ac38c 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -108,19 +108,10 @@
}
-int hostapd_reload_config(struct hostapd_iface *iface)
+static void hostapd_clear_old(struct hostapd_iface *iface)
{
- struct hostapd_data *hapd = iface->bss[0];
- struct hostapd_config *newconf, *oldconf;
size_t j;
- if (iface->interfaces == NULL ||
- iface->interfaces->config_read_cb == NULL)
- return -1;
- newconf = iface->interfaces->config_read_cb(iface->config_fname);
- if (newconf == NULL)
- return -1;
-
/*
* Deauthenticate all stations since the new configuration may not
* allow them to use the BSS anymore.
@@ -136,6 +127,31 @@
radius_client_flush(iface->bss[j]->radius, 0);
#endif /* CONFIG_NO_RADIUS */
}
+}
+
+
+int hostapd_reload_config(struct hostapd_iface *iface)
+{
+ struct hostapd_data *hapd = iface->bss[0];
+ struct hostapd_config *newconf, *oldconf;
+ size_t j;
+
+ if (iface->config_fname == NULL) {
+ /* Only in-memory config in use - assume it has been updated */
+ hostapd_clear_old(iface);
+ for (j = 0; j < iface->num_bss; j++)
+ hostapd_reload_bss(iface->bss[j]);
+ return 0;
+ }
+
+ if (iface->interfaces == NULL ||
+ iface->interfaces->config_read_cb == NULL)
+ return -1;
+ newconf = iface->interfaces->config_read_cb(iface->config_fname);
+ if (newconf == NULL)
+ return -1;
+
+ hostapd_clear_old(iface);
oldconf = hapd->iconf;
iface->conf = newconf;
@@ -273,6 +289,11 @@
#ifdef CONFIG_INTERWORKING
gas_serv_deinit(hapd);
#endif /* CONFIG_INTERWORKING */
+
+#ifdef CONFIG_SQLITE
+ os_free(hapd->tmp_eap_user.identity);
+ os_free(hapd->tmp_eap_user.password);
+#endif /* CONFIG_SQLITE */
}
@@ -889,7 +910,11 @@
if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
hapd->iconf->channel,
hapd->iconf->ieee80211n,
- hapd->iconf->secondary_channel)) {
+ hapd->iconf->ieee80211ac,
+ hapd->iconf->secondary_channel,
+ hapd->iconf->vht_oper_chwidth,
+ hapd->iconf->vht_oper_centr_freq_seg0_idx,
+ hapd->iconf->vht_oper_centr_freq_seg1_idx)) {
wpa_printf(MSG_ERROR, "Could not set channel for "
"kernel driver");
return -1;
@@ -1113,12 +1138,13 @@
int hostapd_disable_iface(struct hostapd_iface *hapd_iface)
{
size_t j;
- struct hostapd_bss_config *bss = hapd_iface->bss[0]->conf;
+ struct hostapd_bss_config *bss;
const struct wpa_driver_ops *driver;
void *drv_priv;
if (hapd_iface == NULL)
return -1;
+ bss = hapd_iface->bss[0]->conf;
driver = hapd_iface->bss[0]->driver;
drv_priv = hapd_iface->bss[0]->drv_priv;
@@ -1373,8 +1399,10 @@
/* Start accounting here, if IEEE 802.1X and WPA are not used.
* IEEE 802.1X/WPA code will start accounting after the station has
* been authorized. */
- if (!hapd->conf->ieee802_1x && !hapd->conf->wpa)
+ if (!hapd->conf->ieee802_1x && !hapd->conf->wpa) {
+ os_get_time(&sta->connected_time);
accounting_sta_start(hapd, sta);
+ }
/* Start IEEE 802.1X authentication process for new stations */
ieee802_1x_new_station(hapd, sta);
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 71f476c..9a3bb68 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -10,6 +10,7 @@
#define HOSTAPD_H
#include "common/defs.h"
+#include "ap_config.h"
struct wpa_driver_ops;
struct wpa_ctrl_dst;
@@ -39,6 +40,7 @@
int global_ctrl_sock;
char *global_iface_path;
char *global_iface_name;
+ gid_t ctrl_iface_group;
struct hostapd_iface **iface;
};
@@ -150,6 +152,9 @@
void (*public_action_cb)(void *ctx, const u8 *buf, size_t len,
int freq);
void *public_action_cb_ctx;
+ void (*public_action_cb2)(void *ctx, const u8 *buf, size_t len,
+ int freq);
+ void *public_action_cb2_ctx;
int (*vendor_action_cb)(void *ctx, const u8 *buf, size_t len,
int freq);
@@ -187,6 +192,16 @@
#ifdef CONFIG_INTERWORKING
size_t gas_frag_limit;
#endif /* CONFIG_INTERWORKING */
+
+#ifdef CONFIG_SQLITE
+ struct hostapd_eap_user tmp_eap_user;
+#endif /* CONFIG_SQLITE */
+
+#ifdef CONFIG_SAE
+ /** Key used for generating SAE anti-clogging tokens */
+ u8 sae_token_key[8];
+ os_time_t last_sae_token_key_update;
+#endif /* CONFIG_SAE */
};
@@ -205,7 +220,6 @@
int num_ap; /* number of entries in ap_list */
struct ap_info *ap_list; /* AP info list head */
struct ap_info *ap_hash[STA_HASH_SIZE];
- struct ap_info *ap_iter_list;
unsigned int drv_flags;
@@ -215,6 +229,10 @@
*/
unsigned int probe_resp_offloads;
+ /* extended capabilities supported by the driver */
+ const u8 *extended_capa, *extended_capa_mask;
+ unsigned int extended_capa_len;
+
struct hostapd_hw_modes *hw_features;
int num_hw_features;
struct hostapd_hw_modes *current_mode;
@@ -291,10 +309,16 @@
const u8 *ie, size_t ielen, int reassoc);
void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr);
void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr);
+void hostapd_event_connect_failed_reason(struct hostapd_data *hapd,
+ const u8 *addr, int reason_code);
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);
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
int offset);
+const struct hostapd_eap_user *
+hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
+ size_t identity_len, int phase2);
+
#endif /* HOSTAPD_H */
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 97e1238..37112bd 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -122,6 +122,8 @@
case HOSTAPD_MODE_IEEE80211G:
basic_rates = basic_rates_g;
break;
+ case HOSTAPD_MODE_IEEE80211AD:
+ return 0; /* No basic rates for 11ad */
default:
return -1;
}
@@ -441,7 +443,6 @@
iface->conf->channel +
iface->conf->secondary_channel * 4);
iface->conf->secondary_channel = 0;
- iface->conf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
}
res = ieee80211n_allowed_ht40_channel_pair(iface);
@@ -756,6 +757,8 @@
return "IEEE 802.11b";
case HOSTAPD_MODE_IEEE80211G:
return "IEEE 802.11g";
+ case HOSTAPD_MODE_IEEE80211AD:
+ return "IEEE 802.11ad";
default:
return "UNKNOWN";
}
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index ce20e5f..8baa15e 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -13,10 +13,13 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "crypto/crypto.h"
+#include "crypto/sha256.h"
+#include "crypto/random.h"
#include "drivers/driver.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
+#include "common/sae.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "p2p/p2p.h"
@@ -34,6 +37,7 @@
#include "ap_mlme.h"
#include "p2p_hostapd.h"
#include "ap_drv_ops.h"
+#include "wnm_ap.h"
#include "ieee802_11.h"
@@ -49,6 +53,8 @@
num = hapd->iface->num_rates;
if (hapd->iconf->ieee80211n && hapd->iconf->require_ht)
num++;
+ if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
+ num++;
if (num > 8) {
/* rest of the rates are encoded in Extended supported
* rates element */
@@ -66,9 +72,15 @@
pos++;
}
- if (hapd->iconf->ieee80211n && hapd->iconf->require_ht &&
- hapd->iface->num_rates < 8)
+ if (hapd->iconf->ieee80211n && hapd->iconf->require_ht && count < 8) {
+ count++;
*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY;
+ }
+
+ if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht && count < 8) {
+ count++;
+ *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
+ }
return pos;
}
@@ -85,6 +97,8 @@
num = hapd->iface->num_rates;
if (hapd->iconf->ieee80211n && hapd->iconf->require_ht)
num++;
+ if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
+ num++;
if (num <= 8)
return eid;
num -= 8;
@@ -103,9 +117,17 @@
pos++;
}
- if (hapd->iconf->ieee80211n && hapd->iconf->require_ht &&
- hapd->iface->num_rates >= 8)
- *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY;
+ if (hapd->iconf->ieee80211n && hapd->iconf->require_ht) {
+ count++;
+ if (count > 8)
+ *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY;
+ }
+
+ if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht) {
+ count++;
+ if (count > 8)
+ *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
+ }
return pos;
}
@@ -296,6 +318,222 @@
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SAE
+
+static struct wpabuf * auth_process_sae_commit(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ struct wpabuf *buf;
+
+ if (hapd->conf->ssid.wpa_passphrase == NULL) {
+ wpa_printf(MSG_DEBUG, "SAE: No password available");
+ return NULL;
+ }
+
+ if (sae_prepare_commit(hapd->own_addr, sta->addr,
+ (u8 *) hapd->conf->ssid.wpa_passphrase,
+ os_strlen(hapd->conf->ssid.wpa_passphrase),
+ sta->sae) < 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
+ 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);
+
+ return buf;
+}
+
+
+static struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ struct wpabuf *buf;
+
+ buf = wpabuf_alloc(SAE_CONFIRM_MAX_LEN);
+ if (buf == NULL)
+ return NULL;
+
+ sae_write_confirm(sta->sae, buf);
+
+ return buf;
+}
+
+
+static int use_sae_anti_clogging(struct hostapd_data *hapd)
+{
+ struct sta_info *sta;
+ unsigned int open = 0;
+
+ if (hapd->conf->sae_anti_clogging_threshold == 0)
+ return 1;
+
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (!sta->sae)
+ continue;
+ if (sta->sae->state != SAE_COMMITTED &&
+ sta->sae->state != SAE_CONFIRMED)
+ continue;
+ open++;
+ if (open >= hapd->conf->sae_anti_clogging_threshold)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int check_sae_token(struct hostapd_data *hapd, const u8 *addr,
+ const u8 *token, size_t token_len)
+{
+ u8 mac[SHA256_MAC_LEN];
+
+ if (token_len != SHA256_MAC_LEN)
+ return -1;
+ if (hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
+ addr, ETH_ALEN, mac) < 0 ||
+ os_memcmp(token, mac, SHA256_MAC_LEN) != 0)
+ return -1;
+
+ return 0;
+}
+
+
+static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
+ const u8 *addr)
+{
+ struct wpabuf *buf;
+ u8 *token;
+ struct os_time t;
+
+ os_get_time(&t);
+ if (hapd->last_sae_token_key_update == 0 ||
+ t.sec > hapd->last_sae_token_key_update + 60) {
+ if (random_get_bytes(hapd->sae_token_key,
+ sizeof(hapd->sae_token_key)) < 0)
+ return NULL;
+ wpa_hexdump(MSG_DEBUG, "SAE: Updated token key",
+ hapd->sae_token_key, sizeof(hapd->sae_token_key));
+ hapd->last_sae_token_key_update = t.sec;
+ }
+
+ buf = wpabuf_alloc(SHA256_MAC_LEN);
+ if (buf == NULL)
+ return NULL;
+
+ token = wpabuf_put(buf, SHA256_MAC_LEN);
+ hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
+ addr, ETH_ALEN, token);
+
+ return buf;
+}
+
+
+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 resp = WLAN_STATUS_SUCCESS;
+ struct wpabuf *data = NULL;
+
+ if (!sta->sae) {
+ if (auth_transaction != 1)
+ return;
+ sta->sae = os_zalloc(sizeof(*sta->sae));
+ if (sta->sae == NULL)
+ return;
+ sta->sae->state = SAE_NOTHING;
+ }
+
+ if (auth_transaction == 1) {
+ const u8 *token = NULL;
+ size_t token_len = 0;
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "start SAE authentication (RX commit)");
+ resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable,
+ ((const u8 *) mgmt) + len -
+ mgmt->u.auth.variable, &token,
+ &token_len, hapd->conf->sae_groups);
+ if (token && check_sae_token(hapd, sta->addr, token, token_len)
+ < 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Drop commit message with "
+ "incorrect token from " MACSTR,
+ MAC2STR(sta->addr));
+ 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;
+ }
+ }
+ } 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;
+ }
+ 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)
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ else {
+ sta->sae->state = SAE_ACCEPTED;
+ sae_clear_temp_data(sta->sae);
+ }
+ }
+ } else {
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "unexpected SAE authentication transaction %u",
+ auth_transaction);
+ resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
+ }
+
+ 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);
+ wpabuf_free(data);
+}
+#endif /* CONFIG_SAE */
+
+
static void handle_auth(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len)
{
@@ -307,8 +545,7 @@
const u8 *challenge = NULL;
u32 session_timeout, acct_interim_interval;
int vlan_id = 0;
- u8 psk[PMK_LEN];
- int has_psk = 0;
+ struct hostapd_sta_wpa_psk_short *psk = NULL;
u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
size_t resp_ies_len = 0;
char *identity = NULL;
@@ -348,6 +585,10 @@
(hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) &&
auth_alg == WLAN_AUTH_FT) ||
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SAE
+ (hapd->conf->wpa && wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
+ auth_alg == WLAN_AUTH_SAE) ||
+#endif /* CONFIG_SAE */
((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
auth_alg == WLAN_AUTH_SHARED_KEY))) {
printf("Unsupported authentication algorithm (%d)\n",
@@ -356,7 +597,7 @@
goto fail;
}
- if (!(auth_transaction == 1 ||
+ if (!(auth_transaction == 1 || auth_alg == WLAN_AUTH_SAE ||
(auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) {
printf("Unknown authentication transaction number (%d)\n",
auth_transaction);
@@ -374,7 +615,7 @@
res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len,
&session_timeout,
&acct_interim_interval, &vlan_id,
- psk, &has_psk, &identity, &radius_cui);
+ &psk, &identity, &radius_cui);
if (res == HOSTAPD_ACL_REJECT) {
printf("Station " MACSTR " not allowed to authenticate.\n",
@@ -413,13 +654,11 @@
HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
}
- if (has_psk && hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
- os_free(sta->psk);
- sta->psk = os_malloc(PMK_LEN);
- if (sta->psk)
- os_memcpy(sta->psk, psk, PMK_LEN);
+ hostapd_free_psk_list(sta->psk);
+ if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
+ sta->psk = psk;
+ psk = NULL;
} else {
- os_free(sta->psk);
sta->psk = NULL;
}
@@ -486,11 +725,17 @@
/* handle_auth_ft_finish() callback will complete auth. */
return;
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SAE
+ case WLAN_AUTH_SAE:
+ handle_auth_sae(hapd, sta, mgmt, len, auth_transaction);
+ return;
+#endif /* CONFIG_SAE */
}
fail:
os_free(identity);
os_free(radius_cui);
+ hostapd_free_psk_list(psk);
send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg,
auth_transaction + 1, resp, resp_ies, resp_ies_len);
@@ -779,6 +1024,16 @@
}
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SAE
+ if (wpa_auth_uses_sae(sta->wpa_sm) &&
+ sta->auth_alg != WLAN_AUTH_SAE) {
+ wpa_printf(MSG_DEBUG, "SAE: " MACSTR " tried to use "
+ "SAE AKM after non-SAE auth_alg %u",
+ MAC2STR(sta->addr), sta->auth_alg);
+ return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
+ }
+#endif /* CONFIG_SAE */
+
#ifdef CONFIG_IEEE80211N
if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) &&
wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) {
@@ -807,6 +1062,15 @@
p2p_group_notif_assoc(hapd->p2p_group, sta->addr, ies, ies_len);
#endif /* CONFIG_P2P */
+#ifdef CONFIG_HS20
+ wpabuf_free(sta->hs20_ie);
+ if (elems.hs20 && elems.hs20_len > 4) {
+ sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4,
+ elems.hs20_len - 4);
+ } else
+ sta->hs20_ie = NULL;
+#endif /* CONFIG_HS20 */
+
return WLAN_STATUS_SUCCESS;
}
@@ -1254,13 +1518,32 @@
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_WNM
+static void hostapd_wnm_action(struct hostapd_data *hapd, struct sta_info *sta,
+ const struct ieee80211_mgmt *mgmt,
+ size_t len)
+{
+ struct rx_action action;
+ if (len < IEEE80211_HDRLEN + 2)
+ return;
+ os_memset(&action, 0, sizeof(action));
+ action.da = mgmt->da;
+ action.sa = mgmt->sa;
+ action.bssid = mgmt->bssid;
+ action.category = mgmt->u.action.category;
+ action.data = (const u8 *) &mgmt->u.action.u.wnm_sleep_req.action;
+ action.len = len - IEEE80211_HDRLEN - 1;
+ action.freq = hapd->iface->freq;
+ ieee802_11_rx_wnm_action_ap(hapd, &action);
+}
+#endif /* CONFIG_WNM */
+
+
static void handle_action(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len)
{
-#if defined(CONFIG_IEEE80211W) || defined(CONFIG_IEEE80211R)
struct sta_info *sta;
sta = ap_get_sta(hapd, mgmt->sa);
-#endif /* CONFIG_IEEE80211W || CONFIG_IEEE80211R */
if (len < IEEE80211_HDRLEN + 1) {
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
@@ -1270,6 +1553,14 @@
return;
}
+ if (mgmt->u.action.category != WLAN_ACTION_PUBLIC &&
+ (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) {
+ wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored Action "
+ "frame (category=%u) from unassociated STA " MACSTR,
+ MAC2STR(mgmt->sa), mgmt->u.action.category);
+ return;
+ }
+
#ifdef CONFIG_IEEE80211W
if (sta && (sta->flags & WLAN_STA_MFP) &&
!(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP) &&
@@ -1285,20 +1576,10 @@
switch (mgmt->u.action.category) {
#ifdef CONFIG_IEEE80211R
case WLAN_ACTION_FT:
- {
- if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
- wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored FT Action "
- "frame from unassociated STA " MACSTR,
- MAC2STR(mgmt->sa));
- return;
- }
-
if (wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action,
len - IEEE80211_HDRLEN))
break;
-
return;
- }
#endif /* CONFIG_IEEE80211R */
case WLAN_ACTION_WMM:
hostapd_wmm_action(hapd, mgmt, len);
@@ -1308,13 +1589,24 @@
hostapd_sa_query_action(hapd, mgmt, len);
return;
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_WNM
+ case WLAN_ACTION_WNM:
+ hostapd_wnm_action(hapd, sta, mgmt, len);
+ return;
+#endif /* CONFIG_WNM */
case WLAN_ACTION_PUBLIC:
if (hapd->public_action_cb) {
hapd->public_action_cb(hapd->public_action_cb_ctx,
(u8 *) mgmt, len,
hapd->iface->freq);
- return;
}
+ if (hapd->public_action_cb2) {
+ hapd->public_action_cb2(hapd->public_action_cb2_ctx,
+ (u8 *) mgmt, len,
+ hapd->iface->freq);
+ }
+ if (hapd->public_action_cb || hapd->public_action_cb2)
+ return;
break;
case WLAN_ACTION_VENDOR_SPECIFIC:
if (hapd->vendor_action_cb) {
@@ -1505,6 +1797,7 @@
struct sta_info *sta;
int new_assoc = 1;
struct ieee80211_ht_capabilities ht_cap;
+ struct ieee80211_vht_capabilities vht_cap;
if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) :
sizeof(mgmt->u.assoc_resp))) {
@@ -1577,11 +1870,16 @@
if (sta->flags & WLAN_STA_HT)
hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap);
#endif /* CONFIG_IEEE80211N */
+#ifdef CONFIG_IEEE80211AC
+ if (sta->flags & WLAN_STA_VHT)
+ hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap);
+#endif /* CONFIG_IEEE80211AC */
if (hostapd_sta_add(hapd, sta->addr, sta->aid, sta->capability,
sta->supported_rates, sta->supported_rates_len,
sta->listen_interval,
sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
+ sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
sta->flags, sta->qosinfo)) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_NOTICE,
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 1e5800d..2aab56d 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -53,6 +53,9 @@
void hostapd_get_ht_capab(struct hostapd_data *hapd,
struct ieee80211_ht_capabilities *ht_cap,
struct ieee80211_ht_capabilities *neg_ht_cap);
+void hostapd_get_vht_capab(struct hostapd_data *hapd,
+ struct ieee80211_vht_capabilities *vht_cap,
+ struct ieee80211_vht_capabilities *neg_vht_cap);
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ht_capab, size_t ht_capab_len);
void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta);
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index 63ae345..c311e55 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -36,8 +36,7 @@
u32 session_timeout;
u32 acct_interim_interval;
int vlan_id;
- int has_psk;
- u8 psk[PMK_LEN];
+ struct hostapd_sta_wpa_psk_short *psk;
char *identity;
char *radius_cui;
};
@@ -58,6 +57,7 @@
{
os_free(e->identity);
os_free(e->radius_cui);
+ hostapd_free_psk_list(e->psk);
os_free(e);
}
@@ -74,11 +74,34 @@
}
+static void copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
+ struct hostapd_sta_wpa_psk_short *src)
+{
+ struct hostapd_sta_wpa_psk_short **copy_to;
+ struct hostapd_sta_wpa_psk_short *copy_from;
+
+ /* Copy PSK linked list */
+ copy_to = psk;
+ copy_from = src;
+ while (copy_from && copy_to) {
+ *copy_to = os_zalloc(sizeof(struct hostapd_sta_wpa_psk_short));
+ if (*copy_to == NULL)
+ break;
+ os_memcpy(*copy_to, copy_from,
+ sizeof(struct hostapd_sta_wpa_psk_short));
+ copy_from = copy_from->next;
+ copy_to = &((*copy_to)->next);
+ }
+ if (copy_to)
+ *copy_to = NULL;
+}
+
+
static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
u32 *session_timeout,
u32 *acct_interim_interval, int *vlan_id,
- u8 *psk, int *has_psk, char **identity,
- char **radius_cui)
+ struct hostapd_sta_wpa_psk_short **psk,
+ char **identity, char **radius_cui)
{
struct hostapd_cached_radius_acl *entry;
struct os_time now;
@@ -99,10 +122,7 @@
entry->acct_interim_interval;
if (vlan_id)
*vlan_id = entry->vlan_id;
- if (psk)
- os_memcpy(psk, entry->psk, PMK_LEN);
- if (has_psk)
- *has_psk = entry->has_psk;
+ copy_psk_list(psk, entry->psk);
if (identity) {
if (entry->identity)
*identity = os_strdup(entry->identity);
@@ -200,8 +220,7 @@
* @session_timeout: Buffer for returning session timeout (from RADIUS)
* @acct_interim_interval: Buffer for returning account interval (from RADIUS)
* @vlan_id: Buffer for returning VLAN ID
- * @psk: Buffer for returning WPA PSK
- * @has_psk: Buffer for indicating whether psk was filled
+ * @psk: Linked list buffer for returning WPA PSK
* @identity: Buffer for returning identity (from RADIUS)
* @radius_cui: Buffer for returning CUI (from RADIUS)
* Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
@@ -212,8 +231,8 @@
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
const u8 *msg, size_t len, u32 *session_timeout,
u32 *acct_interim_interval, int *vlan_id,
- u8 *psk, int *has_psk, char **identity,
- char **radius_cui)
+ struct hostapd_sta_wpa_psk_short **psk,
+ char **identity, char **radius_cui)
{
if (session_timeout)
*session_timeout = 0;
@@ -221,10 +240,8 @@
*acct_interim_interval = 0;
if (vlan_id)
*vlan_id = 0;
- if (has_psk)
- *has_psk = 0;
if (psk)
- os_memset(psk, 0, PMK_LEN);
+ *psk = NULL;
if (identity)
*identity = NULL;
if (radius_cui)
@@ -253,7 +270,7 @@
/* Check whether ACL cache has an entry for this station */
int res = hostapd_acl_cache_get(hapd, addr, session_timeout,
acct_interim_interval,
- vlan_id, psk, has_psk,
+ vlan_id, psk,
identity, radius_cui);
if (res == HOSTAPD_ACL_ACCEPT ||
res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
@@ -396,6 +413,54 @@
}
+static void decode_tunnel_passwords(struct hostapd_data *hapd,
+ const u8 *shared_secret,
+ size_t shared_secret_len,
+ struct radius_msg *msg,
+ struct radius_msg *req,
+ struct hostapd_cached_radius_acl *cache)
+{
+ int passphraselen;
+ char *passphrase, *strpassphrase;
+ size_t i;
+ struct hostapd_sta_wpa_psk_short *psk;
+
+ /*
+ * Decode all tunnel passwords as PSK and save them into a linked list.
+ */
+ for (i = 0; ; i++) {
+ passphrase = radius_msg_get_tunnel_password(
+ msg, &passphraselen, shared_secret, shared_secret_len,
+ req, i);
+ /*
+ * Passphrase is NULL iff there is no i-th Tunnel-Password
+ * attribute in msg.
+ */
+ if (passphrase == NULL)
+ break;
+ /*
+ * passphrase does not contain the NULL termination.
+ * Add it here as pbkdf2_sha1() requires it.
+ */
+ strpassphrase = os_zalloc(passphraselen + 1);
+ psk = os_zalloc(sizeof(struct hostapd_sta_wpa_psk_short));
+ if (strpassphrase && psk) {
+ os_memcpy(strpassphrase, passphrase, passphraselen);
+ pbkdf2_sha1(strpassphrase,
+ hapd->conf->ssid.ssid,
+ hapd->conf->ssid.ssid_len, 4096,
+ psk->psk, PMK_LEN);
+ psk->next = cache->psk;
+ cache->psk = psk;
+ psk = NULL;
+ }
+ os_free(strpassphrase);
+ os_free(psk);
+ os_free(passphrase);
+ }
+}
+
+
/**
* hostapd_acl_recv_radius - Process incoming RADIUS Authentication messages
* @msg: RADIUS response message
@@ -454,8 +519,6 @@
cache->timestamp = t.sec;
os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
- int passphraselen;
- char *passphrase;
u8 *buf;
size_t len;
@@ -478,27 +541,9 @@
cache->vlan_id = radius_msg_get_vlanid(msg);
- passphrase = radius_msg_get_tunnel_password(
- msg, &passphraselen,
- hapd->conf->radius->auth_server->shared_secret,
- hapd->conf->radius->auth_server->shared_secret_len,
- req);
- cache->has_psk = passphrase != NULL;
- if (passphrase != NULL) {
- /* passphrase does not contain the NULL termination.
- * Add it here as pbkdf2_sha1 requires it. */
- char *strpassphrase = os_zalloc(passphraselen + 1);
- if (strpassphrase) {
- os_memcpy(strpassphrase, passphrase,
- passphraselen);
- pbkdf2_sha1(strpassphrase,
- hapd->conf->ssid.ssid,
- hapd->conf->ssid.ssid_len, 4096,
- cache->psk, PMK_LEN);
- os_free(strpassphrase);
- }
- os_free(passphrase);
- }
+ decode_tunnel_passwords(hapd, shared_secret, shared_secret_len,
+ msg, req, cache);
+
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
&buf, &len, NULL) == 0) {
cache->identity = os_zalloc(len + 1);
@@ -514,7 +559,7 @@
}
if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED &&
- !cache->has_psk)
+ !cache->psk)
cache->accepted = HOSTAPD_ACL_REJECT;
} else
cache->accepted = HOSTAPD_ACL_REJECT;
@@ -586,3 +631,13 @@
hostapd_acl_query_free(prev);
}
}
+
+
+void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk)
+{
+ while (psk) {
+ struct hostapd_sta_wpa_psk_short *prev = psk;
+ psk = psk->next;
+ os_free(prev);
+ }
+}
diff --git a/src/ap/ieee802_11_auth.h b/src/ap/ieee802_11_auth.h
index 0e8d1cb..2bc1065 100644
--- a/src/ap/ieee802_11_auth.h
+++ b/src/ap/ieee802_11_auth.h
@@ -19,9 +19,10 @@
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
const u8 *msg, size_t len, u32 *session_timeout,
u32 *acct_interim_interval, int *vlan_id,
- u8 *psk, int *has_psk, char **identity,
- char **radius_cui);
+ struct hostapd_sta_wpa_psk_short **psk,
+ char **identity, char **radius_cui);
int hostapd_acl_init(struct hostapd_data *hapd);
void hostapd_acl_deinit(struct hostapd_data *hapd);
+void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk);
#endif /* IEEE802_11_AUTH_H */
diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c
index 6c3696f..6483e1c 100644
--- a/src/ap/ieee802_11_ht.c
+++ b/src/ap/ieee802_11_ht.c
@@ -133,8 +133,7 @@
new_op_mode = 0;
if (iface->num_sta_no_ht)
new_op_mode = OP_MODE_MIXED;
- else if ((iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)
- && iface->num_sta_ht_20mhz)
+ else if (iface->conf->secondary_channel && iface->num_sta_ht_20mhz)
new_op_mode = OP_MODE_20MHZ_HT_STA_ASSOCED;
else if (iface->olbc_ht)
new_op_mode = OP_MODE_MAY_BE_LEGACY_STAS;
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index b3fdf3d..c36bbe3 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -164,41 +164,89 @@
#endif /* CONFIG_IEEE80211W */
+static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
+{
+ *pos = 0x00;
+
+ switch (idx) {
+ case 0: /* Bits 0-7 */
+ break;
+ case 1: /* Bits 8-15 */
+ break;
+ case 2: /* Bits 16-23 */
+ if (hapd->conf->wnm_sleep_mode)
+ *pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
+ if (hapd->conf->bss_transition)
+ *pos |= 0x08; /* Bit 19 - BSS Transition */
+ break;
+ case 3: /* Bits 24-31 */
+#ifdef CONFIG_WNM
+ *pos |= 0x02; /* Bit 25 - SSID List */
+#endif /* CONFIG_WNM */
+ if (hapd->conf->time_advertisement == 2)
+ *pos |= 0x08; /* Bit 27 - UTC TSF Offset */
+ if (hapd->conf->interworking)
+ *pos |= 0x80; /* Bit 31 - Interworking */
+ break;
+ case 4: /* Bits 32-39 */
+ if (hapd->conf->tdls & TDLS_PROHIBIT)
+ *pos |= 0x40; /* Bit 38 - TDLS Prohibited */
+ if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH) {
+ /* Bit 39 - TDLS Channel Switching Prohibited */
+ *pos |= 0x80;
+ }
+ break;
+ case 5: /* Bits 40-47 */
+ break;
+ case 6: /* Bits 48-55 */
+ if (hapd->conf->ssid.utf8_ssid)
+ *pos |= 0x01; /* Bit 48 - UTF-8 SSID */
+ break;
+ }
+}
+
+
u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
{
u8 *pos = eid;
- u8 len = 0;
+ u8 len = 0, i;
if (hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH))
len = 5;
if (len < 4 && hapd->conf->interworking)
len = 4;
+ if (len < 3 && hapd->conf->wnm_sleep_mode)
+ len = 3;
+ if (len < 7 && hapd->conf->ssid.utf8_ssid)
+ len = 7;
+#ifdef CONFIG_WNM
+ if (len < 4)
+ len = 4;
+#endif /* CONFIG_WNM */
+ if (len < hapd->iface->extended_capa_len)
+ len = hapd->iface->extended_capa_len;
if (len == 0)
return eid;
*pos++ = WLAN_EID_EXT_CAPAB;
*pos++ = len;
- *pos++ = 0x00;
- *pos++ = 0x00;
- *pos++ = 0x00;
+ for (i = 0; i < len; i++, pos++) {
+ hostapd_ext_capab_byte(hapd, pos, i);
- *pos = 0x00;
- if (hapd->conf->time_advertisement == 2)
- *pos |= 0x08; /* Bit 27 - UTC TSF Offset */
- if (hapd->conf->interworking)
- *pos |= 0x80; /* Bit 31 - Interworking */
- pos++;
+ if (i < hapd->iface->extended_capa_len) {
+ *pos &= ~hapd->iface->extended_capa_mask[i];
+ *pos |= hapd->iface->extended_capa[i];
+ }
+ }
- if (len < 5)
- return pos;
- *pos = 0x00;
- if (hapd->conf->tdls & TDLS_PROHIBIT)
- *pos |= 0x40; /* Bit 38 - TDLS Prohibited */
- if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH)
- *pos |= 0x80; /* Bit 39 - TDLS Channel Switching Prohibited */
- pos++;
+ while (len > 0 && eid[1 + len] == 0) {
+ len--;
+ eid[1] = len;
+ }
+ if (len == 0)
+ return eid;
- return pos;
+ return eid + 2 + len;
}
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index 7599ef8..0012c0f 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -38,7 +38,7 @@
hapd->iface->current_mode->vht_capab);
/* Supported MCS set comes from hw */
- os_memcpy(cap->vht_supported_mcs_set,
+ os_memcpy(&cap->vht_supported_mcs_set,
hapd->iface->current_mode->vht_mcs_set, 8);
pos += sizeof(*cap);
@@ -68,6 +68,8 @@
*/
oper->vht_op_info_chan_center_freq_seg0_idx =
hapd->iconf->vht_oper_centr_freq_seg0_idx;
+ oper->vht_op_info_chan_center_freq_seg1_idx =
+ hapd->iconf->vht_oper_centr_freq_seg1_idx;
oper->vht_op_info_chwidth = hapd->iconf->vht_oper_chwidth;
@@ -106,3 +108,14 @@
return WLAN_STATUS_SUCCESS;
}
+
+void hostapd_get_vht_capab(struct hostapd_data *hapd,
+ struct ieee80211_vht_capabilities *vht_cap,
+ struct ieee80211_vht_capabilities *neg_vht_cap)
+{
+ if (vht_cap == NULL)
+ return;
+ os_memcpy(neg_vht_cap, vht_cap, sizeof(*neg_vht_cap));
+
+ /* TODO: mask own capabilities, like get_ht_capab() */
+}
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index c4d3da8..a832a73 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -66,8 +66,9 @@
if (sta->flags & WLAN_STA_PREAUTH) {
rsn_preauth_send(hapd, sta, buf, len);
} else {
- hostapd_drv_hapd_send_eapol(hapd, sta->addr, buf, len,
- encrypt, sta->flags);
+ hostapd_drv_hapd_send_eapol(
+ hapd, sta->addr, buf, len,
+ encrypt, hostapd_sta_flags_to_drv(sta->flags));
}
os_free(buf);
@@ -99,8 +100,10 @@
"driver (errno=%d).\n", MAC2STR(sta->addr), errno);
}
- if (authorized)
+ if (authorized) {
+ os_get_time(&sta->connected_time);
accounting_sta_start(hapd, sta);
+ }
}
@@ -352,6 +355,8 @@
const char *radius_mode_txt(struct hostapd_data *hapd)
{
switch (hapd->iface->conf->hw_mode) {
+ case HOSTAPD_MODE_IEEE80211AD:
+ return "802.11ad";
case HOSTAPD_MODE_IEEE80211A:
return "802.11a";
case HOSTAPD_MODE_IEEE80211G:
@@ -450,6 +455,16 @@
return -1;
}
+ if (sta->acct_session_id_hi || sta->acct_session_id_lo) {
+ os_snprintf(buf, sizeof(buf), "%08X-%08X",
+ sta->acct_session_id_hi, sta->acct_session_id_lo);
+ if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
+ (u8 *) buf, os_strlen(buf))) {
+ wpa_printf(MSG_ERROR, "Could not add Acct-Session-Id");
+ return -1;
+ }
+ }
+
return 0;
}
@@ -1684,8 +1699,7 @@
const struct hostapd_eap_user *eap_user;
int i;
- eap_user = hostapd_get_eap_user(hapd->conf, identity,
- identity_len, phase2);
+ eap_user = hostapd_get_eap_user(hapd, identity, identity_len, phase2);
if (eap_user == NULL)
return -1;
diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c
index ba2c033..d27fd30 100644
--- a/src/ap/pmksa_cache_auth.c
+++ b/src/ap/pmksa_cache_auth.c
@@ -95,11 +95,9 @@
os_get_time(&now);
while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) {
- struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
- pmksa->pmksa = entry->next;
wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
- MACSTR, MAC2STR(entry->spa));
- pmksa_cache_free_entry(pmksa, entry);
+ MACSTR, MAC2STR(pmksa->pmksa->spa));
+ pmksa_cache_free_entry(pmksa, pmksa->pmksa);
}
pmksa_cache_set_expiration(pmksa);
@@ -211,6 +209,8 @@
pmksa->pmkid[PMKID_HASH(entry->pmkid)] = entry;
pmksa->pmksa_count++;
+ if (prev == NULL)
+ pmksa_cache_set_expiration(pmksa);
wpa_printf(MSG_DEBUG, "RSN: added PMKSA cache entry for " MACSTR,
MAC2STR(entry->spa));
wpa_hexdump(MSG_DEBUG, "RSN: added PMKID", entry->pmkid, PMKID_LEN);
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index d61177f..cbafb47 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -12,6 +12,7 @@
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "common/wpa_ctrl.h"
+#include "common/sae.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "drivers/driver.h"
@@ -20,6 +21,7 @@
#include "accounting.h"
#include "ieee802_1x.h"
#include "ieee802_11.h"
+#include "ieee802_11_auth.h"
#include "wpa_auth.h"
#include "preauth_auth.h"
#include "ap_config.h"
@@ -232,12 +234,18 @@
wpabuf_free(sta->wps_ie);
wpabuf_free(sta->p2p_ie);
+ wpabuf_free(sta->hs20_ie);
os_free(sta->ht_capabilities);
- os_free(sta->psk);
+ hostapd_free_psk_list(sta->psk);
os_free(sta->identity);
os_free(sta->radius_cui);
+#ifdef CONFIG_SAE
+ sae_clear_data(sta->sae);
+ os_free(sta->sae);
+#endif /* CONFIG_SAE */
+
os_free(sta);
}
@@ -491,6 +499,7 @@
return NULL;
}
sta->acct_interim_interval = hapd->conf->acct_interim_interval;
+ accounting_sta_get_id(hapd, sta);
/* initialize STA info data */
wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
@@ -567,7 +576,7 @@
{
wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR,
hapd->conf->iface, MAC2STR(sta->addr));
- sta->flags &= ~WLAN_STA_ASSOC;
+ sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
ap_sta_set_authorized(hapd, sta, 0);
sta->timeout_next = STA_DEAUTH;
wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index b3c57b4..32ea46e 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -95,7 +95,8 @@
struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */
int vlan_id;
- u8 *psk; /* PSK from RADIUS authentication server */
+ /* PSKs from RADIUS authentication server */
+ struct hostapd_sta_wpa_psk_short *psk;
char *identity; /* User-Name from RADIUS */
char *radius_cui; /* Chargeable-User-Identity from RADIUS */
@@ -121,6 +122,13 @@
struct wpabuf *wps_ie; /* WPS IE from (Re)Association Request */
struct wpabuf *p2p_ie; /* P2P IE from (Re)Association Request */
+ struct wpabuf *hs20_ie; /* HS 2.0 IE from (Re)Association Request */
+
+ struct os_time connected_time;
+
+#ifdef CONFIG_SAE
+ struct sae_data *sae;
+#endif /* CONFIG_SAE */
};
diff --git a/src/ap/tkip_countermeasures.c b/src/ap/tkip_countermeasures.c
index dd5aa68..4a2ea06 100644
--- a/src/ap/tkip_countermeasures.c
+++ b/src/ap/tkip_countermeasures.c
@@ -66,9 +66,10 @@
}
-void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local)
+int michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local)
{
struct os_time now;
+ int ret = 0;
if (addr && local) {
struct sta_info *sta = ap_get_sta(hapd, addr);
@@ -84,7 +85,7 @@
"MLME-MICHAELMICFAILURE.indication "
"for not associated STA (" MACSTR
") ignored", MAC2STR(addr));
- return;
+ return ret;
}
}
@@ -93,8 +94,12 @@
hapd->michael_mic_failures = 1;
} else {
hapd->michael_mic_failures++;
- if (hapd->michael_mic_failures > 1)
+ if (hapd->michael_mic_failures > 1) {
ieee80211_tkip_countermeasures_start(hapd);
+ ret = 1;
+ }
}
hapd->michael_mic_failure = now.sec;
+
+ return ret;
}
diff --git a/src/ap/tkip_countermeasures.h b/src/ap/tkip_countermeasures.h
index f7a6624..d3eaed3 100644
--- a/src/ap/tkip_countermeasures.h
+++ b/src/ap/tkip_countermeasures.h
@@ -1,6 +1,6 @@
/*
* hostapd / TKIP countermeasures
- * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -9,7 +9,7 @@
#ifndef TKIP_COUNTERMEASURES_H
#define TKIP_COUNTERMEASURES_H
-void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local);
+int michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local);
void ieee80211_tkip_countermeasures_deinit(struct hostapd_data *hapd);
#endif /* TKIP_COUNTERMEASURES_H */
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
index 2594404..54a6b85 100644
--- a/src/ap/wnm_ap.c
+++ b/src/ap/wnm_ap.c
@@ -19,7 +19,6 @@
#define MAX_TFS_IE_LEN 1024
-#ifdef CONFIG_IEEE80211V
/* get the TFS IE from driver */
static int ieee80211_11_get_tfs_ie(struct hostapd_data *hapd, const u8 *addr,
@@ -57,8 +56,8 @@
u16 wnmtfs_ie_len;
u8 *pos;
struct sta_info *sta;
- enum wnm_oper tfs_oper = action_type == 0 ? WNM_SLEEP_TFS_RESP_IE_ADD :
- WNM_SLEEP_TFS_RESP_IE_NONE;
+ enum wnm_oper tfs_oper = action_type == WNM_SLEEP_MODE_ENTER ?
+ WNM_SLEEP_TFS_RESP_IE_ADD : WNM_SLEEP_TFS_RESP_IE_NONE;
sta = ap_get_sta(hapd, addr);
if (sta == NULL) {
@@ -105,7 +104,8 @@
mgmt->u.action.u.wnm_sleep_resp.dialogtoken = dialog_token;
pos = (u8 *)mgmt->u.action.u.wnm_sleep_resp.variable;
/* add key data if MFP is enabled */
- if (wpa_auth_uses_mfp(sta->wpa_sm) || action_type != 1){
+ if (!wpa_auth_uses_mfp(sta->wpa_sm) ||
+ action_type != WNM_SLEEP_MODE_EXIT) {
mgmt->u.action.u.wnm_sleep_resp.keydata_len = 0;
} else {
gtk_elem_len = wpa_wnmsleep_gtk_subelem(sta->wpa_sm, pos);
@@ -132,7 +132,8 @@
os_memcpy(pos, &wnmsleep_ie, wnmsleep_ie_len);
/* copy TFS IE here */
pos += wnmsleep_ie_len;
- os_memcpy(pos, wnmtfs_ie, wnmtfs_ie_len);
+ if (wnmtfs_ie)
+ os_memcpy(pos, wnmtfs_ie, wnmtfs_ie_len);
len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_resp) + gtk_elem_len +
igtk_elem_len + wnmsleep_ie_len + wnmtfs_ie_len;
@@ -152,7 +153,7 @@
* WNM Sleep
*/
if (wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT &&
- wnmsleep_ie.action_type == 0) {
+ wnmsleep_ie.action_type == WNM_SLEEP_MODE_ENTER) {
hostapd_drv_wnm_oper(hapd, WNM_SLEEP_ENTER_CONFIRM,
addr, NULL, NULL);
wpa_set_wnmsleep(sta->wpa_sm, 1);
@@ -162,12 +163,14 @@
* 2. start GTK/IGTK update if MFP is not used
* 3. unpause the node in driver
*/
- if (wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT &&
- wnmsleep_ie.action_type == 1) {
+ if ((wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT ||
+ wnmsleep_ie.status ==
+ WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) &&
+ wnmsleep_ie.action_type == WNM_SLEEP_MODE_EXIT) {
wpa_set_wnmsleep(sta->wpa_sm, 0);
hostapd_drv_wnm_oper(hapd, WNM_SLEEP_EXIT_CONFIRM,
addr, NULL, NULL);
- if (wpa_auth_uses_mfp(sta->wpa_sm) && action_type == 1)
+ if (!wpa_auth_uses_mfp(sta->wpa_sm))
wpa_wnmsleep_rekey_gtk(sta->wpa_sm);
}
} else
@@ -184,29 +187,29 @@
static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
const u8 *addr, const u8 *frm, int len)
{
- /*
- * Action [1] | Dialog Token [1] | WNM-Sleep Mode IE |
- * TFS Response IE
- */
- u8 *pos = (u8 *) frm; /* point to action field */
- u8 dialog_token = pos[1];
+ /* Dialog Token [1] | WNM-Sleep Mode IE | TFS Response IE */
+ const u8 *pos = frm;
+ u8 dialog_token;
struct wnm_sleep_element *wnmsleep_ie = NULL;
/* multiple TFS Req IE (assuming consecutive) */
u8 *tfsreq_ie_start = NULL;
u8 *tfsreq_ie_end = NULL;
u16 tfsreq_ie_len = 0;
- pos += 1 + 1;
- while (pos - frm < len - 1) {
- u8 ie_len = *(pos+1);
+ dialog_token = *pos++;
+ while (pos + 1 < frm + len) {
+ u8 ie_len = pos[1];
+ if (pos + 2 + ie_len > frm + len)
+ break;
if (*pos == WLAN_EID_WNMSLEEP)
- wnmsleep_ie = (struct wnm_sleep_element *)pos;
+ wnmsleep_ie = (struct wnm_sleep_element *) pos;
else if (*pos == WLAN_EID_TFS_REQ) {
if (!tfsreq_ie_start)
- tfsreq_ie_start = pos;
- tfsreq_ie_end = pos;
+ tfsreq_ie_start = (u8 *) pos;
+ tfsreq_ie_end = (u8 *) pos;
} else
- wpa_printf(MSG_DEBUG, "EID %d not recognized", *pos);
+ wpa_printf(MSG_DEBUG, "WNM: EID %d not recognized",
+ *pos);
pos += ie_len + 2;
}
@@ -215,8 +218,9 @@
return;
}
- if (wnmsleep_ie->action_type == 0 && tfsreq_ie_start &&
- tfsreq_ie_end && tfsreq_ie_end - tfsreq_ie_start >= 0) {
+ if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER &&
+ tfsreq_ie_start && tfsreq_ie_end &&
+ tfsreq_ie_end - tfsreq_ie_start >= 0) {
tfsreq_ie_len = (tfsreq_ie_end + tfsreq_ie_end[1] + 2) -
tfsreq_ie_start;
wpa_printf(MSG_DEBUG, "TFS Req IE(s) found");
@@ -231,7 +235,7 @@
wnmsleep_ie->action_type,
wnmsleep_ie->intval);
- if (wnmsleep_ie->action_type == 1) {
+ if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) {
/* clear the tfs after sending the resp frame */
ieee80211_11_set_tfs_ie(hapd, addr, tfsreq_ie_start,
&tfsreq_ie_len, WNM_SLEEP_TFS_IE_DEL);
@@ -239,20 +243,29 @@
}
-void ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
- struct rx_action *action)
+int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
+ struct rx_action *action)
{
- u8 *pos = (u8 *) action->data + 1; /* point to the action field */
- u8 act = *pos;
+ if (action->len < 1 || action->data == NULL)
+ return -1;
- switch (act) {
+ switch (action->data[0]) {
+ case WNM_BSS_TRANS_MGMT_QUERY:
+ wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Query");
+ /* TODO */
+ return -1;
+ case WNM_BSS_TRANS_MGMT_RESP:
+ wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management "
+ "Response");
+ /* TODO */
+ return -1;
case WNM_SLEEP_MODE_REQ:
ieee802_11_rx_wnmsleep_req(hapd, action->sa, action->data + 1,
- action->len);
- break;
- default:
- break;
+ action->len - 1);
+ return 0;
}
-}
-#endif /* CONFIG_IEEE80211V */
+ wpa_printf(MSG_DEBUG, "WNM: Unsupported WNM Action %u from " MACSTR,
+ action->data[0], MAC2STR(action->sa));
+ return -1;
+}
diff --git a/src/ap/wnm_ap.h b/src/ap/wnm_ap.h
index ab7c4f1..f05726e 100644
--- a/src/ap/wnm_ap.h
+++ b/src/ap/wnm_ap.h
@@ -11,7 +11,7 @@
struct rx_action;
-void ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
- struct rx_action *action);
+int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
+ struct rx_action *action);
#endif /* WNM_AP_H */
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 49d8175..4f1f6fb 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -54,11 +54,12 @@
static const int dot11RSNAConfigSATimeout = 60;
-static inline void wpa_auth_mic_failure_report(
+static inline int wpa_auth_mic_failure_report(
struct wpa_authenticator *wpa_auth, const u8 *addr)
{
if (wpa_auth->cb.mic_failure_report)
- wpa_auth->cb.mic_failure_report(wpa_auth->cb.ctx, addr);
+ return wpa_auth->cb.mic_failure_report(wpa_auth->cb.ctx, addr);
+ return 0;
}
@@ -281,8 +282,9 @@
static int wpa_group_init_gmk_and_counter(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
- u8 buf[ETH_ALEN + 8 + sizeof(group)];
+ u8 buf[ETH_ALEN + 8 + sizeof(unsigned long)];
u8 rkey[32];
+ unsigned long ptr;
if (random_get_bytes(group->GMK, WPA_GMK_LEN) < 0)
return -1;
@@ -294,7 +296,8 @@
*/
os_memcpy(buf, wpa_auth->addr, ETH_ALEN);
wpa_get_ntp_timestamp(buf + ETH_ALEN);
- os_memcpy(buf + ETH_ALEN + 8, &group, sizeof(group));
+ ptr = (unsigned long) group;
+ os_memcpy(buf + ETH_ALEN + 8, &ptr, sizeof(ptr));
if (random_get_bytes(rkey, sizeof(rkey)) < 0)
return -1;
@@ -700,8 +703,8 @@
#endif /* CONFIG_IEEE80211R */
-static void wpa_receive_error_report(struct wpa_authenticator *wpa_auth,
- struct wpa_state_machine *sm, int group)
+static int wpa_receive_error_report(struct wpa_authenticator *wpa_auth,
+ struct wpa_state_machine *sm, int group)
{
/* Supplicant reported a Michael MIC error */
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
@@ -718,7 +721,8 @@
"ignore Michael MIC failure report since "
"pairwise cipher is not TKIP");
} else {
- wpa_auth_mic_failure_report(wpa_auth, sm->addr);
+ if (wpa_auth_mic_failure_report(wpa_auth, sm->addr) > 0)
+ return 1; /* STA entry was removed */
sm->dot11RSNAStatsTKIPRemoteMICFailures++;
wpa_auth->dot11RSNAStatsTKIPRemoteMICFailures++;
}
@@ -728,6 +732,7 @@
* Authenticator may do it, let's change the keys now anyway.
*/
wpa_request_new_ptk(sm);
+ return 0;
}
@@ -1081,9 +1086,10 @@
#endif /* CONFIG_PEERKEY */
return;
} else if (key_info & WPA_KEY_INFO_ERROR) {
- wpa_receive_error_report(
- wpa_auth, sm,
- !(key_info & WPA_KEY_INFO_KEY_TYPE));
+ if (wpa_receive_error_report(
+ wpa_auth, sm,
+ !(key_info & WPA_KEY_INFO_KEY_TYPE)) > 0)
+ return; /* STA entry was removed */
} else if (key_info & WPA_KEY_INFO_KEY_TYPE) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
"received EAPOL-Key Request for new "
@@ -1592,6 +1598,7 @@
SM_ENTRY_MA(WPA_PTK, AUTHENTICATION2, wpa_ptk);
wpa_group_ensure_init(sm->wpa_auth, sm->group);
+ sm->ReAuthenticationRequest = FALSE;
/*
* Definition of ANonce selection in IEEE Std 802.11i-2004 is somewhat
@@ -1605,12 +1612,11 @@
if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
wpa_printf(MSG_ERROR, "WPA: Failed to get random data for "
"ANonce.");
- wpa_sta_disconnect(sm->wpa_auth, sm->addr);
+ sm->Disconnect = TRUE;
return;
}
wpa_hexdump(MSG_DEBUG, "WPA: Assign ANonce", sm->ANonce,
WPA_NONCE_LEN);
- sm->ReAuthenticationRequest = FALSE;
/* IEEE 802.11i does not clear TimeoutCtr here, but this is more
* logical place than INITIALIZE since AUTHENTICATION2 can be
* re-entered on ReAuthenticationRequest without going through
@@ -2409,11 +2415,9 @@
"marking station for GTK rekeying");
}
-#ifdef CONFIG_IEEE80211V
- /* Do not rekey GTK/IGTK when STA is in wnmsleep */
+ /* Do not rekey GTK/IGTK when STA is in WNM-Sleep Mode */
if (sm->is_wnmsleep)
return 0;
-#endif /* CONFIG_IEEE80211V */
sm->group->GKeyDoneStations++;
sm->GUpdateStationKeys = TRUE;
@@ -2423,8 +2427,8 @@
}
-#ifdef CONFIG_IEEE80211V
-/* update GTK when exiting wnmsleep mode */
+#ifdef CONFIG_WNM
+/* update GTK when exiting WNM-Sleep Mode */
void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm)
{
if (sm->is_wnmsleep)
@@ -2442,111 +2446,65 @@
int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos)
{
- u8 *subelem;
struct wpa_group *gsm = sm->group;
- size_t subelem_len, pad_len;
- const u8 *key;
- size_t key_len;
- u8 keybuf[32];
-
- /* GTK subslement */
- key_len = gsm->GTK_len;
- if (key_len > sizeof(keybuf))
- return 0;
+ u8 *start = pos;
/*
- * Pad key for AES Key Wrap if it is not multiple of 8 bytes or is less
- * than 16 bytes.
- */
- pad_len = key_len % 8;
- if (pad_len)
- pad_len = 8 - pad_len;
- if (key_len + pad_len < 16)
- pad_len += 8;
- if (pad_len) {
- os_memcpy(keybuf, gsm->GTK[gsm->GN - 1], key_len);
- os_memset(keybuf + key_len, 0, pad_len);
- keybuf[key_len] = 0xdd;
- key_len += pad_len;
- key = keybuf;
- } else
- key = gsm->GTK[gsm->GN - 1];
-
- /*
+ * GTK subelement:
* Sub-elem ID[1] | Length[1] | Key Info[2] | Key Length[1] | RSC[8] |
- * Key[5..32] | 8 padding.
+ * Key[5..32]
*/
- subelem_len = 13 + key_len + 8;
- subelem = os_zalloc(subelem_len);
- if (subelem == NULL)
- return 0;
-
- subelem[0] = WNM_SLEEP_SUBELEM_GTK;
- subelem[1] = 11 + key_len + 8;
+ *pos++ = WNM_SLEEP_SUBELEM_GTK;
+ *pos++ = 11 + gsm->GTK_len;
/* Key ID in B0-B1 of Key Info */
- WPA_PUT_LE16(&subelem[2], gsm->GN & 0x03);
- subelem[4] = gsm->GTK_len;
- if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, subelem + 5) != 0)
- {
- os_free(subelem);
+ WPA_PUT_LE16(pos, gsm->GN & 0x03);
+ pos += 2;
+ *pos++ = gsm->GTK_len;
+ if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, pos) != 0)
return 0;
- }
- if (aes_wrap(sm->PTK.kek, key_len / 8, key, subelem + 13)) {
- os_free(subelem);
- return 0;
- }
+ pos += 8;
+ os_memcpy(pos, gsm->GTK[gsm->GN - 1], gsm->GTK_len);
+ pos += gsm->GTK_len;
- os_memcpy(pos, subelem, subelem_len);
-
- wpa_hexdump_key(MSG_DEBUG, "Plaintext GTK",
+ wpa_printf(MSG_DEBUG, "WNM: GTK Key ID %u in WNM-Sleep Mode exit",
+ gsm->GN);
+ wpa_hexdump_key(MSG_DEBUG, "WNM: GTK in WNM-Sleep Mode exit",
gsm->GTK[gsm->GN - 1], gsm->GTK_len);
- os_free(subelem);
- return subelem_len;
+ return pos - start;
}
#ifdef CONFIG_IEEE80211W
int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)
{
- u8 *subelem, *ptr;
struct wpa_group *gsm = sm->group;
- size_t subelem_len;
+ u8 *start = pos;
- /* IGTK subelement
- * Sub-elem ID[1] | Length[1] | KeyID[2] | PN[6] |
- * Key[16] | 8 padding */
- subelem_len = 1 + 1 + 2 + 6 + WPA_IGTK_LEN + 8;
- subelem = os_zalloc(subelem_len);
- if (subelem == NULL)
+ /*
+ * IGTK subelement:
+ * Sub-elem ID[1] | Length[1] | KeyID[2] | PN[6] | Key[16]
+ */
+ *pos++ = WNM_SLEEP_SUBELEM_IGTK;
+ *pos++ = 2 + 6 + WPA_IGTK_LEN;
+ WPA_PUT_LE16(pos, gsm->GN_igtk);
+ pos += 2;
+ if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos) != 0)
return 0;
+ pos += 6;
- ptr = subelem;
- *ptr++ = WNM_SLEEP_SUBELEM_IGTK;
- *ptr++ = subelem_len - 2;
- WPA_PUT_LE16(ptr, gsm->GN_igtk);
- ptr += 2;
- if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, ptr) != 0) {
- os_free(subelem);
- return 0;
- }
- ptr += 6;
- if (aes_wrap(sm->PTK.kek, WPA_IGTK_LEN / 8,
- gsm->IGTK[gsm->GN_igtk - 4], ptr)) {
- os_free(subelem);
- return -1;
- }
+ os_memcpy(pos, gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN);
+ pos += WPA_IGTK_LEN;
- os_memcpy(pos, subelem, subelem_len);
-
- wpa_hexdump_key(MSG_DEBUG, "Plaintext IGTK",
+ wpa_printf(MSG_DEBUG, "WNM: IGTK Key ID %u in WNM-Sleep Mode exit",
+ gsm->GN_igtk);
+ wpa_hexdump_key(MSG_DEBUG, "WNM: IGTK in WNM-Sleep Mode exit",
gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN);
- os_free(subelem);
- return subelem_len;
+ return pos - start;
}
#endif /* CONFIG_IEEE80211W */
-#endif /* CONFIG_IEEE80211V */
+#endif /* CONFIG_WNM */
static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
@@ -3056,3 +3014,11 @@
wpa_send_eapol_timeout, wpa_auth, sm);
}
}
+
+
+int wpa_auth_uses_sae(struct wpa_state_machine *sm)
+{
+ if (sm == NULL)
+ return 0;
+ return wpa_key_mgmt_sae(sm->wpa_key_mgmt);
+}
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 91ba499..465eec6 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -177,7 +177,7 @@
void (*logger)(void *ctx, const u8 *addr, logger_level level,
const char *txt);
void (*disconnect)(void *ctx, const u8 *addr, u16 reason);
- void (*mic_failure_report)(void *ctx, const u8 *addr);
+ int (*mic_failure_report)(void *ctx, const u8 *addr);
void (*set_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var,
int value);
int (*get_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var);
@@ -282,13 +282,11 @@
void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr);
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211V
void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm);
void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag);
int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos);
-#ifdef CONFIG_IEEE80211W
int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos);
-#endif /* CONFIG_IEEE80211W */
-#endif /* CONFIG_IEEE80211V */
+
+int wpa_auth_uses_sae(struct wpa_state_machine *sm);
#endif /* WPA_AUTH_H */
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index 48bf79b..ccb3f82 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -416,7 +416,7 @@
pad_len = 8 - pad_len;
if (key_len + pad_len < 16)
pad_len += 8;
- if (pad_len) {
+ if (pad_len && key_len < sizeof(keybuf)) {
os_memcpy(keybuf, gsm->GTK[gsm->GN - 1], key_len);
os_memset(keybuf + key_len, 0, pad_len);
keybuf[key_len] = 0xdd;
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index bdc89e4..fdaaaff 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -1,6 +1,6 @@
/*
* hostapd / WPA authenticator glue code
- * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2012, 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 "eapol_auth/eapol_auth_sm_i.h"
#include "eap_server/eap.h"
@@ -112,10 +113,10 @@
}
-static void hostapd_wpa_auth_mic_failure_report(void *ctx, const u8 *addr)
+static int hostapd_wpa_auth_mic_failure_report(void *ctx, const u8 *addr)
{
struct hostapd_data *hapd = ctx;
- michael_mic_failure(hapd, addr, 0);
+ return michael_mic_failure(hapd, addr, 0);
}
@@ -184,14 +185,32 @@
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta = ap_get_sta(hapd, addr);
- const u8 *psk = hostapd_get_psk(hapd->conf, addr, prev_psk);
+ const u8 *psk;
+
+#ifdef CONFIG_SAE
+ if (sta && sta->auth_alg == WLAN_AUTH_SAE) {
+ if (!sta->sae || prev_psk)
+ return NULL;
+ return sta->sae->pmk;
+ }
+#endif /* CONFIG_SAE */
+
+ psk = hostapd_get_psk(hapd->conf, addr, prev_psk);
/*
* This is about to iterate over all psks, prev_psk gives the last
* returned psk which should not be returned again.
- * logic list (all hostapd_get_psk; sta->psk)
+ * logic list (all hostapd_get_psk; all sta->psk)
*/
- if (sta && sta->psk && !psk && sta->psk != prev_psk)
- psk = sta->psk;
+ if (sta && sta->psk && !psk) {
+ struct hostapd_sta_wpa_psk_short *pos;
+ psk = sta->psk->psk;
+ for (pos = sta->psk; pos; pos = pos->next) {
+ if (pos->psk == prev_psk) {
+ psk = pos->next ? pos->next->psk : NULL;
+ break;
+ }
+ }
+ }
return psk;
}
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index d5cf2c5..97489d3 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -87,9 +87,7 @@
unsigned int ft_completed:1;
unsigned int pmk_r1_name_valid:1;
#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211V
unsigned int is_wnmsleep:1;
-#endif /* CONFIG_IEEE80211V */
u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN];
int req_replay_counter_used;
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 1786230..cdfcca1 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -188,6 +188,18 @@
num_suites++;
}
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+#endif /* CONFIG_SAE */
#ifdef CONFIG_RSN_TESTING
if (rsn_testing) {
@@ -407,6 +419,12 @@
else if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
selector = RSN_AUTH_KEY_MGMT_PSK_SHA256;
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+ else if (data.key_mgmt & WPA_KEY_MGMT_SAE)
+ selector = RSN_AUTH_KEY_MGMT_SAE;
+ else if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE)
+ selector = RSN_AUTH_KEY_MGMT_FT_SAE;
+#endif /* CONFIG_SAE */
else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X)
selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
else if (data.key_mgmt & WPA_KEY_MGMT_PSK)
@@ -479,6 +497,12 @@
else if (key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+ else if (key_mgmt & WPA_KEY_MGMT_SAE)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_SAE;
+ else if (key_mgmt & WPA_KEY_MGMT_FT_SAE)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_SAE;
+#endif /* CONFIG_SAE */
else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X)
sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X;
else
@@ -540,12 +564,9 @@
}
#endif /* CONFIG_IEEE80211R */
- if (ciphers & WPA_CIPHER_CCMP)
- sm->pairwise = WPA_CIPHER_CCMP;
- else if (ciphers & WPA_CIPHER_GCMP)
- sm->pairwise = WPA_CIPHER_GCMP;
- else
- sm->pairwise = WPA_CIPHER_TKIP;
+ sm->pairwise = wpa_pick_pairwise_cipher(ciphers, 0);
+ if (sm->pairwise < 0)
+ return WPA_INVALID_PAIRWISE;
/* TODO: clear WPA/WPA2 state if STA changes from one to another */
if (wpa_ie[0] == WLAN_EID_RSN)
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index 5e44c72..69b34fe 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -11,8 +11,6 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "utils/uuid.h"
-#include "crypto/dh_groups.h"
-#include "crypto/dh_group5.h"
#include "common/wpa_ctrl.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
@@ -47,6 +45,7 @@
struct wps_for_each_data {
int (*func)(struct hostapd_data *h, void *ctx);
void *ctx;
+ struct hostapd_data *calling_hapd;
};
@@ -59,7 +58,14 @@
return 0;
for (j = 0; j < iface->num_bss; j++) {
struct hostapd_data *hapd = iface->bss[j];
- int ret = data->func(hapd, data->ctx);
+ int ret;
+
+ if (hapd != data->calling_hapd &&
+ (hapd->conf->wps_independent ||
+ data->calling_hapd->conf->wps_independent))
+ continue;
+
+ ret = data->func(hapd, data->ctx);
if (ret)
return ret;
}
@@ -76,6 +82,7 @@
struct wps_for_each_data data;
data.func = func;
data.ctx = ctx;
+ data.calling_hapd = hapd;
if (iface->interfaces == NULL ||
iface->interfaces->for_each_interface == NULL)
return wps_for_each(iface, &data);
@@ -279,6 +286,114 @@
}
+static int hapd_wps_reconfig_in_memory(struct hostapd_data *hapd,
+ const struct wps_credential *cred)
+{
+ struct hostapd_bss_config *bss = hapd->conf;
+
+ wpa_printf(MSG_DEBUG, "WPS: Updating in-memory configuration");
+
+ bss->wps_state = 2;
+ if (cred->ssid_len <= HOSTAPD_MAX_SSID_LEN) {
+ os_memcpy(bss->ssid.ssid, cred->ssid, cred->ssid_len);
+ bss->ssid.ssid_len = cred->ssid_len;
+ bss->ssid.ssid_set = 1;
+ }
+
+ if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) &&
+ (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)))
+ bss->wpa = 3;
+ else if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK))
+ bss->wpa = 2;
+ else if (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK))
+ bss->wpa = 1;
+ else
+ bss->wpa = 0;
+
+ if (bss->wpa) {
+ if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA))
+ bss->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X;
+ if (cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK))
+ bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
+
+ bss->wpa_pairwise = 0;
+ if (cred->encr_type & WPS_ENCR_AES)
+ bss->wpa_pairwise |= WPA_CIPHER_CCMP;
+ if (cred->encr_type & WPS_ENCR_TKIP)
+ bss->wpa_pairwise |= WPA_CIPHER_TKIP;
+ bss->rsn_pairwise = bss->wpa_pairwise;
+ bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa,
+ bss->wpa_pairwise,
+ bss->rsn_pairwise);
+
+ if (cred->key_len >= 8 && cred->key_len < 64) {
+ os_free(bss->ssid.wpa_passphrase);
+ bss->ssid.wpa_passphrase = os_zalloc(cred->key_len + 1);
+ if (bss->ssid.wpa_passphrase)
+ os_memcpy(bss->ssid.wpa_passphrase, cred->key,
+ cred->key_len);
+ os_free(bss->ssid.wpa_psk);
+ bss->ssid.wpa_psk = NULL;
+ } else if (cred->key_len == 64) {
+ os_free(bss->ssid.wpa_psk);
+ bss->ssid.wpa_psk =
+ os_zalloc(sizeof(struct hostapd_wpa_psk));
+ if (bss->ssid.wpa_psk &&
+ hexstr2bin((const char *) cred->key,
+ bss->ssid.wpa_psk->psk, PMK_LEN) == 0) {
+ bss->ssid.wpa_psk->group = 1;
+ os_free(bss->ssid.wpa_passphrase);
+ bss->ssid.wpa_passphrase = NULL;
+ }
+ }
+ bss->auth_algs = 1;
+ } else {
+ if ((cred->auth_type & WPS_AUTH_OPEN) &&
+ (cred->auth_type & WPS_AUTH_SHARED))
+ bss->auth_algs = 3;
+ else if (cred->auth_type & WPS_AUTH_SHARED)
+ bss->auth_algs = 2;
+ else
+ bss->auth_algs = 1;
+ if (cred->encr_type & WPS_ENCR_WEP && cred->key_idx > 0 &&
+ cred->key_idx <= 4) {
+ struct hostapd_wep_keys *wep = &bss->ssid.wep;
+ int idx = cred->key_idx;
+ if (idx)
+ idx--;
+ wep->idx = idx;
+ if (cred->key_len == 10 || cred->key_len == 26) {
+ os_free(wep->key[idx]);
+ wep->key[idx] = os_malloc(cred->key_len / 2);
+ if (wep->key[idx] == NULL ||
+ hexstr2bin((const char *) cred->key,
+ wep->key[idx],
+ cred->key_len / 2))
+ return -1;
+ wep->len[idx] = cred->key_len / 2;
+ } else {
+ os_free(wep->key[idx]);
+ wep->key[idx] = os_malloc(cred->key_len);
+ if (wep->key[idx] == NULL)
+ return -1;
+ os_memcpy(wep->key[idx], cred->key,
+ cred->key_len);
+ wep->len[idx] = cred->key_len;
+ }
+ wep->keys_set = 1;
+ }
+ }
+
+ /* Schedule configuration reload after short period of time to allow
+ * EAP-WSC to be finished.
+ */
+ eloop_register_timeout(0, 100000, wps_reload_config, hapd->iface,
+ NULL);
+
+ return 0;
+}
+
+
static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
{
const struct wps_credential *cred = ctx;
@@ -346,7 +461,7 @@
hapd->wps->wps_state = WPS_STATE_CONFIGURED;
if (hapd->iface->config_fname == NULL)
- return 0;
+ return hapd_wps_reconfig_in_memory(hapd, cred);
len = os_strlen(hapd->iface->config_fname) + 5;
tmp_fname = os_malloc(len);
if (tmp_fname == NULL)
@@ -708,7 +823,8 @@
return 0;
for (j = 0; j < iface->num_bss; j++) {
struct hostapd_data *hapd = iface->bss[j];
- if (hapd->wps && !is_nil_uuid(hapd->wps->uuid)) {
+ if (hapd->wps && !hapd->conf->wps_independent &&
+ !is_nil_uuid(hapd->wps->uuid)) {
*uuid = hapd->wps->uuid;
return 1;
}
@@ -801,7 +917,7 @@
if (is_nil_uuid(hapd->conf->uuid)) {
const u8 *uuid;
uuid = get_own_uuid(hapd->iface);
- if (uuid) {
+ if (uuid && !conf->wps_independent) {
os_memcpy(wps->uuid, uuid, UUID_LEN);
wpa_hexdump(MSG_DEBUG, "WPS: Clone UUID from another "
"interface", wps->uuid, UUID_LEN);
@@ -959,6 +1075,9 @@
if (conf->ssid.security_policy == SECURITY_STATIC_WEP)
cfg.static_wep_only = 1;
cfg.dualband = interface_count(hapd->iface) > 1;
+ if ((wps->dev.rf_bands & (WPS_RF_50GHZ | WPS_RF_24GHZ)) ==
+ (WPS_RF_50GHZ | WPS_RF_24GHZ))
+ cfg.dualband = 1;
if (cfg.dualband)
wpa_printf(MSG_DEBUG, "WPS: Dualband AP");
@@ -1036,8 +1155,6 @@
wps_device_data_free(&hapd->wps->dev);
wpabuf_free(hapd->wps->dh_pubkey);
wpabuf_free(hapd->wps->dh_privkey);
- wpabuf_free(hapd->wps->oob_conf.pubkey_hash);
- wpabuf_free(hapd->wps->oob_conf.dev_password);
wps_free_pending_msgs(hapd->wps->upnp_msgs);
hostapd_wps_nfc_clear(hapd->wps);
os_free(hapd->wps);
@@ -1155,60 +1272,6 @@
}
-#ifdef CONFIG_WPS_OOB
-int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type,
- char *path, char *method, char *name)
-{
- struct wps_context *wps = hapd->wps;
- struct oob_device_data *oob_dev;
-
- oob_dev = wps_get_oob_device(device_type);
- if (oob_dev == NULL)
- return -1;
- oob_dev->device_path = path;
- oob_dev->device_name = name;
- wps->oob_conf.oob_method = wps_get_oob_method(method);
-
- if (wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_R) {
- /*
- * Use pre-configured DH keys in order to be able to write the
- * key hash into the OOB file.
- */
- wpabuf_free(wps->dh_pubkey);
- wpabuf_free(wps->dh_privkey);
- wps->dh_privkey = NULL;
- wps->dh_pubkey = dh_init(dh_groups_get(WPS_DH_GROUP),
- &wps->dh_privkey);
- wps->dh_pubkey = wpabuf_zeropad(wps->dh_pubkey, 192);
- if (wps->dh_pubkey == NULL) {
- wpa_printf(MSG_ERROR, "WPS: Failed to initialize "
- "Diffie-Hellman handshake");
- return -1;
- }
- }
-
- if (wps_process_oob(wps, oob_dev, 1) < 0)
- goto error;
-
- if ((wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_E ||
- wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_R) &&
- hostapd_wps_add_pin(hapd, NULL, "any",
- wpabuf_head(wps->oob_conf.dev_password), 0) <
- 0)
- goto error;
-
- return 0;
-
-error:
- wpabuf_free(wps->dh_pubkey);
- wps->dh_pubkey = NULL;
- wpabuf_free(wps->dh_privkey);
- wps->dh_privkey = NULL;
- return -1;
-}
-#endif /* CONFIG_WPS_OOB */
-
-
static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, const u8 *da,
const u8 *bssid,
const u8 *ie, size_t ie_len,
@@ -1638,8 +1701,25 @@
}
+struct wpabuf * hostapd_wps_nfc_hs_cr(struct hostapd_data *hapd, int ndef)
+{
+ /*
+ * Handover Select carrier record for WPS uses the same format as
+ * configuration token.
+ */
+ return hostapd_wps_nfc_config_token(hapd, ndef);
+}
+
+
struct wpabuf * hostapd_wps_nfc_token_gen(struct hostapd_data *hapd, int ndef)
{
+ if (hapd->conf->wps_nfc_pw_from_config) {
+ return wps_nfc_token_build(ndef,
+ hapd->conf->wps_nfc_dev_pw_id,
+ hapd->conf->wps_nfc_dh_pubkey,
+ hapd->conf->wps_nfc_dev_pw);
+ }
+
return wps_nfc_token_gen(ndef, &hapd->conf->wps_nfc_dev_pw_id,
&hapd->conf->wps_nfc_dh_pubkey,
&hapd->conf->wps_nfc_dh_privkey,
@@ -1650,6 +1730,7 @@
int hostapd_wps_nfc_token_enable(struct hostapd_data *hapd)
{
struct wps_context *wps = hapd->wps;
+ struct wpabuf *pw;
if (wps == NULL)
return -1;
@@ -1664,7 +1745,16 @@
wps->ap_nfc_dev_pw_id = hapd->conf->wps_nfc_dev_pw_id;
wps->ap_nfc_dh_pubkey = wpabuf_dup(hapd->conf->wps_nfc_dh_pubkey);
wps->ap_nfc_dh_privkey = wpabuf_dup(hapd->conf->wps_nfc_dh_privkey);
- wps->ap_nfc_dev_pw = wpabuf_dup(hapd->conf->wps_nfc_dev_pw);
+ pw = hapd->conf->wps_nfc_dev_pw;
+ wps->ap_nfc_dev_pw = wpabuf_alloc(
+ wpabuf_len(pw) * 2 + 1);
+ if (wps->ap_nfc_dev_pw) {
+ wpa_snprintf_hex_uppercase(
+ (char *) wpabuf_put(wps->ap_nfc_dev_pw,
+ wpabuf_len(pw) * 2),
+ wpabuf_len(pw) * 2 + 1,
+ wpabuf_head(pw), wpabuf_len(pw));
+ }
if (!wps->ap_nfc_dh_pubkey || !wps->ap_nfc_dh_privkey ||
!wps->ap_nfc_dev_pw) {
diff --git a/src/ap/wps_hostapd.h b/src/ap/wps_hostapd.h
index f968e15..a2c2cf0 100644
--- a/src/ap/wps_hostapd.h
+++ b/src/ap/wps_hostapd.h
@@ -21,8 +21,6 @@
int hostapd_wps_button_pushed(struct hostapd_data *hapd,
const u8 *p2p_dev_addr);
int hostapd_wps_cancel(struct hostapd_data *hapd);
-int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type,
- char *path, char *method, char *name);
int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr,
char *buf, size_t buflen);
void hostapd_wps_ap_pin_disable(struct hostapd_data *hapd);
@@ -37,6 +35,7 @@
const struct wpabuf *data);
struct wpabuf * hostapd_wps_nfc_config_token(struct hostapd_data *hapd,
int ndef);
+struct wpabuf * hostapd_wps_nfc_hs_cr(struct hostapd_data *hapd, int ndef);
struct wpabuf * hostapd_wps_nfc_token_gen(struct hostapd_data *hapd, int ndef);
int hostapd_wps_nfc_token_enable(struct hostapd_data *hapd);
void hostapd_wps_nfc_token_disable(struct hostapd_data *hapd);
diff --git a/src/common/defs.h b/src/common/defs.h
index db29b5d..281dd8a 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -27,6 +27,7 @@
#define WPA_CIPHER_AES_128_CMAC BIT(5)
#endif /* CONFIG_IEEE80211W */
#define WPA_CIPHER_GCMP BIT(6)
+#define WPA_CIPHER_SMS4 BIT(7)
#define WPA_KEY_MGMT_IEEE8021X BIT(0)
#define WPA_KEY_MGMT_PSK BIT(1)
@@ -38,11 +39,17 @@
#define WPA_KEY_MGMT_IEEE8021X_SHA256 BIT(7)
#define WPA_KEY_MGMT_PSK_SHA256 BIT(8)
#define WPA_KEY_MGMT_WPS BIT(9)
+#define WPA_KEY_MGMT_SAE BIT(10)
+#define WPA_KEY_MGMT_FT_SAE BIT(11)
+#define WPA_KEY_MGMT_WAPI_PSK BIT(12)
+#define WPA_KEY_MGMT_WAPI_CERT BIT(13)
+#define WPA_KEY_MGMT_CCKM BIT(14)
static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
{
return !!(akm & (WPA_KEY_MGMT_IEEE8021X |
WPA_KEY_MGMT_FT_IEEE8021X |
+ WPA_KEY_MGMT_CCKM |
WPA_KEY_MGMT_IEEE8021X_SHA256));
}
@@ -50,13 +57,21 @@
{
return !!(akm & (WPA_KEY_MGMT_PSK |
WPA_KEY_MGMT_FT_PSK |
- WPA_KEY_MGMT_PSK_SHA256));
+ WPA_KEY_MGMT_PSK_SHA256 |
+ WPA_KEY_MGMT_SAE));
}
static inline int wpa_key_mgmt_ft(int akm)
{
return !!(akm & (WPA_KEY_MGMT_FT_PSK |
- WPA_KEY_MGMT_FT_IEEE8021X));
+ WPA_KEY_MGMT_FT_IEEE8021X |
+ WPA_KEY_MGMT_FT_SAE));
+}
+
+static inline int wpa_key_mgmt_sae(int akm)
+{
+ return !!(akm & (WPA_KEY_MGMT_SAE |
+ WPA_KEY_MGMT_FT_SAE));
}
static inline int wpa_key_mgmt_sha256(int akm)
@@ -76,14 +91,21 @@
return wpa_key_mgmt_wpa(akm) || (akm & WPA_KEY_MGMT_WPA_NONE);
}
+static inline int wpa_key_mgmt_cckm(int akm)
+{
+ return akm == WPA_KEY_MGMT_CCKM;
+}
+
#define WPA_PROTO_WPA BIT(0)
#define WPA_PROTO_RSN BIT(1)
+#define WPA_PROTO_WAPI BIT(2)
#define WPA_AUTH_ALG_OPEN BIT(0)
#define WPA_AUTH_ALG_SHARED BIT(1)
#define WPA_AUTH_ALG_LEAP BIT(2)
#define WPA_AUTH_ALG_FT BIT(3)
+#define WPA_AUTH_ALG_SAE BIT(4)
enum wpa_alg {
@@ -93,7 +115,9 @@
WPA_ALG_CCMP,
WPA_ALG_IGTK,
WPA_ALG_PMK,
- WPA_ALG_GCMP
+ WPA_ALG_GCMP,
+ WPA_ALG_SMS4,
+ WPA_ALG_KRK
};
/**
@@ -105,7 +129,8 @@
CIPHER_TKIP,
CIPHER_CCMP,
CIPHER_WEP104,
- CIPHER_GCMP
+ CIPHER_GCMP,
+ CIPHER_SMS4
};
/**
@@ -121,7 +146,12 @@
KEY_MGMT_FT_PSK,
KEY_MGMT_802_1X_SHA256,
KEY_MGMT_PSK_SHA256,
- KEY_MGMT_WPS
+ KEY_MGMT_WPS,
+ KEY_MGMT_SAE,
+ KEY_MGMT_FT_SAE,
+ KEY_MGMT_WAPI_PSK,
+ KEY_MGMT_WAPI_CERT,
+ KEY_MGMT_CCKM
};
/**
@@ -256,8 +286,9 @@
enum mfp_options {
NO_MGMT_FRAME_PROTECTION = 0,
MGMT_FRAME_PROTECTION_OPTIONAL = 1,
- MGMT_FRAME_PROTECTION_REQUIRED = 2
+ MGMT_FRAME_PROTECTION_REQUIRED = 2,
};
+#define MGMT_FRAME_PROTECTION_DEFAULT 3
/**
* enum hostapd_hw_mode - Hardware mode
@@ -266,6 +297,7 @@
HOSTAPD_MODE_IEEE80211B,
HOSTAPD_MODE_IEEE80211G,
HOSTAPD_MODE_IEEE80211A,
+ HOSTAPD_MODE_IEEE80211AD,
NUM_HOSTAPD_MODES
};
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index d9d3cd0..98fadda 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -284,6 +284,10 @@
break;
elems->bss_max_idle_period = pos;
break;
+ case WLAN_EID_SSID_LIST:
+ elems->ssid_list = pos;
+ elems->ssid_list_len = elen;
+ break;
default:
unknown++;
if (!show_errors)
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index bfc3eb2..55fa49d 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -1,6 +1,6 @@
/*
* IEEE 802.11 Common routines
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2012, 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 @@
const u8 *hs20;
const u8 *ext_capab;
const u8 *bss_max_idle_period;
+ const u8 *ssid_list;
u8 ssid_len;
u8 supp_rates_len;
@@ -74,6 +75,7 @@
u8 interworking_len;
u8 hs20_len;
u8 ext_capab_len;
+ u8 ssid_list_len;
};
typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 2ab7fbf..f782c86 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -76,6 +76,7 @@
#define WLAN_AUTH_OPEN 0
#define WLAN_AUTH_SHARED_KEY 1
#define WLAN_AUTH_FT 2
+#define WLAN_AUTH_SAE 3
#define WLAN_AUTH_LEAP 128
#define WLAN_AUTH_CHALLENGE_LEN 128
@@ -157,6 +158,8 @@
#define WLAN_STATUS_REQ_REFUSED_SSPN 67
#define WLAN_STATUS_REQ_REFUSED_UNAUTH_ACCESS 68
#define WLAN_STATUS_INVALID_RSNIE 72
+#define WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ 76
+#define WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED 77
#define WLAN_STATUS_TRANSMISSION_FAILURE 79
/* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */
@@ -215,6 +218,7 @@
/* EIDs defined by IEEE 802.11h - END */
#define WLAN_EID_ERP_INFO 42
#define WLAN_EID_HT_CAP 45
+#define WLAN_EID_QOS 46
#define WLAN_EID_RSN 48
#define WLAN_EID_EXT_SUPP_RATES 50
#define WLAN_EID_MOBILITY_DOMAIN 54
@@ -223,11 +227,13 @@
#define WLAN_EID_RIC_DATA 57
#define WLAN_EID_HT_OPERATION 61
#define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62
+#define WLAN_EID_WAPI 68
#define WLAN_EID_TIME_ADVERTISEMENT 69
#define WLAN_EID_20_40_BSS_COEXISTENCE 72
#define WLAN_EID_20_40_BSS_INTOLERANT 73
#define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74
#define WLAN_EID_MMIE 76
+#define WLAN_EID_SSID_LIST 84
#define WLAN_EID_BSS_MAX_IDLE_PERIOD 90
#define WLAN_EID_TFS_REQ 91
#define WLAN_EID_TFS_RESP 92
@@ -238,6 +244,7 @@
#define WLAN_EID_ADV_PROTO 108
#define WLAN_EID_ROAMING_CONSORTIUM 111
#define WLAN_EID_EXT_CAPAB 127
+#define WLAN_EID_CCKM 156
#define WLAN_EID_VHT_CAP 191
#define WLAN_EID_VHT_OPERATION 192
#define WLAN_EID_VHT_EXTENDED_BSS_LOAD 193
@@ -532,6 +539,16 @@
* Entries */
u8 variable[0];
} STRUCT_PACKED bss_tm_req;
+ struct {
+ u8 action; /* 8 */
+ u8 dialog_token;
+ u8 status_code;
+ u8 bss_termination_delay;
+ /* Target BSSID (optional),
+ * BSS Transition Candidate List
+ * Entries (optional) */
+ u8 variable[0];
+ } STRUCT_PACKED bss_tm_resp;
} u;
} STRUCT_PACKED action;
} u;
@@ -562,7 +579,12 @@
struct ieee80211_vht_capabilities {
le32 vht_capabilities_info;
- u8 vht_supported_mcs_set[8];
+ struct {
+ le16 rx_map;
+ le16 rx_highest;
+ le16 tx_map;
+ le16 tx_highest;
+ } vht_supported_mcs_set;
} STRUCT_PACKED;
struct ieee80211_vht_operation {
@@ -666,6 +688,7 @@
#define HT_INFO_STBC_PARAM_PCO_ACTIVE ((u16) BIT(10))
#define HT_INFO_STBC_PARAM_PCO_PHASE ((u16) BIT(11))
+#define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
#define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
/* VHT Defines */
@@ -695,6 +718,12 @@
#define VHT_CAP_RX_ANTENNA_PATTERN ((u32) BIT(28))
#define VHT_CAP_TX_ANTENNA_PATTERN ((u32) BIT(29))
+/* VHT channel widths */
+#define VHT_CHANWIDTH_USE_HT 0
+#define VHT_CHANWIDTH_80MHZ 1
+#define VHT_CHANWIDTH_160MHZ 2
+#define VHT_CHANWIDTH_80P80MHZ 3
+
#define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs)
* 00:50:F2 */
#define WPA_IE_VENDOR_TYPE 0x0050f201
@@ -966,9 +995,19 @@
#define WLAN_CIPHER_SUITE_NO_GROUP_ADDR 0x000FAC07
#define WLAN_CIPHER_SUITE_GCMP 0x000FAC08
+#define WLAN_CIPHER_SUITE_SMS4 0x00147201
+
+#define WLAN_CIPHER_SUITE_CKIP 0x00409600
+#define WLAN_CIPHER_SUITE_CKIP_CMIC 0x00409601
+#define WLAN_CIPHER_SUITE_CMIC 0x00409602
+#define WLAN_CIPHER_SUITE_KRK 0x004096FF /* for nl80211 use only */
+
/* AKM suite selectors */
#define WLAN_AKM_SUITE_8021X 0x000FAC01
#define WLAN_AKM_SUITE_PSK 0x000FAC02
+#define WLAN_AKM_SUITE_FT_8021X 0x000FAC03
+#define WLAN_AKM_SUITE_FT_PSK 0x000FAC04
+#define WLAN_AKM_SUITE_CCKM 0x00409600
/* IEEE 802.11v - WNM Action field values */
@@ -1034,11 +1073,14 @@
struct wnm_sleep_element {
u8 eid; /* WLAN_EID_WNMSLEEP */
u8 len;
- u8 action_type; /* WLAN_WNM_SLEEP_ENTER/EXIT */
+ u8 action_type; /* WNM_SLEEP_ENTER/WNM_SLEEP_MODE_EXIT */
u8 status;
le16 intval;
} STRUCT_PACKED;
+#define WNM_SLEEP_MODE_ENTER 0
+#define WNM_SLEEP_MODE_EXIT 1
+
enum wnm_sleep_mode_response_status {
WNM_STATUS_SLEEP_ACCEPT = 0,
WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE = 1,
diff --git a/src/common/sae.c b/src/common/sae.c
new file mode 100644
index 0000000..bce60a3
--- /dev/null
+++ b/src/common/sae.c
@@ -0,0 +1,1042 @@
+/*
+ * Simultaneous authentication of equals
+ * Copyright (c) 2012-2013, 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 "crypto/crypto.h"
+#include "crypto/sha256.h"
+#include "crypto/random.h"
+#include "crypto/dh_groups.h"
+#include "ieee802_11_defs.h"
+#include "sae.h"
+
+
+int sae_set_group(struct sae_data *sae, int group)
+{
+ struct sae_temporary_data *tmp;
+
+ sae_clear_data(sae);
+ tmp = sae->tmp = os_zalloc(sizeof(*tmp));
+ if (tmp == NULL)
+ return -1;
+
+ /* First, check if this is an ECC group */
+ tmp->ec = crypto_ec_init(group);
+ if (tmp->ec) {
+ sae->group = group;
+ tmp->prime_len = crypto_ec_prime_len(tmp->ec);
+ tmp->prime = crypto_ec_get_prime(tmp->ec);
+ tmp->order = crypto_ec_get_order(tmp->ec);
+ return 0;
+ }
+
+ /* Not an ECC group, check FFC */
+ tmp->dh = dh_groups_get(group);
+ if (tmp->dh) {
+ sae->group = group;
+ tmp->prime_len = tmp->dh->prime_len;
+ if (tmp->prime_len > SAE_MAX_PRIME_LEN) {
+ sae_clear_data(sae);
+ return -1;
+ }
+
+ tmp->prime_buf = crypto_bignum_init_set(tmp->dh->prime,
+ tmp->prime_len);
+ if (tmp->prime_buf == NULL) {
+ sae_clear_data(sae);
+ return -1;
+ }
+ tmp->prime = tmp->prime_buf;
+
+ tmp->order_buf = crypto_bignum_init_set(tmp->dh->order,
+ tmp->dh->order_len);
+ if (tmp->order_buf == NULL) {
+ sae_clear_data(sae);
+ return -1;
+ }
+ tmp->order = tmp->order_buf;
+
+ return 0;
+ }
+
+ /* Unsupported group */
+ return -1;
+}
+
+
+void sae_clear_temp_data(struct sae_data *sae)
+{
+ struct sae_temporary_data *tmp;
+ if (sae == NULL || sae->tmp == NULL)
+ return;
+ tmp = sae->tmp;
+ crypto_ec_deinit(tmp->ec);
+ crypto_bignum_deinit(tmp->prime_buf, 0);
+ crypto_bignum_deinit(tmp->order_buf, 0);
+ crypto_bignum_deinit(tmp->sae_rand, 1);
+ crypto_bignum_deinit(tmp->pwe_ffc, 1);
+ crypto_bignum_deinit(tmp->own_commit_scalar, 0);
+ crypto_bignum_deinit(tmp->own_commit_element_ffc, 0);
+ crypto_bignum_deinit(tmp->peer_commit_element_ffc, 0);
+ 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);
+ sae->tmp = NULL;
+}
+
+
+void sae_clear_data(struct sae_data *sae)
+{
+ if (sae == NULL)
+ return;
+ sae_clear_temp_data(sae);
+ crypto_bignum_deinit(sae->peer_commit_scalar, 0);
+ os_memset(sae, 0, sizeof(*sae));
+}
+
+
+static void buf_shift_right(u8 *buf, size_t len, size_t bits)
+{
+ size_t i;
+ for (i = len - 1; i > 0; i--)
+ buf[i] = (buf[i - 1] << (8 - bits)) | (buf[i] >> bits);
+ buf[0] >>= bits;
+}
+
+
+static struct crypto_bignum * sae_get_rand(struct sae_data *sae)
+{
+ u8 val[SAE_MAX_PRIME_LEN];
+ int iter = 0;
+ struct crypto_bignum *bn = NULL;
+ int order_len_bits = crypto_bignum_bits(sae->tmp->order);
+ size_t order_len = (order_len_bits + 7) / 8;
+
+ if (order_len > sizeof(val))
+ return NULL;
+
+ for (;;) {
+ if (iter++ > 100)
+ return NULL;
+ if (random_get_bytes(val, order_len) < 0)
+ return NULL;
+ if (order_len_bits % 8)
+ buf_shift_right(val, order_len, 8 - order_len_bits % 8);
+ bn = crypto_bignum_init_set(val, order_len);
+ if (bn == NULL)
+ return NULL;
+ if (crypto_bignum_is_zero(bn) ||
+ crypto_bignum_is_one(bn) ||
+ crypto_bignum_cmp(bn, sae->tmp->order) >= 0)
+ continue;
+ break;
+ }
+
+ os_memset(val, 0, order_len);
+ return bn;
+}
+
+
+static struct crypto_bignum * sae_get_rand_and_mask(struct sae_data *sae)
+{
+ crypto_bignum_deinit(sae->tmp->sae_rand, 1);
+ sae->tmp->sae_rand = sae_get_rand(sae);
+ if (sae->tmp->sae_rand == NULL)
+ return NULL;
+ return sae_get_rand(sae);
+}
+
+
+static void sae_pwd_seed_key(const u8 *addr1, const u8 *addr2, u8 *key)
+{
+ wpa_printf(MSG_DEBUG, "SAE: PWE derivation - addr1=" MACSTR
+ " addr2=" MACSTR, MAC2STR(addr1), MAC2STR(addr2));
+ if (os_memcmp(addr1, addr2, ETH_ALEN) > 0) {
+ os_memcpy(key, addr1, ETH_ALEN);
+ os_memcpy(key + ETH_ALEN, addr2, ETH_ALEN);
+ } else {
+ os_memcpy(key, addr2, ETH_ALEN);
+ os_memcpy(key + ETH_ALEN, addr1, ETH_ALEN);
+ }
+}
+
+
+static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
+ struct crypto_ec_point *pwe)
+{
+ u8 pwd_value[SAE_MAX_ECC_PRIME_LEN], prime[SAE_MAX_ECC_PRIME_LEN];
+ struct crypto_bignum *x;
+ int y_bit;
+ size_t bits;
+
+ if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime),
+ sae->tmp->prime_len) < 0)
+ return -1;
+
+ wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
+
+ /* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */
+ bits = crypto_ec_prime_len_bits(sae->tmp->ec);
+ sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
+ prime, sae->tmp->prime_len, pwd_value, bits);
+ if (bits % 8)
+ buf_shift_right(pwd_value, sizeof(pwd_value), 8 - bits % 8);
+ wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value",
+ pwd_value, sae->tmp->prime_len);
+
+ if (os_memcmp(pwd_value, prime, sae->tmp->prime_len) >= 0)
+ return 0;
+
+ y_bit = pwd_seed[SHA256_MAC_LEN - 1] & 0x01;
+
+ x = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
+ if (x == NULL)
+ return -1;
+ if (crypto_ec_point_solve_y_coord(sae->tmp->ec, pwe, x, y_bit) < 0) {
+ crypto_bignum_deinit(x, 0);
+ wpa_printf(MSG_DEBUG, "SAE: No solution found");
+ return 0;
+ }
+ crypto_bignum_deinit(x, 0);
+
+ wpa_printf(MSG_DEBUG, "SAE: PWE found");
+
+ return 1;
+}
+
+
+static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed,
+ struct crypto_bignum *pwe)
+{
+ u8 pwd_value[SAE_MAX_PRIME_LEN];
+ size_t bits = sae->tmp->prime_len * 8;
+ u8 exp[1];
+ struct crypto_bignum *a, *b;
+ int res;
+
+ wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
+
+ /* pwd-value = KDF-z(pwd-seed, "SAE Hunting and Pecking", p) */
+ sha256_prf_bits(pwd_seed, SHA256_MAC_LEN, "SAE Hunting and Pecking",
+ sae->tmp->dh->prime, sae->tmp->prime_len, pwd_value,
+ bits);
+ if (bits % 8)
+ buf_shift_right(pwd_value, sizeof(pwd_value), 8 - bits % 8);
+ wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value", pwd_value,
+ sae->tmp->prime_len);
+
+ if (os_memcmp(pwd_value, sae->tmp->dh->prime, sae->tmp->prime_len) >= 0)
+ {
+ wpa_printf(MSG_DEBUG, "SAE: pwd-value >= p");
+ return 0;
+ }
+
+ /* PWE = pwd-value^((p-1)/r) modulo p */
+
+ a = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
+
+ if (sae->tmp->dh->safe_prime) {
+ /*
+ * r = (p-1)/2 for the group used here, so this becomes:
+ * PWE = pwd-value^2 modulo p
+ */
+ exp[0] = 2;
+ b = crypto_bignum_init_set(exp, sizeof(exp));
+ } else {
+ /* Calculate exponent: (p-1)/r */
+ exp[0] = 1;
+ b = crypto_bignum_init_set(exp, sizeof(exp));
+ if (b == NULL ||
+ crypto_bignum_sub(sae->tmp->prime, b, b) < 0 ||
+ crypto_bignum_div(b, sae->tmp->order, b) < 0) {
+ crypto_bignum_deinit(b, 0);
+ b = NULL;
+ }
+ }
+
+ if (a == NULL || b == NULL)
+ res = -1;
+ else
+ res = crypto_bignum_exptmod(a, b, sae->tmp->prime, pwe);
+
+ crypto_bignum_deinit(a, 0);
+ crypto_bignum_deinit(b, 0);
+
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Failed to calculate PWE");
+ return -1;
+ }
+
+ /* if (PWE > 1) --> found */
+ if (crypto_bignum_is_zero(pwe) || crypto_bignum_is_one(pwe)) {
+ wpa_printf(MSG_DEBUG, "SAE: PWE <= 1");
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG, "SAE: PWE found");
+ return 1;
+}
+
+
+static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
+ const u8 *addr2, const u8 *password,
+ size_t password_len)
+{
+ u8 counter, k = 4;
+ u8 addrs[2 * ETH_ALEN];
+ const u8 *addr[2];
+ size_t len[2];
+ int found = 0;
+ struct crypto_ec_point *pwe_tmp;
+
+ if (sae->tmp->pwe_ecc == NULL) {
+ sae->tmp->pwe_ecc = crypto_ec_point_init(sae->tmp->ec);
+ if (sae->tmp->pwe_ecc == NULL)
+ return -1;
+ }
+ pwe_tmp = crypto_ec_point_init(sae->tmp->ec);
+ if (pwe_tmp == NULL)
+ return -1;
+
+ wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
+ password, password_len);
+
+ /*
+ * H(salt, ikm) = HMAC-SHA256(salt, ikm)
+ * pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC),
+ * password || counter)
+ */
+ sae_pwd_seed_key(addr1, addr2, addrs);
+
+ addr[0] = password;
+ len[0] = password_len;
+ addr[1] = &counter;
+ len[1] = sizeof(counter);
+
+ /*
+ * Continue for at least k iterations to protect against side-channel
+ * attacks that attempt to determine the number of iterations required
+ * in the loop.
+ */
+ for (counter = 1; counter < k || !found; counter++) {
+ u8 pwd_seed[SHA256_MAC_LEN];
+ int res;
+
+ if (counter > 200) {
+ /* This should not happen in practice */
+ wpa_printf(MSG_DEBUG, "SAE: Failed to derive PWE");
+ break;
+ }
+
+ wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter);
+ if (hmac_sha256_vector(addrs, sizeof(addrs), 2, addr, len,
+ pwd_seed) < 0)
+ break;
+ res = sae_test_pwd_seed_ecc(sae, pwd_seed,
+ found ? pwe_tmp :
+ sae->tmp->pwe_ecc);
+ if (res < 0)
+ break;
+ if (res == 0)
+ continue;
+ if (found) {
+ wpa_printf(MSG_DEBUG, "SAE: Ignore this PWE (one was "
+ "already selected)");
+ } else {
+ wpa_printf(MSG_DEBUG, "SAE: Use this PWE");
+ found = 1;
+ }
+ }
+
+ crypto_ec_point_deinit(pwe_tmp, 1);
+
+ return found ? 0 : -1;
+}
+
+
+static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1,
+ const u8 *addr2, const u8 *password,
+ size_t password_len)
+{
+ u8 counter;
+ u8 addrs[2 * ETH_ALEN];
+ const u8 *addr[2];
+ size_t len[2];
+ int found = 0;
+
+ if (sae->tmp->pwe_ffc == NULL) {
+ sae->tmp->pwe_ffc = crypto_bignum_init();
+ if (sae->tmp->pwe_ffc == NULL)
+ return -1;
+ }
+
+ wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
+ password, password_len);
+
+ /*
+ * H(salt, ikm) = HMAC-SHA256(salt, ikm)
+ * pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC),
+ * password || counter)
+ */
+ sae_pwd_seed_key(addr1, addr2, addrs);
+
+ addr[0] = password;
+ len[0] = password_len;
+ addr[1] = &counter;
+ len[1] = sizeof(counter);
+
+ for (counter = 1; !found; counter++) {
+ u8 pwd_seed[SHA256_MAC_LEN];
+ int res;
+
+ if (counter > 200) {
+ /* This should not happen in practice */
+ wpa_printf(MSG_DEBUG, "SAE: Failed to derive PWE");
+ break;
+ }
+
+ wpa_printf(MSG_DEBUG, "SAE: counter = %u", counter);
+ if (hmac_sha256_vector(addrs, sizeof(addrs), 2, addr, len,
+ pwd_seed) < 0)
+ break;
+ res = sae_test_pwd_seed_ffc(sae, pwd_seed, sae->tmp->pwe_ffc);
+ if (res < 0)
+ break;
+ if (res > 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Use this PWE");
+ found = 1;
+ }
+ }
+
+ return found ? 0 : -1;
+}
+
+
+static int sae_derive_commit_element_ecc(struct sae_data *sae,
+ struct crypto_bignum *mask)
+{
+ /* COMMIT-ELEMENT = inverse(scalar-op(mask, PWE)) */
+ if (!sae->tmp->own_commit_element_ecc) {
+ sae->tmp->own_commit_element_ecc =
+ crypto_ec_point_init(sae->tmp->ec);
+ if (!sae->tmp->own_commit_element_ecc)
+ return -1;
+ }
+
+ if (crypto_ec_point_mul(sae->tmp->ec, sae->tmp->pwe_ecc, mask,
+ sae->tmp->own_commit_element_ecc) < 0 ||
+ crypto_ec_point_invert(sae->tmp->ec,
+ sae->tmp->own_commit_element_ecc) < 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Could not compute commit-element");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int sae_derive_commit_element_ffc(struct sae_data *sae,
+ struct crypto_bignum *mask)
+{
+ /* COMMIT-ELEMENT = inverse(scalar-op(mask, PWE)) */
+ if (!sae->tmp->own_commit_element_ffc) {
+ sae->tmp->own_commit_element_ffc = crypto_bignum_init();
+ if (!sae->tmp->own_commit_element_ffc)
+ return -1;
+ }
+
+ if (crypto_bignum_exptmod(sae->tmp->pwe_ffc, mask, sae->tmp->prime,
+ sae->tmp->own_commit_element_ffc) < 0 ||
+ crypto_bignum_inverse(sae->tmp->own_commit_element_ffc,
+ sae->tmp->prime,
+ sae->tmp->own_commit_element_ffc) < 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Could not compute commit-element");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int sae_derive_commit(struct sae_data *sae)
+{
+ struct crypto_bignum *mask;
+ int ret = -1;
+
+ mask = sae_get_rand_and_mask(sae);
+ if (mask == NULL) {
+ wpa_printf(MSG_DEBUG, "SAE: Could not get rand/mask");
+ return -1;
+ }
+
+ /* commit-scalar = (rand + mask) modulo r */
+ if (!sae->tmp->own_commit_scalar) {
+ sae->tmp->own_commit_scalar = crypto_bignum_init();
+ if (!sae->tmp->own_commit_scalar)
+ goto fail;
+ }
+ crypto_bignum_add(sae->tmp->sae_rand, mask,
+ sae->tmp->own_commit_scalar);
+ crypto_bignum_mod(sae->tmp->own_commit_scalar, sae->tmp->order,
+ sae->tmp->own_commit_scalar);
+
+ if (sae->tmp->ec && sae_derive_commit_element_ecc(sae, mask) < 0)
+ goto fail;
+ if (sae->tmp->dh && sae_derive_commit_element_ffc(sae, mask) < 0)
+ goto fail;
+
+ ret = 0;
+fail:
+ crypto_bignum_deinit(mask, 1);
+ return ret;
+}
+
+
+int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
+ const u8 *password, size_t password_len,
+ struct sae_data *sae)
+{
+ if (sae->tmp->ec && sae_derive_pwe_ecc(sae, addr1, addr2, password,
+ password_len) < 0)
+ return -1;
+ if (sae->tmp->dh && sae_derive_pwe_ffc(sae, addr1, addr2, password,
+ password_len) < 0)
+ return -1;
+ if (sae_derive_commit(sae) < 0)
+ return -1;
+ return 0;
+}
+
+
+static int sae_derive_k_ecc(struct sae_data *sae, u8 *k)
+{
+ struct crypto_ec_point *K;
+ int ret = -1;
+
+ K = crypto_ec_point_init(sae->tmp->ec);
+ if (K == NULL)
+ goto fail;
+
+ /*
+ * K = scalar-op(rand, (elem-op(scalar-op(peer-commit-scalar, PWE),
+ * PEER-COMMIT-ELEMENT)))
+ * If K is identity element (point-at-infinity), reject
+ * k = F(K) (= x coordinate)
+ */
+
+ if (crypto_ec_point_mul(sae->tmp->ec, sae->tmp->pwe_ecc,
+ sae->peer_commit_scalar, K) < 0 ||
+ crypto_ec_point_add(sae->tmp->ec, K,
+ sae->tmp->peer_commit_element_ecc, K) < 0 ||
+ crypto_ec_point_mul(sae->tmp->ec, K, sae->tmp->sae_rand, K) < 0 ||
+ crypto_ec_point_is_at_infinity(sae->tmp->ec, K) ||
+ crypto_ec_point_to_bin(sae->tmp->ec, K, k, NULL) < 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Failed to calculate K and k");
+ goto fail;
+ }
+
+ wpa_hexdump_key(MSG_DEBUG, "SAE: k", k, sae->tmp->prime_len);
+
+ ret = 0;
+fail:
+ crypto_ec_point_deinit(K, 1);
+ return ret;
+}
+
+
+static int sae_derive_k_ffc(struct sae_data *sae, u8 *k)
+{
+ struct crypto_bignum *K;
+ int ret = -1;
+
+ K = crypto_bignum_init();
+ if (K == NULL)
+ goto fail;
+
+ /*
+ * K = scalar-op(rand, (elem-op(scalar-op(peer-commit-scalar, PWE),
+ * PEER-COMMIT-ELEMENT)))
+ * If K is identity element (one), reject.
+ * k = F(K) (= x coordinate)
+ */
+
+ if (crypto_bignum_exptmod(sae->tmp->pwe_ffc, sae->peer_commit_scalar,
+ sae->tmp->prime, K) < 0 ||
+ crypto_bignum_mulmod(K, sae->tmp->peer_commit_element_ffc,
+ sae->tmp->prime, K) < 0 ||
+ crypto_bignum_exptmod(K, sae->tmp->sae_rand, sae->tmp->prime, K) < 0
+ ||
+ crypto_bignum_is_one(K) ||
+ crypto_bignum_to_bin(K, k, SAE_MAX_PRIME_LEN, sae->tmp->prime_len) <
+ 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Failed to calculate K and k");
+ goto fail;
+ }
+
+ wpa_hexdump_key(MSG_DEBUG, "SAE: k", k, sae->tmp->prime_len);
+
+ ret = 0;
+fail:
+ crypto_bignum_deinit(K, 1);
+ return ret;
+}
+
+
+static int sae_derive_keys(struct sae_data *sae, const u8 *k)
+{
+ u8 null_key[SAE_KEYSEED_KEY_LEN], val[SAE_MAX_PRIME_LEN];
+ u8 keyseed[SHA256_MAC_LEN];
+ u8 keys[SAE_KCK_LEN + SAE_PMK_LEN];
+ struct crypto_bignum *tmp;
+ int ret = -1;
+
+ tmp = crypto_bignum_init();
+ if (tmp == NULL)
+ goto fail;
+
+ /* keyseed = H(<0>32, k)
+ * KCK || PMK = KDF-512(keyseed, "SAE KCK and PMK",
+ * (commit-scalar + peer-commit-scalar) modulo r)
+ * PMKID = L((commit-scalar + peer-commit-scalar) modulo r, 0, 128)
+ */
+
+ os_memset(null_key, 0, sizeof(null_key));
+ hmac_sha256(null_key, sizeof(null_key), k, sae->tmp->prime_len,
+ keyseed);
+ wpa_hexdump_key(MSG_DEBUG, "SAE: keyseed", keyseed, sizeof(keyseed));
+
+ crypto_bignum_add(sae->tmp->own_commit_scalar, sae->peer_commit_scalar,
+ tmp);
+ crypto_bignum_mod(tmp, sae->tmp->order, tmp);
+ crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->prime_len);
+ wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_LEN);
+ sha256_prf(keyseed, sizeof(keyseed), "SAE KCK and PMK",
+ val, sae->tmp->prime_len, keys, sizeof(keys));
+ os_memcpy(sae->tmp->kck, keys, SAE_KCK_LEN);
+ os_memcpy(sae->pmk, keys + SAE_KCK_LEN, SAE_PMK_LEN);
+ 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);
+
+ ret = 0;
+fail:
+ crypto_bignum_deinit(tmp, 0);
+ return ret;
+}
+
+
+int sae_process_commit(struct sae_data *sae)
+{
+ u8 k[SAE_MAX_PRIME_LEN];
+ if ((sae->tmp->ec && sae_derive_k_ecc(sae, k) < 0) ||
+ (sae->tmp->dh && sae_derive_k_ffc(sae, k) < 0) ||
+ sae_derive_keys(sae, k) < 0)
+ return -1;
+ return 0;
+}
+
+
+void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
+ const struct wpabuf *token)
+{
+ u8 *pos;
+ wpabuf_put_le16(buf, sae->group); /* Finite Cyclic Group */
+ if (token)
+ wpabuf_put_buf(buf, 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);
+ wpa_hexdump(MSG_DEBUG, "SAE: own commit-scalar",
+ pos, sae->tmp->prime_len);
+ if (sae->tmp->ec) {
+ pos = wpabuf_put(buf, 2 * sae->tmp->prime_len);
+ crypto_ec_point_to_bin(sae->tmp->ec,
+ sae->tmp->own_commit_element_ecc,
+ pos, pos + sae->tmp->prime_len);
+ wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(x)",
+ pos, sae->tmp->prime_len);
+ wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(y)",
+ pos + sae->tmp->prime_len, sae->tmp->prime_len);
+ } else {
+ pos = wpabuf_put(buf, sae->tmp->prime_len);
+ crypto_bignum_to_bin(sae->tmp->own_commit_element_ffc, pos,
+ sae->tmp->prime_len, sae->tmp->prime_len);
+ wpa_hexdump(MSG_DEBUG, "SAE: own commit-element",
+ pos, sae->tmp->prime_len);
+ }
+}
+
+
+static u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups,
+ u16 group)
+{
+ if (allowed_groups) {
+ int i;
+ for (i = 0; allowed_groups[i] >= 0; i++) {
+ if (allowed_groups[i] == group)
+ break;
+ }
+ if (allowed_groups[i] != group) {
+ wpa_printf(MSG_DEBUG, "SAE: Proposed group %u not "
+ "enabled in the current configuration",
+ group);
+ return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
+ }
+ }
+
+ if (sae->state == SAE_COMMITTED && group != sae->group) {
+ wpa_printf(MSG_DEBUG, "SAE: Do not allow group to be changed");
+ return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
+ }
+
+ if (group != sae->group && sae_set_group(sae, group) < 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Unsupported Finite Cyclic Group %u",
+ group);
+ return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
+ }
+
+ if (sae->tmp->dh && !allowed_groups) {
+ wpa_printf(MSG_DEBUG, "SAE: Do not allow FFC group %u without "
+ "explicit configuration enabling it", group);
+ return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
+ }
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos,
+ const u8 *end, const u8 **token,
+ size_t *token_len)
+{
+ if (*pos + (sae->tmp->ec ? 3 : 2) * sae->tmp->prime_len < end) {
+ size_t tlen = end - (*pos + (sae->tmp->ec ? 3 : 2) *
+ sae->tmp->prime_len);
+ wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token", *pos, tlen);
+ if (token)
+ *token = *pos;
+ if (token_len)
+ *token_len = tlen;
+ *pos += tlen;
+ } else {
+ if (token)
+ *token = NULL;
+ if (token_len)
+ *token_len = 0;
+ }
+}
+
+
+static u16 sae_parse_commit_scalar(struct sae_data *sae, const u8 **pos,
+ const u8 *end)
+{
+ struct crypto_bignum *peer_scalar;
+
+ if (*pos + sae->tmp->prime_len > end) {
+ wpa_printf(MSG_DEBUG, "SAE: Not enough data for scalar");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ peer_scalar = crypto_bignum_init_set(*pos, sae->tmp->prime_len);
+ if (peer_scalar == NULL)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+ /*
+ * IEEE Std 802.11-2012, 11.3.8.6.1: If there is a protocol instance for
+ * the peer and it is in Authenticated state, the new Commit Message
+ * shall be dropped if the peer-scalar is identical to the one used in
+ * the existing protocol instance.
+ */
+ if (sae->state == SAE_ACCEPTED && sae->peer_commit_scalar &&
+ crypto_bignum_cmp(sae->peer_commit_scalar, peer_scalar) == 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Do not accept re-use of previous "
+ "peer-commit-scalar");
+ crypto_bignum_deinit(peer_scalar, 0);
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ /* 0 < scalar < r */
+ if (crypto_bignum_is_zero(peer_scalar) ||
+ crypto_bignum_cmp(peer_scalar, sae->tmp->order) >= 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Invalid peer scalar");
+ crypto_bignum_deinit(peer_scalar, 0);
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+
+ crypto_bignum_deinit(sae->peer_commit_scalar, 0);
+ sae->peer_commit_scalar = peer_scalar;
+ wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-scalar",
+ *pos, sae->tmp->prime_len);
+ *pos += sae->tmp->prime_len;
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 *pos,
+ const u8 *end)
+{
+ u8 prime[SAE_MAX_ECC_PRIME_LEN];
+
+ if (pos + 2 * sae->tmp->prime_len > end) {
+ wpa_printf(MSG_DEBUG, "SAE: Not enough data for "
+ "commit-element");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime),
+ sae->tmp->prime_len) < 0)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+ /* element x and y coordinates < p */
+ if (os_memcmp(pos, prime, sae->tmp->prime_len) >= 0 ||
+ os_memcmp(pos + sae->tmp->prime_len + sae->tmp->prime_len, prime,
+ sae->tmp->prime_len) >= 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Invalid coordinates in peer "
+ "element");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(x)",
+ pos, sae->tmp->prime_len);
+ wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element(y)",
+ pos + sae->tmp->prime_len, sae->tmp->prime_len);
+
+ crypto_ec_point_deinit(sae->tmp->peer_commit_element_ecc, 0);
+ sae->tmp->peer_commit_element_ecc =
+ crypto_ec_point_from_bin(sae->tmp->ec, pos);
+ if (sae->tmp->peer_commit_element_ecc == NULL)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+ if (!crypto_ec_point_is_on_curve(sae->tmp->ec,
+ sae->tmp->peer_commit_element_ecc)) {
+ wpa_printf(MSG_DEBUG, "SAE: Peer element is not on curve");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+static u16 sae_parse_commit_element_ffc(struct sae_data *sae, const u8 *pos,
+ const u8 *end)
+{
+ struct crypto_bignum *res;
+
+ if (pos + sae->tmp->prime_len > end) {
+ wpa_printf(MSG_DEBUG, "SAE: Not enough data for "
+ "commit-element");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+ wpa_hexdump(MSG_DEBUG, "SAE: Peer commit-element", pos,
+ sae->tmp->prime_len);
+
+ crypto_bignum_deinit(sae->tmp->peer_commit_element_ffc, 0);
+ sae->tmp->peer_commit_element_ffc =
+ crypto_bignum_init_set(pos, sae->tmp->prime_len);
+ if (sae->tmp->peer_commit_element_ffc == NULL)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ if (crypto_bignum_is_zero(sae->tmp->peer_commit_element_ffc) ||
+ crypto_bignum_is_one(sae->tmp->peer_commit_element_ffc) ||
+ crypto_bignum_cmp(sae->tmp->peer_commit_element_ffc,
+ sae->tmp->prime) >= 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Invalid peer element");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ /* scalar-op(r, ELEMENT) = 1 modulo p */
+ res = crypto_bignum_init();
+ if (res == NULL ||
+ crypto_bignum_exptmod(sae->tmp->peer_commit_element_ffc,
+ sae->tmp->order, sae->tmp->prime, res) < 0 ||
+ !crypto_bignum_is_one(res)) {
+ wpa_printf(MSG_DEBUG, "SAE: Invalid peer element (scalar-op)");
+ crypto_bignum_deinit(res, 0);
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+ crypto_bignum_deinit(res, 0);
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+static u16 sae_parse_commit_element(struct sae_data *sae, const u8 *pos,
+ const u8 *end)
+{
+ if (sae->tmp->dh)
+ return sae_parse_commit_element_ffc(sae, pos, end);
+ return sae_parse_commit_element_ecc(sae, pos, end);
+}
+
+
+u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
+ const u8 **token, size_t *token_len, int *allowed_groups)
+{
+ const u8 *pos = data, *end = data + len;
+ u16 res;
+
+ /* Check Finite Cyclic Group */
+ if (pos + 2 > end)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ res = sae_group_allowed(sae, allowed_groups, WPA_GET_LE16(pos));
+ if (res != WLAN_STATUS_SUCCESS)
+ return res;
+ pos += 2;
+
+ /* Optional Anti-Clogging Token */
+ sae_parse_commit_token(sae, &pos, end, token, token_len);
+
+ /* commit-scalar */
+ res = sae_parse_commit_scalar(sae, &pos, end);
+ if (res != WLAN_STATUS_SUCCESS)
+ return res;
+
+ /* commit-element */
+ return sae_parse_commit_element(sae, pos, end);
+}
+
+
+static void sae_cn_confirm(struct sae_data *sae, const u8 *sc,
+ const struct crypto_bignum *scalar1,
+ const u8 *element1, size_t element1_len,
+ const struct crypto_bignum *scalar2,
+ const u8 *element2, size_t element2_len,
+ u8 *confirm)
+{
+ const u8 *addr[5];
+ size_t len[5];
+ u8 scalar_b1[SAE_MAX_PRIME_LEN], scalar_b2[SAE_MAX_PRIME_LEN];
+
+ /* Confirm
+ * CN(key, X, Y, Z, ...) =
+ * HMAC-SHA256(key, D2OS(X) || D2OS(Y) || D2OS(Z) | ...)
+ * confirm = CN(KCK, send-confirm, commit-scalar, COMMIT-ELEMENT,
+ * peer-commit-scalar, PEER-COMMIT-ELEMENT)
+ * verifier = CN(KCK, peer-send-confirm, peer-commit-scalar,
+ * PEER-COMMIT-ELEMENT, commit-scalar, COMMIT-ELEMENT)
+ */
+ addr[0] = sc;
+ len[0] = 2;
+ crypto_bignum_to_bin(scalar1, scalar_b1, sizeof(scalar_b1),
+ sae->tmp->prime_len);
+ addr[1] = scalar_b1;
+ len[1] = sae->tmp->prime_len;
+ addr[2] = element1;
+ len[2] = element1_len;
+ crypto_bignum_to_bin(scalar2, scalar_b2, sizeof(scalar_b2),
+ sae->tmp->prime_len);
+ addr[3] = scalar_b2;
+ len[3] = sae->tmp->prime_len;
+ addr[4] = element2;
+ len[4] = element2_len;
+ hmac_sha256_vector(sae->tmp->kck, sizeof(sae->tmp->kck), 5, addr, len,
+ confirm);
+}
+
+
+static void sae_cn_confirm_ecc(struct sae_data *sae, const u8 *sc,
+ const struct crypto_bignum *scalar1,
+ const struct crypto_ec_point *element1,
+ const struct crypto_bignum *scalar2,
+ const struct crypto_ec_point *element2,
+ u8 *confirm)
+{
+ u8 element_b1[2 * SAE_MAX_ECC_PRIME_LEN];
+ u8 element_b2[2 * SAE_MAX_ECC_PRIME_LEN];
+
+ crypto_ec_point_to_bin(sae->tmp->ec, element1, element_b1,
+ element_b1 + sae->tmp->prime_len);
+ crypto_ec_point_to_bin(sae->tmp->ec, element2, element_b2,
+ element_b2 + sae->tmp->prime_len);
+
+ sae_cn_confirm(sae, sc, scalar1, element_b1, 2 * sae->tmp->prime_len,
+ scalar2, element_b2, 2 * sae->tmp->prime_len, confirm);
+}
+
+
+static void sae_cn_confirm_ffc(struct sae_data *sae, const u8 *sc,
+ const struct crypto_bignum *scalar1,
+ const struct crypto_bignum *element1,
+ const struct crypto_bignum *scalar2,
+ const struct crypto_bignum *element2,
+ u8 *confirm)
+{
+ u8 element_b1[SAE_MAX_PRIME_LEN];
+ u8 element_b2[SAE_MAX_PRIME_LEN];
+
+ crypto_bignum_to_bin(element1, element_b1, sizeof(element_b1),
+ sae->tmp->prime_len);
+ crypto_bignum_to_bin(element2, element_b2, sizeof(element_b2),
+ sae->tmp->prime_len);
+
+ sae_cn_confirm(sae, sc, scalar1, element_b1, sae->tmp->prime_len,
+ scalar2, element_b2, sae->tmp->prime_len, confirm);
+}
+
+
+void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf)
+{
+ const u8 *sc;
+
+ /* Send-Confirm */
+ sc = wpabuf_put(buf, 0);
+ wpabuf_put_le16(buf, sae->send_confirm);
+ sae->send_confirm++;
+
+ if (sae->tmp->ec)
+ sae_cn_confirm_ecc(sae, sc, sae->tmp->own_commit_scalar,
+ sae->tmp->own_commit_element_ecc,
+ sae->peer_commit_scalar,
+ sae->tmp->peer_commit_element_ecc,
+ wpabuf_put(buf, SHA256_MAC_LEN));
+ else
+ sae_cn_confirm_ffc(sae, sc, sae->tmp->own_commit_scalar,
+ sae->tmp->own_commit_element_ffc,
+ sae->peer_commit_scalar,
+ sae->tmp->peer_commit_element_ffc,
+ wpabuf_put(buf, SHA256_MAC_LEN));
+}
+
+
+int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len)
+{
+ u8 verifier[SHA256_MAC_LEN];
+
+ if (len < 2 + SHA256_MAC_LEN) {
+ wpa_printf(MSG_DEBUG, "SAE: Too short confirm message");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", WPA_GET_LE16(data));
+
+ if (sae->tmp->ec)
+ sae_cn_confirm_ecc(sae, data, sae->peer_commit_scalar,
+ sae->tmp->peer_commit_element_ecc,
+ sae->tmp->own_commit_scalar,
+ sae->tmp->own_commit_element_ecc,
+ verifier);
+ else
+ sae_cn_confirm_ffc(sae, data, sae->peer_commit_scalar,
+ sae->tmp->peer_commit_element_ffc,
+ sae->tmp->own_commit_scalar,
+ sae->tmp->own_commit_element_ffc,
+ verifier);
+
+ if (os_memcmp(verifier, data + 2, SHA256_MAC_LEN) != 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Confirm mismatch");
+ wpa_hexdump(MSG_DEBUG, "SAE: Received confirm",
+ data + 2, SHA256_MAC_LEN);
+ wpa_hexdump(MSG_DEBUG, "SAE: Calculated verifier",
+ verifier, SHA256_MAC_LEN);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/common/sae.h b/src/common/sae.h
new file mode 100644
index 0000000..d82a98e
--- /dev/null
+++ b/src/common/sae.h
@@ -0,0 +1,64 @@
+/*
+ * Simultaneous authentication of equals
+ * Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SAE_H
+#define SAE_H
+
+#define SAE_KCK_LEN 32
+#define SAE_PMK_LEN 32
+#define SAE_PMKID_LEN 16
+#define SAE_KEYSEED_KEY_LEN 32
+#define SAE_MAX_PRIME_LEN 512
+#define SAE_MAX_ECC_PRIME_LEN 66
+#define SAE_COMMIT_MAX_LEN (2 + 3 * SAE_MAX_PRIME_LEN)
+#define SAE_CONFIRM_MAX_LEN (2 + SAE_MAX_PRIME_LEN)
+
+struct sae_temporary_data {
+ u8 kck[SAE_KCK_LEN];
+ struct crypto_bignum *own_commit_scalar;
+ struct crypto_bignum *own_commit_element_ffc;
+ struct crypto_ec_point *own_commit_element_ecc;
+ struct crypto_bignum *peer_commit_element_ffc;
+ struct crypto_ec_point *peer_commit_element_ecc;
+ struct crypto_ec_point *pwe_ecc;
+ struct crypto_bignum *pwe_ffc;
+ struct crypto_bignum *sae_rand;
+ struct crypto_ec *ec;
+ int prime_len;
+ const struct dh_group *dh;
+ const struct crypto_bignum *prime;
+ const struct crypto_bignum *order;
+ struct crypto_bignum *prime_buf;
+ struct crypto_bignum *order_buf;
+};
+
+struct sae_data {
+ enum { SAE_NOTHING, SAE_COMMITTED, SAE_CONFIRMED, SAE_ACCEPTED } state;
+ u16 send_confirm;
+ u8 pmk[SAE_PMK_LEN];
+ struct crypto_bignum *peer_commit_scalar;
+ int group;
+ struct sae_temporary_data *tmp;
+};
+
+int sae_set_group(struct sae_data *sae, int group);
+void sae_clear_temp_data(struct sae_data *sae);
+void sae_clear_data(struct sae_data *sae);
+
+int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
+ const u8 *password, size_t password_len,
+ struct sae_data *sae);
+int sae_process_commit(struct sae_data *sae);
+void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
+ const struct wpabuf *token);
+u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
+ 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);
+
+#endif /* SAE_H */
diff --git a/src/common/version.h b/src/common/version.h
index 7afba48..2faa8c7 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.0-devel" VERSION_STR_POSTFIX
+#define VERSION_STR "2.1-devel" VERSION_STR_POSTFIX
#endif /* VERSION_H */
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index 36c308a..a8cf6be 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -1,6 +1,6 @@
/*
* WPA/RSN - Shared functions for supplicant and authenticator
- * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -376,6 +376,12 @@
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256)
return WPA_KEY_MGMT_PSK_SHA256;
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE)
+ return WPA_KEY_MGMT_SAE;
+ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_SAE)
+ return WPA_KEY_MGMT_FT_SAE;
+#endif /* CONFIG_SAE */
return 0;
}
#endif /* CONFIG_NO_WPA2 */
@@ -1126,6 +1132,26 @@
}
+enum wpa_cipher wpa_cipher_to_suite_driver(int cipher)
+{
+ switch (cipher) {
+ case WPA_CIPHER_NONE:
+ return CIPHER_NONE;
+ case WPA_CIPHER_WEP40:
+ return CIPHER_WEP40;
+ case WPA_CIPHER_WEP104:
+ return CIPHER_WEP104;
+ case WPA_CIPHER_CCMP:
+ return CIPHER_CCMP;
+ case WPA_CIPHER_GCMP:
+ return CIPHER_GCMP;
+ case WPA_CIPHER_TKIP:
+ default:
+ return CIPHER_TKIP;
+ }
+}
+
+
int wpa_cipher_valid_pairwise(int cipher)
{
return cipher == WPA_CIPHER_CCMP ||
@@ -1208,3 +1234,150 @@
return num_suites;
}
+
+
+int wpa_pick_pairwise_cipher(int ciphers, int none_allowed)
+{
+ if (ciphers & WPA_CIPHER_CCMP)
+ return WPA_CIPHER_CCMP;
+ if (ciphers & WPA_CIPHER_GCMP)
+ return WPA_CIPHER_GCMP;
+ if (ciphers & WPA_CIPHER_TKIP)
+ return WPA_CIPHER_TKIP;
+ if (none_allowed && (ciphers & WPA_CIPHER_NONE))
+ return WPA_CIPHER_NONE;
+ return -1;
+}
+
+
+int wpa_pick_group_cipher(int ciphers)
+{
+ if (ciphers & WPA_CIPHER_CCMP)
+ return WPA_CIPHER_CCMP;
+ if (ciphers & WPA_CIPHER_GCMP)
+ return WPA_CIPHER_GCMP;
+ if (ciphers & WPA_CIPHER_TKIP)
+ return WPA_CIPHER_TKIP;
+ if (ciphers & WPA_CIPHER_WEP104)
+ return WPA_CIPHER_WEP104;
+ if (ciphers & WPA_CIPHER_WEP40)
+ return WPA_CIPHER_WEP40;
+ return -1;
+}
+
+
+int wpa_parse_cipher(const char *value)
+{
+ int val = 0, last;
+ char *start, *end, *buf;
+
+ buf = os_strdup(value);
+ if (buf == NULL)
+ return -1;
+ start = buf;
+
+ while (*start != '\0') {
+ while (*start == ' ' || *start == '\t')
+ start++;
+ if (*start == '\0')
+ break;
+ end = start;
+ while (*end != ' ' && *end != '\t' && *end != '\0')
+ end++;
+ last = *end == '\0';
+ *end = '\0';
+ if (os_strcmp(start, "CCMP") == 0)
+ val |= WPA_CIPHER_CCMP;
+ else if (os_strcmp(start, "GCMP") == 0)
+ val |= WPA_CIPHER_GCMP;
+ else if (os_strcmp(start, "TKIP") == 0)
+ val |= WPA_CIPHER_TKIP;
+ else if (os_strcmp(start, "WEP104") == 0)
+ val |= WPA_CIPHER_WEP104;
+ else if (os_strcmp(start, "WEP40") == 0)
+ val |= WPA_CIPHER_WEP40;
+ else if (os_strcmp(start, "NONE") == 0)
+ val |= WPA_CIPHER_NONE;
+ else {
+ os_free(buf);
+ return -1;
+ }
+
+ if (last)
+ break;
+ start = end + 1;
+ }
+ os_free(buf);
+
+ return val;
+}
+
+
+int wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim)
+{
+ char *pos = start;
+ int ret;
+
+ if (ciphers & WPA_CIPHER_CCMP) {
+ ret = os_snprintf(pos, end - pos, "%sCCMP",
+ pos == start ? "" : delim);
+ if (ret < 0 || ret >= end - pos)
+ 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)
+ 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)
+ 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)
+ 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)
+ 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)
+ return -1;
+ pos += ret;
+ }
+
+ return pos - start;
+}
+
+
+int wpa_select_ap_group_cipher(int wpa, int wpa_pairwise, int rsn_pairwise)
+{
+ int pairwise = 0;
+
+ /* Select group cipher based on the enabled pairwise cipher suites */
+ if (wpa & 1)
+ pairwise |= wpa_pairwise;
+ if (wpa & 2)
+ pairwise |= rsn_pairwise;
+
+ if (pairwise & WPA_CIPHER_TKIP)
+ return WPA_CIPHER_TKIP;
+ if ((pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) == WPA_CIPHER_GCMP)
+ return WPA_CIPHER_GCMP;
+ return WPA_CIPHER_CCMP;
+}
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index 603166b..2d63662 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -1,6 +1,6 @@
/*
* WPA definitions shared between hostapd and wpa_supplicant
- * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -20,6 +20,12 @@
#define WPA_GMK_LEN 32
#define WPA_GTK_MAX_LEN 32
+#define WPA_ALLOWED_PAIRWISE_CIPHERS \
+(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | WPA_CIPHER_NONE)
+#define WPA_ALLOWED_GROUP_CIPHERS \
+(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | WPA_CIPHER_WEP104 | \
+WPA_CIPHER_WEP40)
+
#define WPA_SELECTOR_LEN 4
#define WPA_VERSION 1
#define RSN_SELECTOR_LEN 4
@@ -32,6 +38,7 @@
#define WPA_AUTH_KEY_MGMT_NONE RSN_SELECTOR(0x00, 0x50, 0xf2, 0)
#define WPA_AUTH_KEY_MGMT_UNSPEC_802_1X RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
#define WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X RSN_SELECTOR(0x00, 0x50, 0xf2, 2)
+#define WPA_AUTH_KEY_MGMT_CCKM RSN_SELECTOR(0x00, 0x40, 0x96, 0)
#define WPA_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x50, 0xf2, 0)
#define WPA_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
#define WPA_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x50, 0xf2, 2)
@@ -51,6 +58,9 @@
#define RSN_AUTH_KEY_MGMT_802_1X_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
#define RSN_AUTH_KEY_MGMT_PSK_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
#define RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
+#define RSN_AUTH_KEY_MGMT_SAE RSN_SELECTOR(0x00, 0x0f, 0xac, 8)
+#define RSN_AUTH_KEY_MGMT_FT_SAE RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
+#define RSN_AUTH_KEY_MGMT_CCKM RSN_SELECTOR(0x00, 0x40, 0x96, 0x00)
#define RSN_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x0f, 0xac, 0)
#define RSN_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
@@ -382,9 +392,15 @@
int wpa_cipher_key_len(int cipher);
int wpa_cipher_rsc_len(int cipher);
int wpa_cipher_to_alg(int cipher);
+enum wpa_cipher wpa_cipher_to_suite_driver(int cipher);
int wpa_cipher_valid_pairwise(int cipher);
u32 wpa_cipher_to_suite(int proto, int cipher);
int rsn_cipher_put_suites(u8 *pos, int ciphers);
int wpa_cipher_put_suites(u8 *pos, int ciphers);
+int wpa_pick_pairwise_cipher(int ciphers, int none_allowed);
+int wpa_pick_group_cipher(int ciphers);
+int wpa_parse_cipher(const char *value);
+int wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim);
+int wpa_select_ap_group_cipher(int wpa, int wpa_pairwise, int rsn_pairwise);
#endif /* WPA_COMMON_H */
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 84f1195..dbabe8c 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -150,10 +150,12 @@
#define AP_STA_CONNECTED "AP-STA-CONNECTED "
#define AP_STA_DISCONNECTED "AP-STA-DISCONNECTED "
+#define AP_REJECTED_MAX_STA "AP-REJECTED-MAX-STA "
+#define AP_REJECTED_BLOCKED_STA "AP-REJECTED-BLOCKED-STA "
/* BSS command information masks */
-#define WPA_BSS_MASK_ALL 0xFFFFFFFF
+#define WPA_BSS_MASK_ALL 0xFFFDFFFF
#define WPA_BSS_MASK_ID BIT(0)
#define WPA_BSS_MASK_BSSID BIT(1)
#define WPA_BSS_MASK_FREQ BIT(2)
@@ -171,6 +173,7 @@
#define WPA_BSS_MASK_P2P_SCAN BIT(14)
#define WPA_BSS_MASK_INTERNETW BIT(15)
#define WPA_BSS_MASK_WIFI_DISPLAY BIT(16)
+#define WPA_BSS_MASK_DELIM BIT(17)
/* wpa_supplicant/hostapd control interface access */
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index 26b9acf..9bccaaa 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / wrapper functions for crypto libraries
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Wrapper functions for crypto libraries
+ * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -457,4 +457,329 @@
*/
int crypto_get_random(void *buf, size_t len);
+
+/**
+ * struct crypto_bignum - bignum
+ *
+ * Internal data structure for bignum implementation. The contents is specific
+ * to the used crypto library.
+ */
+struct crypto_bignum;
+
+/**
+ * crypto_bignum_init - Allocate memory for bignum
+ * Returns: Pointer to allocated bignum or %NULL on failure
+ */
+struct crypto_bignum * crypto_bignum_init(void);
+
+/**
+ * crypto_bignum_init_set - Allocate memory for bignum and set the value
+ * @buf: Buffer with unsigned binary value
+ * @len: Length of buf in octets
+ * Returns: Pointer to allocated bignum or %NULL on failure
+ */
+struct crypto_bignum * crypto_bignum_init_set(const u8 *buf, size_t len);
+
+/**
+ * crypto_bignum_deinit - Free bignum
+ * @n: Bignum from crypto_bignum_init() or crypto_bignum_init_set()
+ * @clear: Whether to clear the value from memory
+ */
+void crypto_bignum_deinit(struct crypto_bignum *n, int clear);
+
+/**
+ * crypto_bignum_to_bin - Set binary buffer to unsigned bignum
+ * @a: Bignum
+ * @buf: Buffer for the binary number
+ * @len: Length of @buf in octets
+ * @padlen: Length in octets to pad the result to or 0 to indicate no padding
+ * Returns: Number of octets written on success, -1 on failure
+ */
+int crypto_bignum_to_bin(const struct crypto_bignum *a,
+ u8 *buf, size_t buflen, size_t padlen);
+
+/**
+ * crypto_bignum_add - c = a + b
+ * @a: Bignum
+ * @b: Bignum
+ * @c: Bignum; used to store the result of a + b
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_add(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c);
+
+/**
+ * crypto_bignum_mod - c = a % b
+ * @a: Bignum
+ * @b: Bignum
+ * @c: Bignum; used to store the result of a % b
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_mod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c);
+
+/**
+ * crypto_bignum_exptmod - Modular exponentiation: d = a^b (mod c)
+ * @a: Bignum; base
+ * @b: Bignum; exponent
+ * @c: Bignum; modulus
+ * @d: Bignum; used to store the result of a^b (mod c)
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_exptmod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ const struct crypto_bignum *c,
+ struct crypto_bignum *d);
+
+/**
+ * crypto_bignum_rshift - b = a >> n
+ * @a: Bignum
+ * @n: Number of bits to shift
+ * @b: Bignum; used to store the result of a >> n
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_rshift(const struct crypto_bignum *a, int n,
+ struct crypto_bignum *b);
+
+/**
+ * crypto_bignum_inverse - Inverse a bignum so that a * c = 1 (mod b)
+ * @a: Bignum
+ * @b: Bignum
+ * @c: Bignum; used to store the result
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_inverse(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c);
+
+/**
+ * crypto_bignum_sub - c = a - b
+ * @a: Bignum
+ * @b: Bignum
+ * @c: Bignum; used to store the result of a - b
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_sub(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c);
+
+/**
+ * crypto_bignum_div - c = a / b
+ * @a: Bignum
+ * @b: Bignum
+ * @c: Bignum; used to store the result of a / b
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_div(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c);
+
+/**
+ * crypto_bignum_mulmod - d = a * b (mod c)
+ * @a: Bignum
+ * @b: Bignum
+ * @c: Bignum
+ * @d: Bignum; used to store the result of (a * b) % c
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_mulmod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ const struct crypto_bignum *c,
+ struct crypto_bignum *d);
+
+/**
+ * crypto_bignum_cmp - Compare two bignums
+ * @a: Bignum
+ * @b: Bignum
+ * Returns: -1 if a < b, 0 if a == b, or 1 if a > b
+ */
+int crypto_bignum_cmp(const struct crypto_bignum *a,
+ const struct crypto_bignum *b);
+
+/**
+ * crypto_bignum_bits - Get size of a bignum in bits
+ * @a: Bignum
+ * Returns: Number of bits in the bignum
+ */
+int crypto_bignum_bits(const struct crypto_bignum *a);
+
+/**
+ * crypto_bignum_is_zero - Is the given bignum zero
+ * @a: Bignum
+ * Returns: 1 if @a is zero or 0 if not
+ */
+int crypto_bignum_is_zero(const struct crypto_bignum *a);
+
+/**
+ * crypto_bignum_is_one - Is the given bignum one
+ * @a: Bignum
+ * Returns: 1 if @a is one or 0 if not
+ */
+int crypto_bignum_is_one(const struct crypto_bignum *a);
+
+/**
+ * struct crypto_ec - Elliptic curve context
+ *
+ * Internal data structure for EC implementation. The contents is specific
+ * to the used crypto library.
+ */
+struct crypto_ec;
+
+/**
+ * crypto_ec_init - Initialize elliptic curve context
+ * @group: Identifying number for the ECC group (IANA "Group Description"
+ * attribute registrty for RFC 2409)
+ * Returns: Pointer to EC context or %NULL on failure
+ */
+struct crypto_ec * crypto_ec_init(int group);
+
+/**
+ * crypto_ec_deinit - Deinitialize elliptic curve context
+ * @e: EC context from crypto_ec_init()
+ */
+void crypto_ec_deinit(struct crypto_ec *e);
+
+/**
+ * crypto_ec_prime_len - Get length of the prime in octets
+ * @e: EC context from crypto_ec_init()
+ * Returns: Length of the prime defining the group
+ */
+size_t crypto_ec_prime_len(struct crypto_ec *e);
+
+/**
+ * crypto_ec_prime_len_bits - Get length of the prime in bits
+ * @e: EC context from crypto_ec_init()
+ * Returns: Length of the prime defining the group in bits
+ */
+size_t crypto_ec_prime_len_bits(struct crypto_ec *e);
+
+/**
+ * crypto_ec_get_prime - Get prime defining an EC group
+ * @e: EC context from crypto_ec_init()
+ * Returns: Prime (bignum) defining the group
+ */
+const struct crypto_bignum * crypto_ec_get_prime(struct crypto_ec *e);
+
+/**
+ * crypto_ec_get_order - Get order of an EC group
+ * @e: EC context from crypto_ec_init()
+ * Returns: Order (bignum) of the group
+ */
+const struct crypto_bignum * crypto_ec_get_order(struct crypto_ec *e);
+
+/**
+ * struct crypto_ec_point - Elliptic curve point
+ *
+ * Internal data structure for EC implementation to represent a point. The
+ * contents is specific to the used crypto library.
+ */
+struct crypto_ec_point;
+
+/**
+ * crypto_ec_point_init - Initialize data for an EC point
+ * @e: EC context from crypto_ec_init()
+ * Returns: Pointer to EC point data or %NULL on failure
+ */
+struct crypto_ec_point * crypto_ec_point_init(struct crypto_ec *e);
+
+/**
+ * crypto_ec_point_deinit - Deinitialize EC point data
+ * @p: EC point data from crypto_ec_point_init()
+ * @clear: Whether to clear the EC point value from memory
+ */
+void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear);
+
+/**
+ * crypto_ec_point_to_bin - Write EC point value as binary data
+ * @e: EC context from crypto_ec_init()
+ * @p: EC point data from crypto_ec_point_init()
+ * @x: Buffer for writing the binary data for x coordinate or %NULL if not used
+ * @y: Buffer for writing the binary data for y coordinate or %NULL if not used
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function can be used to write an EC point as binary data in a format
+ * that has the x and y coordinates in big endian byte order fields padded to
+ * the length of the prime defining the group.
+ */
+int crypto_ec_point_to_bin(struct crypto_ec *e,
+ const struct crypto_ec_point *point, u8 *x, u8 *y);
+
+/**
+ * crypto_ec_point_from_bin - Create EC point from binary data
+ * @e: EC context from crypto_ec_init()
+ * @val: Binary data to read the EC point from
+ * Returns: Pointer to EC point data or %NULL on failure
+ *
+ * This function readers x and y coordinates of the EC point from the provided
+ * buffer assuming the values are in big endian byte order with fields padded to
+ * the length of the prime defining the group.
+ */
+struct crypto_ec_point * crypto_ec_point_from_bin(struct crypto_ec *e,
+ const u8 *val);
+
+/**
+ * crypto_bignum_add - c = a + b
+ * @e: EC context from crypto_ec_init()
+ * @a: Bignum
+ * @b: Bignum
+ * @c: Bignum; used to store the result of a + b
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_ec_point_add(struct crypto_ec *e, const struct crypto_ec_point *a,
+ const struct crypto_ec_point *b,
+ struct crypto_ec_point *c);
+
+/**
+ * crypto_bignum_mul - res = b * p
+ * @e: EC context from crypto_ec_init()
+ * @p: EC point
+ * @b: Bignum
+ * @res: EC point; used to store the result of b * p
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_ec_point_mul(struct crypto_ec *e, const struct crypto_ec_point *p,
+ const struct crypto_bignum *b,
+ struct crypto_ec_point *res);
+
+/**
+ * crypto_ec_point_invert - Compute inverse of an EC point
+ * @e: EC context from crypto_ec_init()
+ * @p: EC point to invert (and result of the operation)
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_ec_point_invert(struct crypto_ec *e, struct crypto_ec_point *p);
+
+/**
+ * crypto_ec_point_solve_y_coord - Solve y coordinate for an x coordinate
+ * @e: EC context from crypto_ec_init()
+ * @p: EC point to use for the returning the result
+ * @x: x coordinate
+ * @y_bit: y-bit (0 or 1) for selecting the y value to use
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_ec_point_solve_y_coord(struct crypto_ec *e,
+ struct crypto_ec_point *p,
+ const struct crypto_bignum *x, int y_bit);
+
+/**
+ * crypto_ec_point_is_at_infinity - Check whether EC point is neutral element
+ * @e: EC context from crypto_ec_init()
+ * @p: EC point
+ * Returns: 1 if the specified EC point is the neutral element of the group or
+ * 0 if not
+ */
+int crypto_ec_point_is_at_infinity(struct crypto_ec *e,
+ const struct crypto_ec_point *p);
+
+/**
+ * crypto_ec_point_is_on_curve - Check whether EC point is on curve
+ * @e: EC context from crypto_ec_init()
+ * @p: EC point
+ * Returns: 1 if the specified EC point is on the curve or 0 if not
+ */
+int crypto_ec_point_is_on_curve(struct crypto_ec *e,
+ const struct crypto_ec_point *p);
+
#endif /* CRYPTO_H */
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index 711e312..5215c00 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / wrapper functions for libcrypto
- * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
+ * Wrapper functions for OpenSSL libcrypto
+ * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -19,6 +19,9 @@
#ifdef CONFIG_OPENSSL_CMAC
#include <openssl/cmac.h>
#endif /* CONFIG_OPENSSL_CMAC */
+#ifdef CONFIG_ECC
+#include <openssl/ec.h>
+#endif /* CONFIG_ECC */
#include "common.h"
#include "wpabuf.h"
@@ -818,3 +821,413 @@
return omac1_aes_128_vector(key, 1, &data, &data_len, mac);
}
#endif /* CONFIG_OPENSSL_CMAC */
+
+
+struct crypto_bignum * crypto_bignum_init(void)
+{
+ return (struct crypto_bignum *) BN_new();
+}
+
+
+struct crypto_bignum * crypto_bignum_init_set(const u8 *buf, size_t len)
+{
+ BIGNUM *bn = BN_bin2bn(buf, len, NULL);
+ return (struct crypto_bignum *) bn;
+}
+
+
+void crypto_bignum_deinit(struct crypto_bignum *n, int clear)
+{
+ if (clear)
+ BN_clear_free((BIGNUM *) n);
+ else
+ BN_free((BIGNUM *) n);
+}
+
+
+int crypto_bignum_to_bin(const struct crypto_bignum *a,
+ u8 *buf, size_t buflen, size_t padlen)
+{
+ int num_bytes, offset;
+
+ if (padlen > buflen)
+ return -1;
+
+ num_bytes = BN_num_bytes((const BIGNUM *) a);
+ if ((size_t) num_bytes > buflen)
+ return -1;
+ if (padlen > (size_t) num_bytes)
+ offset = padlen - num_bytes;
+ else
+ offset = 0;
+
+ os_memset(buf, 0, offset);
+ BN_bn2bin((const BIGNUM *) a, buf + offset);
+
+ return num_bytes + offset;
+}
+
+
+int crypto_bignum_add(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c)
+{
+ return BN_add((BIGNUM *) c, (const BIGNUM *) a, (const BIGNUM *) b) ?
+ 0 : -1;
+}
+
+
+int crypto_bignum_mod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c)
+{
+ int res;
+ BN_CTX *bnctx;
+
+ bnctx = BN_CTX_new();
+ if (bnctx == NULL)
+ return -1;
+ res = BN_mod((BIGNUM *) c, (const BIGNUM *) a, (const BIGNUM *) b,
+ bnctx);
+ BN_CTX_free(bnctx);
+
+ return res ? 0 : -1;
+}
+
+
+int crypto_bignum_exptmod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ const struct crypto_bignum *c,
+ struct crypto_bignum *d)
+{
+ int res;
+ BN_CTX *bnctx;
+
+ bnctx = BN_CTX_new();
+ if (bnctx == NULL)
+ return -1;
+ res = BN_mod_exp((BIGNUM *) d, (const BIGNUM *) a, (const BIGNUM *) b,
+ (const BIGNUM *) c, bnctx);
+ BN_CTX_free(bnctx);
+
+ return res ? 0 : -1;
+}
+
+
+int crypto_bignum_rshift(const struct crypto_bignum *a, int n,
+ struct crypto_bignum *b)
+{
+ return BN_rshift((BIGNUM *) b, (const BIGNUM *) a, n) ? 0 : -1;
+}
+
+
+int crypto_bignum_inverse(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c)
+{
+ BIGNUM *res;
+ BN_CTX *bnctx;
+
+ bnctx = BN_CTX_new();
+ if (bnctx == NULL)
+ return -1;
+ res = BN_mod_inverse((BIGNUM *) c, (const BIGNUM *) a,
+ (const BIGNUM *) b, bnctx);
+ BN_CTX_free(bnctx);
+
+ return res ? 0 : -1;
+}
+
+
+int crypto_bignum_sub(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c)
+{
+ return BN_sub((BIGNUM *) c, (const BIGNUM *) a, (const BIGNUM *) b) ?
+ 0 : -1;
+}
+
+
+int crypto_bignum_div(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c)
+{
+ int res;
+
+ BN_CTX *bnctx;
+
+ bnctx = BN_CTX_new();
+ if (bnctx == NULL)
+ return -1;
+ res = BN_div((BIGNUM *) c, NULL, (const BIGNUM *) a,
+ (const BIGNUM *) b, bnctx);
+ BN_CTX_free(bnctx);
+
+ return res ? 0 : -1;
+}
+
+
+int crypto_bignum_mulmod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ const struct crypto_bignum *c,
+ struct crypto_bignum *d)
+{
+ int res;
+
+ BN_CTX *bnctx;
+
+ bnctx = BN_CTX_new();
+ if (bnctx == NULL)
+ return -1;
+ res = BN_mod_mul((BIGNUM *) d, (const BIGNUM *) a, (const BIGNUM *) b,
+ (const BIGNUM *) c, bnctx);
+ BN_CTX_free(bnctx);
+
+ return res ? 0 : -1;
+}
+
+
+int crypto_bignum_cmp(const struct crypto_bignum *a,
+ const struct crypto_bignum *b)
+{
+ return BN_cmp((const BIGNUM *) a, (const BIGNUM *) b);
+}
+
+
+int crypto_bignum_bits(const struct crypto_bignum *a)
+{
+ return BN_num_bits((const BIGNUM *) a);
+}
+
+
+int crypto_bignum_is_zero(const struct crypto_bignum *a)
+{
+ return BN_is_zero((const BIGNUM *) a);
+}
+
+
+int crypto_bignum_is_one(const struct crypto_bignum *a)
+{
+ return BN_is_one((const BIGNUM *) a);
+}
+
+
+#ifdef CONFIG_ECC
+
+struct crypto_ec {
+ EC_GROUP *group;
+ BN_CTX *bnctx;
+ BIGNUM *prime;
+ BIGNUM *order;
+};
+
+struct crypto_ec * crypto_ec_init(int group)
+{
+ struct crypto_ec *e;
+ int nid;
+
+ /* Map from IANA registry for IKE D-H groups to OpenSSL NID */
+ switch (group) {
+ case 19:
+ nid = NID_X9_62_prime256v1;
+ break;
+ case 20:
+ nid = NID_secp384r1;
+ break;
+ case 21:
+ nid = NID_secp521r1;
+ break;
+ case 25:
+ nid = NID_X9_62_prime192v1;
+ break;
+ case 26:
+ nid = NID_secp224r1;
+ break;
+ default:
+ return NULL;
+ }
+
+ e = os_zalloc(sizeof(*e));
+ if (e == NULL)
+ return NULL;
+
+ e->bnctx = BN_CTX_new();
+ e->group = EC_GROUP_new_by_curve_name(nid);
+ e->prime = BN_new();
+ e->order = BN_new();
+ if (e->group == NULL || e->bnctx == NULL || e->prime == NULL ||
+ e->order == NULL ||
+ !EC_GROUP_get_curve_GFp(e->group, e->prime, NULL, NULL, e->bnctx) ||
+ !EC_GROUP_get_order(e->group, e->order, e->bnctx)) {
+ crypto_ec_deinit(e);
+ e = NULL;
+ }
+
+ return e;
+}
+
+
+void crypto_ec_deinit(struct crypto_ec *e)
+{
+ if (e == NULL)
+ return;
+ BN_free(e->order);
+ EC_GROUP_free(e->group);
+ BN_CTX_free(e->bnctx);
+ os_free(e);
+}
+
+
+struct crypto_ec_point * crypto_ec_point_init(struct crypto_ec *e)
+{
+ if (e == NULL)
+ return NULL;
+ return (struct crypto_ec_point *) EC_POINT_new(e->group);
+}
+
+
+size_t crypto_ec_prime_len(struct crypto_ec *e)
+{
+ return BN_num_bytes(e->prime);
+}
+
+
+size_t crypto_ec_prime_len_bits(struct crypto_ec *e)
+{
+ return BN_num_bits(e->prime);
+}
+
+
+const struct crypto_bignum * crypto_ec_get_prime(struct crypto_ec *e)
+{
+ return (const struct crypto_bignum *) e->prime;
+}
+
+
+const struct crypto_bignum * crypto_ec_get_order(struct crypto_ec *e)
+{
+ return (const struct crypto_bignum *) e->order;
+}
+
+
+void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear)
+{
+ if (clear)
+ EC_POINT_clear_free((EC_POINT *) p);
+ else
+ EC_POINT_free((EC_POINT *) p);
+}
+
+
+int crypto_ec_point_to_bin(struct crypto_ec *e,
+ const struct crypto_ec_point *point, u8 *x, u8 *y)
+{
+ BIGNUM *x_bn, *y_bn;
+ int ret = -1;
+ int len = BN_num_bytes(e->prime);
+
+ x_bn = BN_new();
+ y_bn = BN_new();
+
+ if (x_bn && y_bn &&
+ EC_POINT_get_affine_coordinates_GFp(e->group, (EC_POINT *) point,
+ x_bn, y_bn, e->bnctx)) {
+ if (x) {
+ crypto_bignum_to_bin((struct crypto_bignum *) x_bn,
+ x, len, len);
+ }
+ if (y) {
+ crypto_bignum_to_bin((struct crypto_bignum *) y_bn,
+ y, len, len);
+ }
+ ret = 0;
+ }
+
+ BN_free(x_bn);
+ BN_free(y_bn);
+ return ret;
+}
+
+
+struct crypto_ec_point * crypto_ec_point_from_bin(struct crypto_ec *e,
+ const u8 *val)
+{
+ BIGNUM *x, *y;
+ EC_POINT *elem;
+ int len = BN_num_bytes(e->prime);
+
+ x = BN_bin2bn(val, len, NULL);
+ y = BN_bin2bn(val + len, len, NULL);
+ elem = EC_POINT_new(e->group);
+ if (x == NULL || y == NULL || elem == NULL) {
+ BN_free(x);
+ BN_free(y);
+ EC_POINT_free(elem);
+ return NULL;
+ }
+
+ if (!EC_POINT_set_affine_coordinates_GFp(e->group, elem, x, y,
+ e->bnctx)) {
+ EC_POINT_free(elem);
+ elem = NULL;
+ }
+
+ BN_free(x);
+ BN_free(y);
+
+ return (struct crypto_ec_point *) elem;
+}
+
+
+int crypto_ec_point_add(struct crypto_ec *e, const struct crypto_ec_point *a,
+ const struct crypto_ec_point *b,
+ struct crypto_ec_point *c)
+{
+ return EC_POINT_add(e->group, (EC_POINT *) c, (const EC_POINT *) a,
+ (const EC_POINT *) b, e->bnctx) ? 0 : -1;
+}
+
+
+int crypto_ec_point_mul(struct crypto_ec *e, const struct crypto_ec_point *p,
+ const struct crypto_bignum *b,
+ struct crypto_ec_point *res)
+{
+ return EC_POINT_mul(e->group, (EC_POINT *) res, NULL,
+ (const EC_POINT *) p, (const BIGNUM *) b, e->bnctx)
+ ? 0 : -1;
+}
+
+
+int crypto_ec_point_invert(struct crypto_ec *e, struct crypto_ec_point *p)
+{
+ return EC_POINT_invert(e->group, (EC_POINT *) p, e->bnctx) ? 0 : -1;
+}
+
+
+int crypto_ec_point_solve_y_coord(struct crypto_ec *e,
+ struct crypto_ec_point *p,
+ const struct crypto_bignum *x, int y_bit)
+{
+ if (!EC_POINT_set_compressed_coordinates_GFp(e->group, (EC_POINT *) p,
+ (const BIGNUM *) x, y_bit,
+ e->bnctx) ||
+ !EC_POINT_is_on_curve(e->group, (EC_POINT *) p, e->bnctx))
+ return -1;
+ return 0;
+}
+
+
+int crypto_ec_point_is_at_infinity(struct crypto_ec *e,
+ const struct crypto_ec_point *p)
+{
+ return EC_POINT_is_at_infinity(e->group, (const EC_POINT *) p);
+}
+
+
+int crypto_ec_point_is_on_curve(struct crypto_ec *e,
+ const struct crypto_ec_point *p)
+{
+ return EC_POINT_is_on_curve(e->group, (const EC_POINT *) p, e->bnctx);
+}
+
+#endif /* CONFIG_ECC */
diff --git a/src/crypto/dh_groups.c b/src/crypto/dh_groups.c
index f757b6b..3a675df 100644
--- a/src/crypto/dh_groups.c
+++ b/src/crypto/dh_groups.c
@@ -35,6 +35,20 @@
0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x3A, 0x36, 0x20,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
+static const u8 dh_group1_order[96] = {
+ 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A,
+ 0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68,
+ 0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A,
+ 0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91,
+ 0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E,
+ 0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D,
+ 0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B,
+ 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22,
+ 0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63,
+ 0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1D, 0x1B, 0x10,
+ 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
/* RFC 4306, B.2. Group 2 - 1024 Bit MODP
* Generator: 2
@@ -59,6 +73,24 @@
0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
+static const u8 dh_group2_order[128] = {
+ 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A,
+ 0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68,
+ 0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A,
+ 0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91,
+ 0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E,
+ 0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D,
+ 0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B,
+ 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22,
+ 0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63,
+ 0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5,
+ 0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6,
+ 0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2,
+ 0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3,
+ 0x24, 0x94, 0x33, 0x28, 0xF6, 0x73, 0x29, 0xC0,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
#endif /* ALL_DH_GROUPS */
@@ -93,6 +125,32 @@
0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x23, 0x73, 0x27,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
+static const u8 dh_group5_order[192] = {
+ 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A,
+ 0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68,
+ 0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A,
+ 0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91,
+ 0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E,
+ 0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D,
+ 0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B,
+ 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22,
+ 0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63,
+ 0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5,
+ 0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6,
+ 0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2,
+ 0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3,
+ 0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D, 0x9E,
+ 0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1, 0xDF, 0x82,
+ 0xCC, 0x6D, 0x24, 0x1B, 0x0E, 0x2A, 0xE9, 0xCD,
+ 0x34, 0x8B, 0x1F, 0xD4, 0x7E, 0x92, 0x67, 0xAF,
+ 0xC1, 0xB2, 0xAE, 0x91, 0xEE, 0x51, 0xD6, 0xCB,
+ 0x0E, 0x31, 0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D,
+ 0xCF, 0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36,
+ 0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C, 0x02,
+ 0x78, 0xBA, 0x36, 0x04, 0x65, 0x11, 0xB9, 0x93,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
#ifdef ALL_DH_GROUPS
@@ -135,6 +193,40 @@
0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
+static const u8 dh_group14_order[256] = {
+ 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A,
+ 0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68,
+ 0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A,
+ 0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91,
+ 0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E,
+ 0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D,
+ 0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B,
+ 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22,
+ 0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63,
+ 0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5,
+ 0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6,
+ 0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2,
+ 0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3,
+ 0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D, 0x9E,
+ 0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1, 0xDF, 0x82,
+ 0xCC, 0x6D, 0x24, 0x1B, 0x0E, 0x2A, 0xE9, 0xCD,
+ 0x34, 0x8B, 0x1F, 0xD4, 0x7E, 0x92, 0x67, 0xAF,
+ 0xC1, 0xB2, 0xAE, 0x91, 0xEE, 0x51, 0xD6, 0xCB,
+ 0x0E, 0x31, 0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D,
+ 0xCF, 0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36,
+ 0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C, 0x02,
+ 0x78, 0xBA, 0x36, 0x04, 0x65, 0x0C, 0x10, 0xBE,
+ 0x19, 0x48, 0x2F, 0x23, 0x17, 0x1B, 0x67, 0x1D,
+ 0xF1, 0xCF, 0x3B, 0x96, 0x0C, 0x07, 0x43, 0x01,
+ 0xCD, 0x93, 0xC1, 0xD1, 0x76, 0x03, 0xD1, 0x47,
+ 0xDA, 0xE2, 0xAE, 0xF8, 0x37, 0xA6, 0x29, 0x64,
+ 0xEF, 0x15, 0xE5, 0xFB, 0x4A, 0xAC, 0x0B, 0x8C,
+ 0x1C, 0xCA, 0xA4, 0xBE, 0x75, 0x4A, 0xB5, 0x72,
+ 0x8A, 0xE9, 0x13, 0x0C, 0x4C, 0x7D, 0x02, 0x88,
+ 0x0A, 0xB9, 0x47, 0x2D, 0x45, 0x56, 0x55, 0x34,
+ 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
/* RFC 3526, 4. Group 15 - 3072 Bit MODP
* Generator: 2
@@ -191,6 +283,56 @@
0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x3A, 0xD2, 0xCA,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
+static const u8 dh_group15_order[384] = {
+ 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A,
+ 0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68,
+ 0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A,
+ 0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91,
+ 0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E,
+ 0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D,
+ 0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B,
+ 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22,
+ 0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63,
+ 0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5,
+ 0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6,
+ 0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2,
+ 0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3,
+ 0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D, 0x9E,
+ 0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1, 0xDF, 0x82,
+ 0xCC, 0x6D, 0x24, 0x1B, 0x0E, 0x2A, 0xE9, 0xCD,
+ 0x34, 0x8B, 0x1F, 0xD4, 0x7E, 0x92, 0x67, 0xAF,
+ 0xC1, 0xB2, 0xAE, 0x91, 0xEE, 0x51, 0xD6, 0xCB,
+ 0x0E, 0x31, 0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D,
+ 0xCF, 0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36,
+ 0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C, 0x02,
+ 0x78, 0xBA, 0x36, 0x04, 0x65, 0x0C, 0x10, 0xBE,
+ 0x19, 0x48, 0x2F, 0x23, 0x17, 0x1B, 0x67, 0x1D,
+ 0xF1, 0xCF, 0x3B, 0x96, 0x0C, 0x07, 0x43, 0x01,
+ 0xCD, 0x93, 0xC1, 0xD1, 0x76, 0x03, 0xD1, 0x47,
+ 0xDA, 0xE2, 0xAE, 0xF8, 0x37, 0xA6, 0x29, 0x64,
+ 0xEF, 0x15, 0xE5, 0xFB, 0x4A, 0xAC, 0x0B, 0x8C,
+ 0x1C, 0xCA, 0xA4, 0xBE, 0x75, 0x4A, 0xB5, 0x72,
+ 0x8A, 0xE9, 0x13, 0x0C, 0x4C, 0x7D, 0x02, 0x88,
+ 0x0A, 0xB9, 0x47, 0x2D, 0x45, 0x55, 0x62, 0x16,
+ 0xD6, 0x99, 0x8B, 0x86, 0x82, 0x28, 0x3D, 0x19,
+ 0xD4, 0x2A, 0x90, 0xD5, 0xEF, 0x8E, 0x5D, 0x32,
+ 0x76, 0x7D, 0xC2, 0x82, 0x2C, 0x6D, 0xF7, 0x85,
+ 0x45, 0x75, 0x38, 0xAB, 0xAE, 0x83, 0x06, 0x3E,
+ 0xD9, 0xCB, 0x87, 0xC2, 0xD3, 0x70, 0xF2, 0x63,
+ 0xD5, 0xFA, 0xD7, 0x46, 0x6D, 0x84, 0x99, 0xEB,
+ 0x8F, 0x46, 0x4A, 0x70, 0x25, 0x12, 0xB0, 0xCE,
+ 0xE7, 0x71, 0xE9, 0x13, 0x0D, 0x69, 0x77, 0x35,
+ 0xF8, 0x97, 0xFD, 0x03, 0x6C, 0xC5, 0x04, 0x32,
+ 0x6C, 0x3B, 0x01, 0x39, 0x9F, 0x64, 0x35, 0x32,
+ 0x29, 0x0F, 0x95, 0x8C, 0x0B, 0xBD, 0x90, 0x06,
+ 0x5D, 0xF0, 0x8B, 0xAB, 0xBD, 0x30, 0xAE, 0xB6,
+ 0x3B, 0x84, 0xC4, 0x60, 0x5D, 0x6C, 0xA3, 0x71,
+ 0x04, 0x71, 0x27, 0xD0, 0x3A, 0x72, 0xD5, 0x98,
+ 0xA1, 0xED, 0xAD, 0xFE, 0x70, 0x7E, 0x88, 0x47,
+ 0x25, 0xC1, 0x68, 0x90, 0x54, 0x9D, 0x69, 0x65,
+ 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
/* RFC 3526, 5. Group 16 - 4096 Bit MODP
* Generator: 2
@@ -263,6 +405,72 @@
0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
+static const u8 dh_group16_order[512] = {
+ 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A,
+ 0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68,
+ 0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A,
+ 0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91,
+ 0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E,
+ 0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D,
+ 0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B,
+ 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22,
+ 0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63,
+ 0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5,
+ 0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6,
+ 0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2,
+ 0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3,
+ 0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D, 0x9E,
+ 0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1, 0xDF, 0x82,
+ 0xCC, 0x6D, 0x24, 0x1B, 0x0E, 0x2A, 0xE9, 0xCD,
+ 0x34, 0x8B, 0x1F, 0xD4, 0x7E, 0x92, 0x67, 0xAF,
+ 0xC1, 0xB2, 0xAE, 0x91, 0xEE, 0x51, 0xD6, 0xCB,
+ 0x0E, 0x31, 0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D,
+ 0xCF, 0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36,
+ 0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C, 0x02,
+ 0x78, 0xBA, 0x36, 0x04, 0x65, 0x0C, 0x10, 0xBE,
+ 0x19, 0x48, 0x2F, 0x23, 0x17, 0x1B, 0x67, 0x1D,
+ 0xF1, 0xCF, 0x3B, 0x96, 0x0C, 0x07, 0x43, 0x01,
+ 0xCD, 0x93, 0xC1, 0xD1, 0x76, 0x03, 0xD1, 0x47,
+ 0xDA, 0xE2, 0xAE, 0xF8, 0x37, 0xA6, 0x29, 0x64,
+ 0xEF, 0x15, 0xE5, 0xFB, 0x4A, 0xAC, 0x0B, 0x8C,
+ 0x1C, 0xCA, 0xA4, 0xBE, 0x75, 0x4A, 0xB5, 0x72,
+ 0x8A, 0xE9, 0x13, 0x0C, 0x4C, 0x7D, 0x02, 0x88,
+ 0x0A, 0xB9, 0x47, 0x2D, 0x45, 0x55, 0x62, 0x16,
+ 0xD6, 0x99, 0x8B, 0x86, 0x82, 0x28, 0x3D, 0x19,
+ 0xD4, 0x2A, 0x90, 0xD5, 0xEF, 0x8E, 0x5D, 0x32,
+ 0x76, 0x7D, 0xC2, 0x82, 0x2C, 0x6D, 0xF7, 0x85,
+ 0x45, 0x75, 0x38, 0xAB, 0xAE, 0x83, 0x06, 0x3E,
+ 0xD9, 0xCB, 0x87, 0xC2, 0xD3, 0x70, 0xF2, 0x63,
+ 0xD5, 0xFA, 0xD7, 0x46, 0x6D, 0x84, 0x99, 0xEB,
+ 0x8F, 0x46, 0x4A, 0x70, 0x25, 0x12, 0xB0, 0xCE,
+ 0xE7, 0x71, 0xE9, 0x13, 0x0D, 0x69, 0x77, 0x35,
+ 0xF8, 0x97, 0xFD, 0x03, 0x6C, 0xC5, 0x04, 0x32,
+ 0x6C, 0x3B, 0x01, 0x39, 0x9F, 0x64, 0x35, 0x32,
+ 0x29, 0x0F, 0x95, 0x8C, 0x0B, 0xBD, 0x90, 0x06,
+ 0x5D, 0xF0, 0x8B, 0xAB, 0xBD, 0x30, 0xAE, 0xB6,
+ 0x3B, 0x84, 0xC4, 0x60, 0x5D, 0x6C, 0xA3, 0x71,
+ 0x04, 0x71, 0x27, 0xD0, 0x3A, 0x72, 0xD5, 0x98,
+ 0xA1, 0xED, 0xAD, 0xFE, 0x70, 0x7E, 0x88, 0x47,
+ 0x25, 0xC1, 0x68, 0x90, 0x54, 0x90, 0x84, 0x00,
+ 0x8D, 0x39, 0x1E, 0x09, 0x53, 0xC3, 0xF3, 0x6B,
+ 0xC4, 0x38, 0xCD, 0x08, 0x5E, 0xDD, 0x2D, 0x93,
+ 0x4C, 0xE1, 0x93, 0x8C, 0x35, 0x7A, 0x71, 0x1E,
+ 0x0D, 0x4A, 0x34, 0x1A, 0x5B, 0x0A, 0x85, 0xED,
+ 0x12, 0xC1, 0xF4, 0xE5, 0x15, 0x6A, 0x26, 0x74,
+ 0x6D, 0xDD, 0xE1, 0x6D, 0x82, 0x6F, 0x47, 0x7C,
+ 0x97, 0x47, 0x7E, 0x0A, 0x0F, 0xDF, 0x65, 0x53,
+ 0x14, 0x3E, 0x2C, 0xA3, 0xA7, 0x35, 0xE0, 0x2E,
+ 0xCC, 0xD9, 0x4B, 0x27, 0xD0, 0x48, 0x61, 0xD1,
+ 0x11, 0x9D, 0xD0, 0xC3, 0x28, 0xAD, 0xF3, 0xF6,
+ 0x8F, 0xB0, 0x94, 0xB8, 0x67, 0x71, 0x6B, 0xD7,
+ 0xDC, 0x0D, 0xEE, 0xBB, 0x10, 0xB8, 0x24, 0x0E,
+ 0x68, 0x03, 0x48, 0x93, 0xEA, 0xD8, 0x2D, 0x54,
+ 0xC9, 0xDA, 0x75, 0x4C, 0x46, 0xC7, 0xEE, 0xE0,
+ 0xC3, 0x7F, 0xDB, 0xEE, 0x48, 0x53, 0x60, 0x47,
+ 0xA6, 0xFA, 0x1A, 0xE4, 0x9A, 0x03, 0x18, 0xCC,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
/* RFC 3526, 6. Group 17 - 6144 Bit MODP
* Generator: 2
@@ -367,6 +575,104 @@
0xE6, 0x94, 0xF9, 0x1E, 0x6D, 0xCC, 0x40, 0x24,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
+static const u8 dh_group17_order[768] = {
+ 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A,
+ 0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68,
+ 0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A,
+ 0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91,
+ 0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E,
+ 0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D,
+ 0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B,
+ 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22,
+ 0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63,
+ 0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5,
+ 0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6,
+ 0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2,
+ 0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3,
+ 0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D, 0x9E,
+ 0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1, 0xDF, 0x82,
+ 0xCC, 0x6D, 0x24, 0x1B, 0x0E, 0x2A, 0xE9, 0xCD,
+ 0x34, 0x8B, 0x1F, 0xD4, 0x7E, 0x92, 0x67, 0xAF,
+ 0xC1, 0xB2, 0xAE, 0x91, 0xEE, 0x51, 0xD6, 0xCB,
+ 0x0E, 0x31, 0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D,
+ 0xCF, 0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36,
+ 0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C, 0x02,
+ 0x78, 0xBA, 0x36, 0x04, 0x65, 0x0C, 0x10, 0xBE,
+ 0x19, 0x48, 0x2F, 0x23, 0x17, 0x1B, 0x67, 0x1D,
+ 0xF1, 0xCF, 0x3B, 0x96, 0x0C, 0x07, 0x43, 0x01,
+ 0xCD, 0x93, 0xC1, 0xD1, 0x76, 0x03, 0xD1, 0x47,
+ 0xDA, 0xE2, 0xAE, 0xF8, 0x37, 0xA6, 0x29, 0x64,
+ 0xEF, 0x15, 0xE5, 0xFB, 0x4A, 0xAC, 0x0B, 0x8C,
+ 0x1C, 0xCA, 0xA4, 0xBE, 0x75, 0x4A, 0xB5, 0x72,
+ 0x8A, 0xE9, 0x13, 0x0C, 0x4C, 0x7D, 0x02, 0x88,
+ 0x0A, 0xB9, 0x47, 0x2D, 0x45, 0x55, 0x62, 0x16,
+ 0xD6, 0x99, 0x8B, 0x86, 0x82, 0x28, 0x3D, 0x19,
+ 0xD4, 0x2A, 0x90, 0xD5, 0xEF, 0x8E, 0x5D, 0x32,
+ 0x76, 0x7D, 0xC2, 0x82, 0x2C, 0x6D, 0xF7, 0x85,
+ 0x45, 0x75, 0x38, 0xAB, 0xAE, 0x83, 0x06, 0x3E,
+ 0xD9, 0xCB, 0x87, 0xC2, 0xD3, 0x70, 0xF2, 0x63,
+ 0xD5, 0xFA, 0xD7, 0x46, 0x6D, 0x84, 0x99, 0xEB,
+ 0x8F, 0x46, 0x4A, 0x70, 0x25, 0x12, 0xB0, 0xCE,
+ 0xE7, 0x71, 0xE9, 0x13, 0x0D, 0x69, 0x77, 0x35,
+ 0xF8, 0x97, 0xFD, 0x03, 0x6C, 0xC5, 0x04, 0x32,
+ 0x6C, 0x3B, 0x01, 0x39, 0x9F, 0x64, 0x35, 0x32,
+ 0x29, 0x0F, 0x95, 0x8C, 0x0B, 0xBD, 0x90, 0x06,
+ 0x5D, 0xF0, 0x8B, 0xAB, 0xBD, 0x30, 0xAE, 0xB6,
+ 0x3B, 0x84, 0xC4, 0x60, 0x5D, 0x6C, 0xA3, 0x71,
+ 0x04, 0x71, 0x27, 0xD0, 0x3A, 0x72, 0xD5, 0x98,
+ 0xA1, 0xED, 0xAD, 0xFE, 0x70, 0x7E, 0x88, 0x47,
+ 0x25, 0xC1, 0x68, 0x90, 0x54, 0x90, 0x84, 0x00,
+ 0x8D, 0x39, 0x1E, 0x09, 0x53, 0xC3, 0xF3, 0x6B,
+ 0xC4, 0x38, 0xCD, 0x08, 0x5E, 0xDD, 0x2D, 0x93,
+ 0x4C, 0xE1, 0x93, 0x8C, 0x35, 0x7A, 0x71, 0x1E,
+ 0x0D, 0x4A, 0x34, 0x1A, 0x5B, 0x0A, 0x85, 0xED,
+ 0x12, 0xC1, 0xF4, 0xE5, 0x15, 0x6A, 0x26, 0x74,
+ 0x6D, 0xDD, 0xE1, 0x6D, 0x82, 0x6F, 0x47, 0x7C,
+ 0x97, 0x47, 0x7E, 0x0A, 0x0F, 0xDF, 0x65, 0x53,
+ 0x14, 0x3E, 0x2C, 0xA3, 0xA7, 0x35, 0xE0, 0x2E,
+ 0xCC, 0xD9, 0x4B, 0x27, 0xD0, 0x48, 0x61, 0xD1,
+ 0x11, 0x9D, 0xD0, 0xC3, 0x28, 0xAD, 0xF3, 0xF6,
+ 0x8F, 0xB0, 0x94, 0xB8, 0x67, 0x71, 0x6B, 0xD7,
+ 0xDC, 0x0D, 0xEE, 0xBB, 0x10, 0xB8, 0x24, 0x0E,
+ 0x68, 0x03, 0x48, 0x93, 0xEA, 0xD8, 0x2D, 0x54,
+ 0xC9, 0xDA, 0x75, 0x4C, 0x46, 0xC7, 0xEE, 0xE0,
+ 0xC3, 0x7F, 0xDB, 0xEE, 0x48, 0x53, 0x60, 0x47,
+ 0xA6, 0xFA, 0x1A, 0xE4, 0x9A, 0x01, 0x42, 0x49,
+ 0x1B, 0x61, 0xFD, 0x5A, 0x69, 0x3E, 0x38, 0x13,
+ 0x60, 0xEA, 0x6E, 0x59, 0x30, 0x13, 0x23, 0x6F,
+ 0x64, 0xBA, 0x8F, 0x3B, 0x1E, 0xDD, 0x1B, 0xDE,
+ 0xFC, 0x7F, 0xCA, 0x03, 0x56, 0xCF, 0x29, 0x87,
+ 0x72, 0xED, 0x9C, 0x17, 0xA0, 0x98, 0x00, 0xD7,
+ 0x58, 0x35, 0x29, 0xF6, 0xC8, 0x13, 0xEC, 0x18,
+ 0x8B, 0xCB, 0x93, 0xD8, 0x43, 0x2D, 0x44, 0x8C,
+ 0x6D, 0x1F, 0x6D, 0xF5, 0xE7, 0xCD, 0x8A, 0x76,
+ 0xA2, 0x67, 0x36, 0x5D, 0x67, 0x6A, 0x5D, 0x8D,
+ 0xED, 0xBF, 0x8A, 0x23, 0xF3, 0x66, 0x12, 0xA5,
+ 0x99, 0x90, 0x28, 0xA8, 0x95, 0xEB, 0xD7, 0xA1,
+ 0x37, 0xDC, 0x7A, 0x00, 0x9B, 0xC6, 0x69, 0x5F,
+ 0xAC, 0xC1, 0xE5, 0x00, 0xE3, 0x25, 0xC9, 0x76,
+ 0x78, 0x19, 0x75, 0x0A, 0xE8, 0xB9, 0x0E, 0x81,
+ 0xFA, 0x41, 0x6B, 0xE7, 0x37, 0x3A, 0x7F, 0x7B,
+ 0x6A, 0xAF, 0x38, 0x17, 0xA3, 0x4C, 0x06, 0x41,
+ 0x5A, 0xD4, 0x20, 0x18, 0xC8, 0x05, 0x8E, 0x4F,
+ 0x2C, 0xF3, 0xE4, 0xBF, 0xDF, 0x63, 0xF4, 0x79,
+ 0x91, 0xD4, 0xBD, 0x3F, 0x1B, 0x66, 0x44, 0x5F,
+ 0x07, 0x8E, 0xA2, 0xDB, 0xFF, 0xAC, 0x2D, 0x62,
+ 0xA5, 0xEA, 0x03, 0xD9, 0x15, 0xA0, 0xAA, 0x55,
+ 0x66, 0x47, 0xB6, 0xBF, 0x5F, 0xA4, 0x70, 0xEC,
+ 0x0A, 0x66, 0x2F, 0x69, 0x07, 0xC0, 0x1B, 0xF0,
+ 0x53, 0xCB, 0x8A, 0xF7, 0x79, 0x4D, 0xF1, 0x94,
+ 0x03, 0x50, 0xEA, 0xC5, 0xDB, 0xE2, 0xED, 0x3B,
+ 0x7A, 0xA8, 0x55, 0x1E, 0xC5, 0x0F, 0xDF, 0xF8,
+ 0x75, 0x8C, 0xE6, 0x58, 0xD1, 0x89, 0xEA, 0xAE,
+ 0x6D, 0x2B, 0x64, 0xF6, 0x17, 0x79, 0x4B, 0x19,
+ 0x1C, 0x3F, 0xF4, 0x6B, 0xB7, 0x1E, 0x02, 0x34,
+ 0x02, 0x1F, 0x47, 0xB3, 0x1F, 0xA4, 0x30, 0x77,
+ 0x09, 0x5F, 0x96, 0xAD, 0x85, 0xBA, 0x3A, 0x6B,
+ 0x73, 0x4A, 0x7C, 0x8F, 0x36, 0xE6, 0x20, 0x12,
+ 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
/* RFC 3526, 7. Group 18 - 8192 Bit MODP
* Generator: 2
@@ -503,25 +809,363 @@
0x60, 0xC9, 0x80, 0xDD, 0x98, 0xED, 0xD3, 0xDF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
+static const u8 dh_group18_order[1024] = {
+ 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A,
+ 0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68,
+ 0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A,
+ 0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91,
+ 0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E,
+ 0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D,
+ 0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B,
+ 0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22,
+ 0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63,
+ 0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5,
+ 0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6,
+ 0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2,
+ 0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3,
+ 0x24, 0x94, 0x33, 0x28, 0xF6, 0x72, 0x2D, 0x9E,
+ 0xE1, 0x00, 0x3E, 0x5C, 0x50, 0xB1, 0xDF, 0x82,
+ 0xCC, 0x6D, 0x24, 0x1B, 0x0E, 0x2A, 0xE9, 0xCD,
+ 0x34, 0x8B, 0x1F, 0xD4, 0x7E, 0x92, 0x67, 0xAF,
+ 0xC1, 0xB2, 0xAE, 0x91, 0xEE, 0x51, 0xD6, 0xCB,
+ 0x0E, 0x31, 0x79, 0xAB, 0x10, 0x42, 0xA9, 0x5D,
+ 0xCF, 0x6A, 0x94, 0x83, 0xB8, 0x4B, 0x4B, 0x36,
+ 0xB3, 0x86, 0x1A, 0xA7, 0x25, 0x5E, 0x4C, 0x02,
+ 0x78, 0xBA, 0x36, 0x04, 0x65, 0x0C, 0x10, 0xBE,
+ 0x19, 0x48, 0x2F, 0x23, 0x17, 0x1B, 0x67, 0x1D,
+ 0xF1, 0xCF, 0x3B, 0x96, 0x0C, 0x07, 0x43, 0x01,
+ 0xCD, 0x93, 0xC1, 0xD1, 0x76, 0x03, 0xD1, 0x47,
+ 0xDA, 0xE2, 0xAE, 0xF8, 0x37, 0xA6, 0x29, 0x64,
+ 0xEF, 0x15, 0xE5, 0xFB, 0x4A, 0xAC, 0x0B, 0x8C,
+ 0x1C, 0xCA, 0xA4, 0xBE, 0x75, 0x4A, 0xB5, 0x72,
+ 0x8A, 0xE9, 0x13, 0x0C, 0x4C, 0x7D, 0x02, 0x88,
+ 0x0A, 0xB9, 0x47, 0x2D, 0x45, 0x55, 0x62, 0x16,
+ 0xD6, 0x99, 0x8B, 0x86, 0x82, 0x28, 0x3D, 0x19,
+ 0xD4, 0x2A, 0x90, 0xD5, 0xEF, 0x8E, 0x5D, 0x32,
+ 0x76, 0x7D, 0xC2, 0x82, 0x2C, 0x6D, 0xF7, 0x85,
+ 0x45, 0x75, 0x38, 0xAB, 0xAE, 0x83, 0x06, 0x3E,
+ 0xD9, 0xCB, 0x87, 0xC2, 0xD3, 0x70, 0xF2, 0x63,
+ 0xD5, 0xFA, 0xD7, 0x46, 0x6D, 0x84, 0x99, 0xEB,
+ 0x8F, 0x46, 0x4A, 0x70, 0x25, 0x12, 0xB0, 0xCE,
+ 0xE7, 0x71, 0xE9, 0x13, 0x0D, 0x69, 0x77, 0x35,
+ 0xF8, 0x97, 0xFD, 0x03, 0x6C, 0xC5, 0x04, 0x32,
+ 0x6C, 0x3B, 0x01, 0x39, 0x9F, 0x64, 0x35, 0x32,
+ 0x29, 0x0F, 0x95, 0x8C, 0x0B, 0xBD, 0x90, 0x06,
+ 0x5D, 0xF0, 0x8B, 0xAB, 0xBD, 0x30, 0xAE, 0xB6,
+ 0x3B, 0x84, 0xC4, 0x60, 0x5D, 0x6C, 0xA3, 0x71,
+ 0x04, 0x71, 0x27, 0xD0, 0x3A, 0x72, 0xD5, 0x98,
+ 0xA1, 0xED, 0xAD, 0xFE, 0x70, 0x7E, 0x88, 0x47,
+ 0x25, 0xC1, 0x68, 0x90, 0x54, 0x90, 0x84, 0x00,
+ 0x8D, 0x39, 0x1E, 0x09, 0x53, 0xC3, 0xF3, 0x6B,
+ 0xC4, 0x38, 0xCD, 0x08, 0x5E, 0xDD, 0x2D, 0x93,
+ 0x4C, 0xE1, 0x93, 0x8C, 0x35, 0x7A, 0x71, 0x1E,
+ 0x0D, 0x4A, 0x34, 0x1A, 0x5B, 0x0A, 0x85, 0xED,
+ 0x12, 0xC1, 0xF4, 0xE5, 0x15, 0x6A, 0x26, 0x74,
+ 0x6D, 0xDD, 0xE1, 0x6D, 0x82, 0x6F, 0x47, 0x7C,
+ 0x97, 0x47, 0x7E, 0x0A, 0x0F, 0xDF, 0x65, 0x53,
+ 0x14, 0x3E, 0x2C, 0xA3, 0xA7, 0x35, 0xE0, 0x2E,
+ 0xCC, 0xD9, 0x4B, 0x27, 0xD0, 0x48, 0x61, 0xD1,
+ 0x11, 0x9D, 0xD0, 0xC3, 0x28, 0xAD, 0xF3, 0xF6,
+ 0x8F, 0xB0, 0x94, 0xB8, 0x67, 0x71, 0x6B, 0xD7,
+ 0xDC, 0x0D, 0xEE, 0xBB, 0x10, 0xB8, 0x24, 0x0E,
+ 0x68, 0x03, 0x48, 0x93, 0xEA, 0xD8, 0x2D, 0x54,
+ 0xC9, 0xDA, 0x75, 0x4C, 0x46, 0xC7, 0xEE, 0xE0,
+ 0xC3, 0x7F, 0xDB, 0xEE, 0x48, 0x53, 0x60, 0x47,
+ 0xA6, 0xFA, 0x1A, 0xE4, 0x9A, 0x01, 0x42, 0x49,
+ 0x1B, 0x61, 0xFD, 0x5A, 0x69, 0x3E, 0x38, 0x13,
+ 0x60, 0xEA, 0x6E, 0x59, 0x30, 0x13, 0x23, 0x6F,
+ 0x64, 0xBA, 0x8F, 0x3B, 0x1E, 0xDD, 0x1B, 0xDE,
+ 0xFC, 0x7F, 0xCA, 0x03, 0x56, 0xCF, 0x29, 0x87,
+ 0x72, 0xED, 0x9C, 0x17, 0xA0, 0x98, 0x00, 0xD7,
+ 0x58, 0x35, 0x29, 0xF6, 0xC8, 0x13, 0xEC, 0x18,
+ 0x8B, 0xCB, 0x93, 0xD8, 0x43, 0x2D, 0x44, 0x8C,
+ 0x6D, 0x1F, 0x6D, 0xF5, 0xE7, 0xCD, 0x8A, 0x76,
+ 0xA2, 0x67, 0x36, 0x5D, 0x67, 0x6A, 0x5D, 0x8D,
+ 0xED, 0xBF, 0x8A, 0x23, 0xF3, 0x66, 0x12, 0xA5,
+ 0x99, 0x90, 0x28, 0xA8, 0x95, 0xEB, 0xD7, 0xA1,
+ 0x37, 0xDC, 0x7A, 0x00, 0x9B, 0xC6, 0x69, 0x5F,
+ 0xAC, 0xC1, 0xE5, 0x00, 0xE3, 0x25, 0xC9, 0x76,
+ 0x78, 0x19, 0x75, 0x0A, 0xE8, 0xB9, 0x0E, 0x81,
+ 0xFA, 0x41, 0x6B, 0xE7, 0x37, 0x3A, 0x7F, 0x7B,
+ 0x6A, 0xAF, 0x38, 0x17, 0xA3, 0x4C, 0x06, 0x41,
+ 0x5A, 0xD4, 0x20, 0x18, 0xC8, 0x05, 0x8E, 0x4F,
+ 0x2C, 0xF3, 0xE4, 0xBF, 0xDF, 0x63, 0xF4, 0x79,
+ 0x91, 0xD4, 0xBD, 0x3F, 0x1B, 0x66, 0x44, 0x5F,
+ 0x07, 0x8E, 0xA2, 0xDB, 0xFF, 0xAC, 0x2D, 0x62,
+ 0xA5, 0xEA, 0x03, 0xD9, 0x15, 0xA0, 0xAA, 0x55,
+ 0x66, 0x47, 0xB6, 0xBF, 0x5F, 0xA4, 0x70, 0xEC,
+ 0x0A, 0x66, 0x2F, 0x69, 0x07, 0xC0, 0x1B, 0xF0,
+ 0x53, 0xCB, 0x8A, 0xF7, 0x79, 0x4D, 0xF1, 0x94,
+ 0x03, 0x50, 0xEA, 0xC5, 0xDB, 0xE2, 0xED, 0x3B,
+ 0x7A, 0xA8, 0x55, 0x1E, 0xC5, 0x0F, 0xDF, 0xF8,
+ 0x75, 0x8C, 0xE6, 0x58, 0xD1, 0x89, 0xEA, 0xAE,
+ 0x6D, 0x2B, 0x64, 0xF6, 0x17, 0x79, 0x4B, 0x19,
+ 0x1C, 0x3F, 0xF4, 0x6B, 0xB7, 0x1E, 0x02, 0x34,
+ 0x02, 0x1F, 0x47, 0xB3, 0x1F, 0xA4, 0x30, 0x77,
+ 0x09, 0x5F, 0x96, 0xAD, 0x85, 0xBA, 0x3A, 0x6B,
+ 0x73, 0x4A, 0x7C, 0x8F, 0x36, 0xDF, 0x08, 0xAC,
+ 0xBA, 0x51, 0xC9, 0x37, 0x89, 0x7F, 0x72, 0xF2,
+ 0x1C, 0x3B, 0xBE, 0x5B, 0x54, 0x99, 0x6F, 0xC6,
+ 0x6C, 0x5F, 0x62, 0x68, 0x39, 0xDC, 0x98, 0xDD,
+ 0x1D, 0xE4, 0x19, 0x5B, 0x46, 0xCE, 0xE9, 0x80,
+ 0x3A, 0x0F, 0xD3, 0xDF, 0xC5, 0x7E, 0x23, 0xF6,
+ 0x92, 0xBB, 0x7B, 0x49, 0xB5, 0xD2, 0x12, 0x33,
+ 0x1D, 0x55, 0xB1, 0xCE, 0x2D, 0x72, 0x7A, 0xB4,
+ 0x1A, 0x11, 0xDA, 0x3A, 0x15, 0xF8, 0xE4, 0xBC,
+ 0x11, 0xC7, 0x8B, 0x65, 0xF1, 0xCE, 0xB2, 0x96,
+ 0xF1, 0xFE, 0xDC, 0x5F, 0x7E, 0x42, 0x45, 0x6C,
+ 0x91, 0x11, 0x17, 0x02, 0x52, 0x01, 0xBE, 0x03,
+ 0x89, 0xF5, 0xAB, 0xD4, 0x0D, 0x11, 0xF8, 0x63,
+ 0x9A, 0x39, 0xFE, 0x32, 0x36, 0x75, 0x18, 0x35,
+ 0xA5, 0xE5, 0xE4, 0x43, 0x17, 0xC1, 0xC2, 0xEE,
+ 0xFD, 0x4E, 0xA5, 0xBF, 0xD1, 0x60, 0x43, 0xF4,
+ 0x3C, 0xB4, 0x19, 0x81, 0xF6, 0xAD, 0xEE, 0x9D,
+ 0x03, 0x15, 0x9E, 0x7A, 0xD9, 0xD1, 0x3C, 0x53,
+ 0x36, 0x95, 0x09, 0xFC, 0x1F, 0xA2, 0x7C, 0x16,
+ 0xEF, 0x98, 0x87, 0x70, 0x3A, 0x55, 0xB5, 0x1B,
+ 0x22, 0xCB, 0xF4, 0x4C, 0xD0, 0x12, 0xAE, 0xE0,
+ 0xB2, 0x79, 0x8E, 0x62, 0x84, 0x23, 0x42, 0x8E,
+ 0xFC, 0xD5, 0xA4, 0x0C, 0xAE, 0xF6, 0xBF, 0x50,
+ 0xD8, 0xEA, 0x88, 0x5E, 0xBF, 0x73, 0xA6, 0xB9,
+ 0xFD, 0x79, 0xB5, 0xE1, 0x8F, 0x67, 0xD1, 0x34,
+ 0x1A, 0xC8, 0x23, 0x7A, 0x75, 0xC3, 0xCF, 0xC9,
+ 0x20, 0x04, 0xA1, 0xC5, 0xA4, 0x0E, 0x36, 0x6B,
+ 0xC4, 0x4D, 0x00, 0x17, 0x6A, 0xF7, 0x1C, 0x15,
+ 0xE4, 0x8C, 0x86, 0xD3, 0x7E, 0x01, 0x37, 0x23,
+ 0xCA, 0xAC, 0x72, 0x23, 0xAB, 0x3B, 0xF4, 0xD5,
+ 0x4F, 0x18, 0x28, 0x71, 0x3B, 0x2B, 0x4A, 0x6F,
+ 0xE4, 0x0F, 0xAB, 0x74, 0x40, 0x5C, 0xB7, 0x38,
+ 0xB0, 0x64, 0xC0, 0x6E, 0xCC, 0x76, 0xE9, 0xEF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+/*
+ * RFC 5114, 2.1.
+ * Group 22 - 1024-bit MODP Group with 160-bit Prime Order Subgroup
+ */
+static const u8 dh_group22_generator[] = {
+ 0xA4, 0xD1, 0xCB, 0xD5, 0xC3, 0xFD, 0x34, 0x12,
+ 0x67, 0x65, 0xA4, 0x42, 0xEF, 0xB9, 0x99, 0x05,
+ 0xF8, 0x10, 0x4D, 0xD2, 0x58, 0xAC, 0x50, 0x7F,
+ 0xD6, 0x40, 0x6C, 0xFF, 0x14, 0x26, 0x6D, 0x31,
+ 0x26, 0x6F, 0xEA, 0x1E, 0x5C, 0x41, 0x56, 0x4B,
+ 0x77, 0x7E, 0x69, 0x0F, 0x55, 0x04, 0xF2, 0x13,
+ 0x16, 0x02, 0x17, 0xB4, 0xB0, 0x1B, 0x88, 0x6A,
+ 0x5E, 0x91, 0x54, 0x7F, 0x9E, 0x27, 0x49, 0xF4,
+ 0xD7, 0xFB, 0xD7, 0xD3, 0xB9, 0xA9, 0x2E, 0xE1,
+ 0x90, 0x9D, 0x0D, 0x22, 0x63, 0xF8, 0x0A, 0x76,
+ 0xA6, 0xA2, 0x4C, 0x08, 0x7A, 0x09, 0x1F, 0x53,
+ 0x1D, 0xBF, 0x0A, 0x01, 0x69, 0xB6, 0xA2, 0x8A,
+ 0xD6, 0x62, 0xA4, 0xD1, 0x8E, 0x73, 0xAF, 0xA3,
+ 0x2D, 0x77, 0x9D, 0x59, 0x18, 0xD0, 0x8B, 0xC8,
+ 0x85, 0x8F, 0x4D, 0xCE, 0xF9, 0x7C, 0x2A, 0x24,
+ 0x85, 0x5E, 0x6E, 0xEB, 0x22, 0xB3, 0xB2, 0xE5
+};
+static const u8 dh_group22_prime[] = {
+ 0xB1, 0x0B, 0x8F, 0x96, 0xA0, 0x80, 0xE0, 0x1D,
+ 0xDE, 0x92, 0xDE, 0x5E, 0xAE, 0x5D, 0x54, 0xEC,
+ 0x52, 0xC9, 0x9F, 0xBC, 0xFB, 0x06, 0xA3, 0xC6,
+ 0x9A, 0x6A, 0x9D, 0xCA, 0x52, 0xD2, 0x3B, 0x61,
+ 0x60, 0x73, 0xE2, 0x86, 0x75, 0xA2, 0x3D, 0x18,
+ 0x98, 0x38, 0xEF, 0x1E, 0x2E, 0xE6, 0x52, 0xC0,
+ 0x13, 0xEC, 0xB4, 0xAE, 0xA9, 0x06, 0x11, 0x23,
+ 0x24, 0x97, 0x5C, 0x3C, 0xD4, 0x9B, 0x83, 0xBF,
+ 0xAC, 0xCB, 0xDD, 0x7D, 0x90, 0xC4, 0xBD, 0x70,
+ 0x98, 0x48, 0x8E, 0x9C, 0x21, 0x9A, 0x73, 0x72,
+ 0x4E, 0xFF, 0xD6, 0xFA, 0xE5, 0x64, 0x47, 0x38,
+ 0xFA, 0xA3, 0x1A, 0x4F, 0xF5, 0x5B, 0xCC, 0xC0,
+ 0xA1, 0x51, 0xAF, 0x5F, 0x0D, 0xC8, 0xB4, 0xBD,
+ 0x45, 0xBF, 0x37, 0xDF, 0x36, 0x5C, 0x1A, 0x65,
+ 0xE6, 0x8C, 0xFD, 0xA7, 0x6D, 0x4D, 0xA7, 0x08,
+ 0xDF, 0x1F, 0xB2, 0xBC, 0x2E, 0x4A, 0x43, 0x71
+};
+static const u8 dh_group22_order[] = {
+ 0xF5, 0x18, 0xAA, 0x87, 0x81, 0xA8, 0xDF, 0x27,
+ 0x8A, 0xBA, 0x4E, 0x7D, 0x64, 0xB7, 0xCB, 0x9D,
+ 0x49, 0x46, 0x23, 0x53
+};
+
+/*
+ * RFC 5114, 2.2.
+ * Group 23 - 2048-bit MODP Group with 224-bit Prime Order Subgroup
+ */
+static const u8 dh_group23_generator[] = {
+ 0xAC, 0x40, 0x32, 0xEF, 0x4F, 0x2D, 0x9A, 0xE3,
+ 0x9D, 0xF3, 0x0B, 0x5C, 0x8F, 0xFD, 0xAC, 0x50,
+ 0x6C, 0xDE, 0xBE, 0x7B, 0x89, 0x99, 0x8C, 0xAF,
+ 0x74, 0x86, 0x6A, 0x08, 0xCF, 0xE4, 0xFF, 0xE3,
+ 0xA6, 0x82, 0x4A, 0x4E, 0x10, 0xB9, 0xA6, 0xF0,
+ 0xDD, 0x92, 0x1F, 0x01, 0xA7, 0x0C, 0x4A, 0xFA,
+ 0xAB, 0x73, 0x9D, 0x77, 0x00, 0xC2, 0x9F, 0x52,
+ 0xC5, 0x7D, 0xB1, 0x7C, 0x62, 0x0A, 0x86, 0x52,
+ 0xBE, 0x5E, 0x90, 0x01, 0xA8, 0xD6, 0x6A, 0xD7,
+ 0xC1, 0x76, 0x69, 0x10, 0x19, 0x99, 0x02, 0x4A,
+ 0xF4, 0xD0, 0x27, 0x27, 0x5A, 0xC1, 0x34, 0x8B,
+ 0xB8, 0xA7, 0x62, 0xD0, 0x52, 0x1B, 0xC9, 0x8A,
+ 0xE2, 0x47, 0x15, 0x04, 0x22, 0xEA, 0x1E, 0xD4,
+ 0x09, 0x93, 0x9D, 0x54, 0xDA, 0x74, 0x60, 0xCD,
+ 0xB5, 0xF6, 0xC6, 0xB2, 0x50, 0x71, 0x7C, 0xBE,
+ 0xF1, 0x80, 0xEB, 0x34, 0x11, 0x8E, 0x98, 0xD1,
+ 0x19, 0x52, 0x9A, 0x45, 0xD6, 0xF8, 0x34, 0x56,
+ 0x6E, 0x30, 0x25, 0xE3, 0x16, 0xA3, 0x30, 0xEF,
+ 0xBB, 0x77, 0xA8, 0x6F, 0x0C, 0x1A, 0xB1, 0x5B,
+ 0x05, 0x1A, 0xE3, 0xD4, 0x28, 0xC8, 0xF8, 0xAC,
+ 0xB7, 0x0A, 0x81, 0x37, 0x15, 0x0B, 0x8E, 0xEB,
+ 0x10, 0xE1, 0x83, 0xED, 0xD1, 0x99, 0x63, 0xDD,
+ 0xD9, 0xE2, 0x63, 0xE4, 0x77, 0x05, 0x89, 0xEF,
+ 0x6A, 0xA2, 0x1E, 0x7F, 0x5F, 0x2F, 0xF3, 0x81,
+ 0xB5, 0x39, 0xCC, 0xE3, 0x40, 0x9D, 0x13, 0xCD,
+ 0x56, 0x6A, 0xFB, 0xB4, 0x8D, 0x6C, 0x01, 0x91,
+ 0x81, 0xE1, 0xBC, 0xFE, 0x94, 0xB3, 0x02, 0x69,
+ 0xED, 0xFE, 0x72, 0xFE, 0x9B, 0x6A, 0xA4, 0xBD,
+ 0x7B, 0x5A, 0x0F, 0x1C, 0x71, 0xCF, 0xFF, 0x4C,
+ 0x19, 0xC4, 0x18, 0xE1, 0xF6, 0xEC, 0x01, 0x79,
+ 0x81, 0xBC, 0x08, 0x7F, 0x2A, 0x70, 0x65, 0xB3,
+ 0x84, 0xB8, 0x90, 0xD3, 0x19, 0x1F, 0x2B, 0xFA
+};
+static const u8 dh_group23_prime[] = {
+ 0xAD, 0x10, 0x7E, 0x1E, 0x91, 0x23, 0xA9, 0xD0,
+ 0xD6, 0x60, 0xFA, 0xA7, 0x95, 0x59, 0xC5, 0x1F,
+ 0xA2, 0x0D, 0x64, 0xE5, 0x68, 0x3B, 0x9F, 0xD1,
+ 0xB5, 0x4B, 0x15, 0x97, 0xB6, 0x1D, 0x0A, 0x75,
+ 0xE6, 0xFA, 0x14, 0x1D, 0xF9, 0x5A, 0x56, 0xDB,
+ 0xAF, 0x9A, 0x3C, 0x40, 0x7B, 0xA1, 0xDF, 0x15,
+ 0xEB, 0x3D, 0x68, 0x8A, 0x30, 0x9C, 0x18, 0x0E,
+ 0x1D, 0xE6, 0xB8, 0x5A, 0x12, 0x74, 0xA0, 0xA6,
+ 0x6D, 0x3F, 0x81, 0x52, 0xAD, 0x6A, 0xC2, 0x12,
+ 0x90, 0x37, 0xC9, 0xED, 0xEF, 0xDA, 0x4D, 0xF8,
+ 0xD9, 0x1E, 0x8F, 0xEF, 0x55, 0xB7, 0x39, 0x4B,
+ 0x7A, 0xD5, 0xB7, 0xD0, 0xB6, 0xC1, 0x22, 0x07,
+ 0xC9, 0xF9, 0x8D, 0x11, 0xED, 0x34, 0xDB, 0xF6,
+ 0xC6, 0xBA, 0x0B, 0x2C, 0x8B, 0xBC, 0x27, 0xBE,
+ 0x6A, 0x00, 0xE0, 0xA0, 0xB9, 0xC4, 0x97, 0x08,
+ 0xB3, 0xBF, 0x8A, 0x31, 0x70, 0x91, 0x88, 0x36,
+ 0x81, 0x28, 0x61, 0x30, 0xBC, 0x89, 0x85, 0xDB,
+ 0x16, 0x02, 0xE7, 0x14, 0x41, 0x5D, 0x93, 0x30,
+ 0x27, 0x82, 0x73, 0xC7, 0xDE, 0x31, 0xEF, 0xDC,
+ 0x73, 0x10, 0xF7, 0x12, 0x1F, 0xD5, 0xA0, 0x74,
+ 0x15, 0x98, 0x7D, 0x9A, 0xDC, 0x0A, 0x48, 0x6D,
+ 0xCD, 0xF9, 0x3A, 0xCC, 0x44, 0x32, 0x83, 0x87,
+ 0x31, 0x5D, 0x75, 0xE1, 0x98, 0xC6, 0x41, 0xA4,
+ 0x80, 0xCD, 0x86, 0xA1, 0xB9, 0xE5, 0x87, 0xE8,
+ 0xBE, 0x60, 0xE6, 0x9C, 0xC9, 0x28, 0xB2, 0xB9,
+ 0xC5, 0x21, 0x72, 0xE4, 0x13, 0x04, 0x2E, 0x9B,
+ 0x23, 0xF1, 0x0B, 0x0E, 0x16, 0xE7, 0x97, 0x63,
+ 0xC9, 0xB5, 0x3D, 0xCF, 0x4B, 0xA8, 0x0A, 0x29,
+ 0xE3, 0xFB, 0x73, 0xC1, 0x6B, 0x8E, 0x75, 0xB9,
+ 0x7E, 0xF3, 0x63, 0xE2, 0xFF, 0xA3, 0x1F, 0x71,
+ 0xCF, 0x9D, 0xE5, 0x38, 0x4E, 0x71, 0xB8, 0x1C,
+ 0x0A, 0xC4, 0xDF, 0xFE, 0x0C, 0x10, 0xE6, 0x4F
+};
+static const u8 dh_group23_order[] = {
+ 0x80, 0x1C, 0x0D, 0x34, 0xC5, 0x8D, 0x93, 0xFE,
+ 0x99, 0x71, 0x77, 0x10, 0x1F, 0x80, 0x53, 0x5A,
+ 0x47, 0x38, 0xCE, 0xBC, 0xBF, 0x38, 0x9A, 0x99,
+ 0xB3, 0x63, 0x71, 0xEB
+};
+
+/*
+ * RFC 5114, 2.3.
+ * Group 24 - 2048-bit MODP Group with 256-bit Prime Order Subgroup
+ */
+static const u8 dh_group24_generator[] = {
+ 0x3F, 0xB3, 0x2C, 0x9B, 0x73, 0x13, 0x4D, 0x0B,
+ 0x2E, 0x77, 0x50, 0x66, 0x60, 0xED, 0xBD, 0x48,
+ 0x4C, 0xA7, 0xB1, 0x8F, 0x21, 0xEF, 0x20, 0x54,
+ 0x07, 0xF4, 0x79, 0x3A, 0x1A, 0x0B, 0xA1, 0x25,
+ 0x10, 0xDB, 0xC1, 0x50, 0x77, 0xBE, 0x46, 0x3F,
+ 0xFF, 0x4F, 0xED, 0x4A, 0xAC, 0x0B, 0xB5, 0x55,
+ 0xBE, 0x3A, 0x6C, 0x1B, 0x0C, 0x6B, 0x47, 0xB1,
+ 0xBC, 0x37, 0x73, 0xBF, 0x7E, 0x8C, 0x6F, 0x62,
+ 0x90, 0x12, 0x28, 0xF8, 0xC2, 0x8C, 0xBB, 0x18,
+ 0xA5, 0x5A, 0xE3, 0x13, 0x41, 0x00, 0x0A, 0x65,
+ 0x01, 0x96, 0xF9, 0x31, 0xC7, 0x7A, 0x57, 0xF2,
+ 0xDD, 0xF4, 0x63, 0xE5, 0xE9, 0xEC, 0x14, 0x4B,
+ 0x77, 0x7D, 0xE6, 0x2A, 0xAA, 0xB8, 0xA8, 0x62,
+ 0x8A, 0xC3, 0x76, 0xD2, 0x82, 0xD6, 0xED, 0x38,
+ 0x64, 0xE6, 0x79, 0x82, 0x42, 0x8E, 0xBC, 0x83,
+ 0x1D, 0x14, 0x34, 0x8F, 0x6F, 0x2F, 0x91, 0x93,
+ 0xB5, 0x04, 0x5A, 0xF2, 0x76, 0x71, 0x64, 0xE1,
+ 0xDF, 0xC9, 0x67, 0xC1, 0xFB, 0x3F, 0x2E, 0x55,
+ 0xA4, 0xBD, 0x1B, 0xFF, 0xE8, 0x3B, 0x9C, 0x80,
+ 0xD0, 0x52, 0xB9, 0x85, 0xD1, 0x82, 0xEA, 0x0A,
+ 0xDB, 0x2A, 0x3B, 0x73, 0x13, 0xD3, 0xFE, 0x14,
+ 0xC8, 0x48, 0x4B, 0x1E, 0x05, 0x25, 0x88, 0xB9,
+ 0xB7, 0xD2, 0xBB, 0xD2, 0xDF, 0x01, 0x61, 0x99,
+ 0xEC, 0xD0, 0x6E, 0x15, 0x57, 0xCD, 0x09, 0x15,
+ 0xB3, 0x35, 0x3B, 0xBB, 0x64, 0xE0, 0xEC, 0x37,
+ 0x7F, 0xD0, 0x28, 0x37, 0x0D, 0xF9, 0x2B, 0x52,
+ 0xC7, 0x89, 0x14, 0x28, 0xCD, 0xC6, 0x7E, 0xB6,
+ 0x18, 0x4B, 0x52, 0x3D, 0x1D, 0xB2, 0x46, 0xC3,
+ 0x2F, 0x63, 0x07, 0x84, 0x90, 0xF0, 0x0E, 0xF8,
+ 0xD6, 0x47, 0xD1, 0x48, 0xD4, 0x79, 0x54, 0x51,
+ 0x5E, 0x23, 0x27, 0xCF, 0xEF, 0x98, 0xC5, 0x82,
+ 0x66, 0x4B, 0x4C, 0x0F, 0x6C, 0xC4, 0x16, 0x59
+};
+static const u8 dh_group24_prime[] = {
+ 0x87, 0xA8, 0xE6, 0x1D, 0xB4, 0xB6, 0x66, 0x3C,
+ 0xFF, 0xBB, 0xD1, 0x9C, 0x65, 0x19, 0x59, 0x99,
+ 0x8C, 0xEE, 0xF6, 0x08, 0x66, 0x0D, 0xD0, 0xF2,
+ 0x5D, 0x2C, 0xEE, 0xD4, 0x43, 0x5E, 0x3B, 0x00,
+ 0xE0, 0x0D, 0xF8, 0xF1, 0xD6, 0x19, 0x57, 0xD4,
+ 0xFA, 0xF7, 0xDF, 0x45, 0x61, 0xB2, 0xAA, 0x30,
+ 0x16, 0xC3, 0xD9, 0x11, 0x34, 0x09, 0x6F, 0xAA,
+ 0x3B, 0xF4, 0x29, 0x6D, 0x83, 0x0E, 0x9A, 0x7C,
+ 0x20, 0x9E, 0x0C, 0x64, 0x97, 0x51, 0x7A, 0xBD,
+ 0x5A, 0x8A, 0x9D, 0x30, 0x6B, 0xCF, 0x67, 0xED,
+ 0x91, 0xF9, 0xE6, 0x72, 0x5B, 0x47, 0x58, 0xC0,
+ 0x22, 0xE0, 0xB1, 0xEF, 0x42, 0x75, 0xBF, 0x7B,
+ 0x6C, 0x5B, 0xFC, 0x11, 0xD4, 0x5F, 0x90, 0x88,
+ 0xB9, 0x41, 0xF5, 0x4E, 0xB1, 0xE5, 0x9B, 0xB8,
+ 0xBC, 0x39, 0xA0, 0xBF, 0x12, 0x30, 0x7F, 0x5C,
+ 0x4F, 0xDB, 0x70, 0xC5, 0x81, 0xB2, 0x3F, 0x76,
+ 0xB6, 0x3A, 0xCA, 0xE1, 0xCA, 0xA6, 0xB7, 0x90,
+ 0x2D, 0x52, 0x52, 0x67, 0x35, 0x48, 0x8A, 0x0E,
+ 0xF1, 0x3C, 0x6D, 0x9A, 0x51, 0xBF, 0xA4, 0xAB,
+ 0x3A, 0xD8, 0x34, 0x77, 0x96, 0x52, 0x4D, 0x8E,
+ 0xF6, 0xA1, 0x67, 0xB5, 0xA4, 0x18, 0x25, 0xD9,
+ 0x67, 0xE1, 0x44, 0xE5, 0x14, 0x05, 0x64, 0x25,
+ 0x1C, 0xCA, 0xCB, 0x83, 0xE6, 0xB4, 0x86, 0xF6,
+ 0xB3, 0xCA, 0x3F, 0x79, 0x71, 0x50, 0x60, 0x26,
+ 0xC0, 0xB8, 0x57, 0xF6, 0x89, 0x96, 0x28, 0x56,
+ 0xDE, 0xD4, 0x01, 0x0A, 0xBD, 0x0B, 0xE6, 0x21,
+ 0xC3, 0xA3, 0x96, 0x0A, 0x54, 0xE7, 0x10, 0xC3,
+ 0x75, 0xF2, 0x63, 0x75, 0xD7, 0x01, 0x41, 0x03,
+ 0xA4, 0xB5, 0x43, 0x30, 0xC1, 0x98, 0xAF, 0x12,
+ 0x61, 0x16, 0xD2, 0x27, 0x6E, 0x11, 0x71, 0x5F,
+ 0x69, 0x38, 0x77, 0xFA, 0xD7, 0xEF, 0x09, 0xCA,
+ 0xDB, 0x09, 0x4A, 0xE9, 0x1E, 0x1A, 0x15, 0x97
+};
+static const u8 dh_group24_order[] = {
+ 0x8C, 0xF8, 0x36, 0x42, 0xA7, 0x09, 0xA0, 0x97,
+ 0xB4, 0x47, 0x99, 0x76, 0x40, 0x12, 0x9D, 0xA2,
+ 0x99, 0xB1, 0xA4, 0x7D, 0x1E, 0xB3, 0x75, 0x0B,
+ 0xA3, 0x08, 0xB0, 0xFE, 0x64, 0xF5, 0xFB, 0xD3
+};
#endif /* ALL_DH_GROUPS */
-#define DH_GROUP(id) \
+#define DH_GROUP(id,safe) \
{ id, dh_group ## id ## _generator, sizeof(dh_group ## id ## _generator), \
-dh_group ## id ## _prime, sizeof(dh_group ## id ## _prime) }
+dh_group ## id ## _prime, sizeof(dh_group ## id ## _prime), \
+dh_group ## id ## _order, sizeof(dh_group ## id ## _order), safe }
static struct dh_group dh_groups[] = {
- DH_GROUP(5),
+ DH_GROUP(5, 1),
#ifdef ALL_DH_GROUPS
- DH_GROUP(1),
- DH_GROUP(2),
- DH_GROUP(14),
- DH_GROUP(15),
- DH_GROUP(16),
- DH_GROUP(17),
- DH_GROUP(18)
+ DH_GROUP(1, 1),
+ DH_GROUP(2, 1),
+ DH_GROUP(14, 1),
+ DH_GROUP(15, 1),
+ DH_GROUP(16, 1),
+ DH_GROUP(17, 1),
+ DH_GROUP(18, 1),
+ DH_GROUP(22, 0),
+ DH_GROUP(23, 0),
+ DH_GROUP(24, 0)
#endif /* ALL_DH_GROUPS */
};
diff --git a/src/crypto/dh_groups.h b/src/crypto/dh_groups.h
index 225f006..d0e74b9 100644
--- a/src/crypto/dh_groups.h
+++ b/src/crypto/dh_groups.h
@@ -15,6 +15,9 @@
size_t generator_len;
const u8 *prime;
size_t prime_len;
+ const u8 *order;
+ size_t order_len;
+ unsigned int safe_prime:1;
};
const struct dh_group * dh_groups_get(int id);
diff --git a/src/crypto/md5-internal.c b/src/crypto/md5-internal.c
index 790a6f3..f0a2a5d 100644
--- a/src/crypto/md5-internal.c
+++ b/src/crypto/md5-internal.c
@@ -176,8 +176,8 @@
byteReverse(ctx->in, 14);
/* Append length in bits and transform */
- ((u32 *) ctx->in)[14] = ctx->bits[0];
- ((u32 *) ctx->in)[15] = ctx->bits[1];
+ ((u32 *) aliasing_hide_typecast(ctx->in, u32))[14] = ctx->bits[0];
+ ((u32 *) aliasing_hide_typecast(ctx->in, u32))[15] = ctx->bits[1];
MD5Transform(ctx->buf, (u32 *) ctx->in);
byteReverse((unsigned char *) ctx->buf, 4);
diff --git a/src/crypto/sha256-prf.c b/src/crypto/sha256-prf.c
index 0da6d13..9a11208 100644
--- a/src/crypto/sha256-prf.c
+++ b/src/crypto/sha256-prf.c
@@ -1,6 +1,6 @@
/*
* SHA256-based PRF (IEEE 802.11r)
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -29,12 +29,36 @@
void sha256_prf(const u8 *key, size_t key_len, const char *label,
const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
{
+ sha256_prf_bits(key, key_len, label, data, data_len, buf, buf_len * 8);
+}
+
+
+/**
+ * sha256_prf_bits - IEEE Std 802.11-2012, 11.6.1.7.2 Key derivation function
+ * @key: Key for KDF
+ * @key_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @data: Extra data to bind into the key
+ * @data_len: Length of the data
+ * @buf: Buffer for the generated pseudo-random key
+ * @buf_len: Number of bits of key to generate
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key. If the requested buf_len is not divisible by eight, the least
+ * significant 1-7 bits of the last octet in the output are not part of the
+ * requested output.
+ */
+void sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf,
+ size_t buf_len_bits)
+{
u16 counter = 1;
size_t pos, plen;
u8 hash[SHA256_MAC_LEN];
const u8 *addr[4];
size_t len[4];
u8 counter_le[2], length_le[2];
+ size_t buf_len = (buf_len_bits + 7) / 8;
addr[0] = counter_le;
len[0] = 2;
@@ -45,7 +69,7 @@
addr[3] = length_le;
len[3] = sizeof(length_le);
- WPA_PUT_LE16(length_le, buf_len * 8);
+ WPA_PUT_LE16(length_le, buf_len_bits);
pos = 0;
while (pos < buf_len) {
plen = buf_len - pos;
@@ -57,8 +81,18 @@
} else {
hmac_sha256_vector(key, key_len, 4, addr, len, hash);
os_memcpy(&buf[pos], hash, plen);
+ pos += plen;
break;
}
counter++;
}
+
+ /*
+ * Mask out unused bits in the last octet if it does not use all the
+ * bits.
+ */
+ if (buf_len_bits % 8) {
+ u8 mask = 0xff << (8 - buf_len_bits % 8);
+ buf[pos - 1] &= mask;
+ }
}
diff --git a/src/crypto/sha256.h b/src/crypto/sha256.h
index fcac800..7596a52 100644
--- a/src/crypto/sha256.h
+++ b/src/crypto/sha256.h
@@ -1,6 +1,6 @@
/*
* SHA256 hash implementation and interface functions
- * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -17,6 +17,9 @@
size_t data_len, u8 *mac);
void sha256_prf(const u8 *key, size_t key_len, const char *label,
const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
+void sha256_prf_bits(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf,
+ size_t buf_len_bits);
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);
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index e9f926f..14b64a6 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -41,7 +41,7 @@
/**
* freq - Frequency in MHz
*/
- short freq;
+ int freq;
/**
* flag - Channel flags (HOSTAPD_CHAN_*)
@@ -122,6 +122,13 @@
#define IEEE80211_CAP_IBSS 0x0002
#define IEEE80211_CAP_PRIVACY 0x0010
+/* DMG (60 GHz) IEEE 802.11ad */
+/* type - bits 0..1 */
+#define IEEE80211_CAP_DMG_MASK 0x0003
+#define IEEE80211_CAP_DMG_IBSS 0x0001 /* Tx by: STA */
+#define IEEE80211_CAP_DMG_PBSS 0x0002 /* Tx by: PCP */
+#define IEEE80211_CAP_DMG_AP 0x0003 /* Tx by: AP */
+
#define WPA_SCAN_QUAL_INVALID BIT(0)
#define WPA_SCAN_NOISE_INVALID BIT(1)
#define WPA_SCAN_LEVEL_INVALID BIT(2)
@@ -180,10 +187,12 @@
* struct wpa_scan_results - Scan results
* @res: Array of pointers to allocated variable length scan result entries
* @num: Number of entries in the scan result array
+ * @fetch_time: Time when the results were fetched from the driver
*/
struct wpa_scan_results {
struct wpa_scan_res **res;
size_t num;
+ struct os_time fetch_time;
};
/**
@@ -314,6 +323,9 @@
*/
int p2p;
+ const u8 *sae_data;
+ size_t sae_data_len;
+
};
enum wps_mode {
@@ -556,6 +568,19 @@
*/
const u8 *htcaps; /* struct ieee80211_ht_capabilities * */
const u8 *htcaps_mask; /* struct ieee80211_ht_capabilities * */
+
+#ifdef CONFIG_VHT_OVERRIDES
+ /**
+ * disable_vht - Disable VHT for this connection
+ */
+ int disable_vht;
+
+ /**
+ * VHT capability overrides.
+ */
+ const struct ieee80211_vht_capabilities *vhtcaps;
+ const struct ieee80211_vht_capabilities *vhtcaps_mask;
+#endif /* CONFIG_VHT_OVERRIDES */
};
enum hide_ssid {
@@ -758,6 +783,7 @@
#define WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE 0x00000010
#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
unsigned int key_mgmt;
#define WPA_DRIVER_CAPA_ENC_WEP40 0x00000001
@@ -834,6 +860,12 @@
#define WPA_DRIVER_FLAGS_INACTIVITY_TIMER 0x00800000
/* Driver expects user space implementation of MLME in AP mode */
#define WPA_DRIVER_FLAGS_AP_MLME 0x01000000
+/* Driver supports SAE with user space SME */
+#define WPA_DRIVER_FLAGS_SAE 0x02000000
+/* Driver makes use of OBSS scan mechanism in wpa_supplicant */
+#define WPA_DRIVER_FLAGS_OBSS_SCAN 0x04000000
+/* Driver supports IBSS (Ad-hoc) mode */
+#define WPA_DRIVER_FLAGS_IBSS 0x08000000
unsigned int flags;
int max_scan_ssids;
@@ -865,6 +897,15 @@
/* Driver Probe Response offloading support for IEEE 802.11u (Interworking) */
#define WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING 0x00000008
unsigned int probe_resp_offloads;
+
+ /**
+ * extended_capa - extended capabilities in driver/device
+ *
+ * Must be allocated and freed by driver and the pointers must be
+ * valid for the lifetime of the driver, i.e., freed in deinit()
+ */
+ const u8 *extended_capa, *extended_capa_mask;
+ unsigned int extended_capa_len;
};
@@ -890,19 +931,31 @@
size_t supp_rates_len;
u16 listen_interval;
const struct ieee80211_ht_capabilities *ht_capabilities;
+ const struct ieee80211_vht_capabilities *vht_capabilities;
u32 flags; /* bitmask of WPA_STA_* flags */
int set; /* Set STA parameters instead of add */
u8 qosinfo;
+ const u8 *ext_capab;
+ size_t ext_capab_len;
};
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 */
+
+ /* for VHT */
+ 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;
+ int bandwidth;
};
enum wpa_driver_if_type {
@@ -1195,17 +1248,6 @@
int (*deauthenticate)(void *priv, const u8 *addr, int reason_code);
/**
- * disassociate - Request driver to disassociate
- * @priv: private driver interface data
- * @addr: peer address (BSSID of the AP)
- * @reason_code: 16-bit reason code to be sent in the disassociation
- * frame
- *
- * Returns: 0 on success, -1 on failure
- */
- int (*disassociate)(void *priv, const u8 *addr, int reason_code);
-
- /**
* associate - Request driver to associate
* @priv: private driver interface data
* @params: association parameters
@@ -3060,7 +3102,16 @@
*
* This event can be used to request a WNM operation to be performed.
*/
- EVENT_WNM
+ EVENT_WNM,
+
+ /**
+ * EVENT_CONNECT_FAILED_REASON - Connection failure reason in AP mode
+ *
+ * This event indicates that the driver reported a connection failure
+ * with the specified client (for example, max client reached, etc.) in
+ * AP mode.
+ */
+ EVENT_CONNECT_FAILED_REASON
};
@@ -3685,6 +3736,19 @@
int ht_enabled;
int ch_offset;
} ch_switch;
+
+ /**
+ * struct connect_failed - Data for EVENT_CONNECT_FAILED_REASON
+ * @addr: Remote client address
+ * @code: Reason code for connection failure
+ */
+ struct connect_failed_reason {
+ u8 addr[ETH_ALEN];
+ enum {
+ MAX_CLIENT_REACHED,
+ BLOCKED_CLIENT
+ } code;
+ } connect_failed_reason;
};
/**
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index 5f2e675..c2f5934 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -874,7 +874,7 @@
}
#endif /* CONFIG_HS20 */
-#if defined(CONFIG_IEEE80211V) && !defined(CONFIG_IEEE80211R)
+#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)
{
@@ -921,9 +921,9 @@
break;
}
}
-#endif /* CONFIG_IEEE80211V */
+#endif /* CONFIG_WNM */
-#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211V)
+#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)
{
@@ -933,9 +933,9 @@
#ifdef CONFIG_IEEE80211R
atheros_raw_recv_11r(ctx, src_addr, buf, len);
#endif /* CONFIG_IEEE80211R */
-#if defined(CONFIG_IEEE80211V) && !defined(CONFIG_IEEE80211R)
+#if defined(CONFIG_WNM) && !defined(CONFIG_IEEE80211R)
atheros_raw_recv_11v(ctx, src_addr, buf, len);
-#endif /* CONFIG_IEEE80211V */
+#endif /* CONFIG_WNM */
#ifdef CONFIG_HS20
atheros_raw_recv_hs20(ctx, src_addr, buf, len);
#endif /* CONFIG_HS20 */
@@ -957,9 +957,9 @@
IEEE80211_FILTER_TYPE_AUTH |
IEEE80211_FILTER_TYPE_ACTION);
#endif
-#ifdef CONFIG_IEEE80211V
+#ifdef CONFIG_WNM
filt.app_filterype |= IEEE80211_FILTER_TYPE_ACTION;
-#endif /* CONFIG_IEEE80211V */
+#endif /* CONFIG_WNM */
#ifdef CONFIG_HS20
filt.app_filterype |= IEEE80211_FILTER_TYPE_ACTION;
#endif /* CONFIG_HS20 */
@@ -976,8 +976,6 @@
if (drv->sock_raw == NULL)
return -1;
#endif /* CONFIG_WPS || CONFIG_IEEE80211R */
- if (l2_packet_get_own_addr(drv->sock_xmit, drv->own_addr))
- return -1;
return ret;
}
@@ -1656,6 +1654,7 @@
goto bad;
if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr))
goto bad;
+ os_memcpy(drv->own_addr, params->own_addr, ETH_ALEN);
if (params->bridge[0]) {
wpa_printf(MSG_DEBUG, "Configure bridge %s for EAPOL traffic.",
params->bridge[0]);
@@ -1689,13 +1688,17 @@
linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0);
atheros_set_privacy(drv, 0); /* default to no privacy */
- atheros_receive_pkt(drv);
+ if (atheros_receive_pkt(drv))
+ goto bad;
if (atheros_wireless_event_init(drv))
goto bad;
return drv;
bad:
+ atheros_reset_appfilter(drv);
+ if (drv->sock_raw)
+ l2_packet_deinit(drv->sock_raw);
if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit)
l2_packet_deinit(drv->sock_recv);
if (drv->sock_xmit != NULL)
@@ -1960,7 +1963,7 @@
}
-#ifdef CONFIG_IEEE80211V
+#ifdef CONFIG_WNM
static int athr_wnm_tfs(struct atheros_driver_data *drv, const u8* peer,
u8 *ie, u16 *len, enum wnm_oper oper)
{
@@ -2113,7 +2116,7 @@
return -1;
}
}
-#endif /* CONFIG_IEEE80211V */
+#endif /* CONFIG_WNM */
const struct wpa_driver_ops wpa_driver_atheros_ops = {
@@ -2147,7 +2150,7 @@
.add_sta_node = atheros_add_sta_node,
#endif /* CONFIG_IEEE80211R */
.send_action = atheros_send_action,
-#ifdef CONFIG_IEEE80211V
+#ifdef CONFIG_WNM
.wnm_oper = atheros_wnm_oper,
-#endif /* CONFIG_IEEE80211V */
+#endif /* CONFIG_WNM */
};
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index a2b34c1..9d869b1 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -973,13 +973,6 @@
}
static int
-wpa_driver_bsd_disassociate(void *priv, const u8 *addr, int reason_code)
-{
- return bsd_send_mlme_param(priv, IEEE80211_MLME_DISASSOC, reason_code,
- addr);
-}
-
-static int
wpa_driver_bsd_set_auth_alg(void *priv, int auth_alg)
{
int authmode;
@@ -1564,7 +1557,6 @@
.scan2 = wpa_driver_bsd_scan,
.get_scan_results2 = wpa_driver_bsd_get_scan_results2,
.deauthenticate = wpa_driver_bsd_deauthenticate,
- .disassociate = wpa_driver_bsd_disassociate,
.associate = wpa_driver_bsd_associate,
.get_capa = wpa_driver_bsd_get_capa,
#endif /* HOSTAPD */
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index 418cf1a..565a01b 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -79,6 +79,7 @@
E2S(EAPOL_TX_STATUS);
E2S(CH_SWITCH);
E2S(WNM);
+ E2S(CONNECT_FAILED_REASON);
}
return "UNKNOWN";
diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c
index b9e096c..7af3317 100644
--- a/src/drivers/driver_ndis.c
+++ b/src/drivers/driver_ndis.c
@@ -725,14 +725,6 @@
}
-static int wpa_driver_ndis_disassociate(void *priv, const u8 *addr,
- int reason_code)
-{
- struct wpa_driver_ndis_data *drv = priv;
- return wpa_driver_ndis_disconnect(drv);
-}
-
-
static void wpa_driver_ndis_scan_timeout(void *eloop_ctx, void *timeout_ctx)
{
wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
@@ -3223,7 +3215,6 @@
wpa_driver_ndis_ops.init = wpa_driver_ndis_init;
wpa_driver_ndis_ops.deinit = wpa_driver_ndis_deinit;
wpa_driver_ndis_ops.deauthenticate = wpa_driver_ndis_deauthenticate;
- wpa_driver_ndis_ops.disassociate = wpa_driver_ndis_disassociate;
wpa_driver_ndis_ops.associate = wpa_driver_ndis_associate;
wpa_driver_ndis_ops.add_pmkid = wpa_driver_ndis_add_pmkid;
wpa_driver_ndis_ops.remove_pmkid = wpa_driver_ndis_remove_pmkid;
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 4574938..c59d5bf 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -178,7 +178,6 @@
};
static void nl80211_global_deinit(void *priv);
-static void wpa_driver_nl80211_deinit(void *priv);
struct i802_bss {
struct wpa_driver_nl80211_data *drv;
@@ -195,6 +194,7 @@
int freq;
+ void *ctx;
struct nl_handle *nl_preq, *nl_mgmt;
struct nl_cb *nl_cb;
@@ -214,6 +214,8 @@
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;
@@ -244,6 +246,7 @@
unsigned int scan_for_auth:1;
unsigned int retry_auth:1;
unsigned int use_monitor:1;
+ unsigned int ignore_next_local_disconnect:1;
u64 remain_on_chan_cookie;
u64 send_action_cookie;
@@ -284,6 +287,7 @@
};
+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,
@@ -299,7 +303,8 @@
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 wpa_driver_nl80211_probe_req_report(void *priv, int report);
+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);
@@ -318,7 +323,7 @@
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(void *priv,
+static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
enum wpa_driver_if_type type,
const char *ifname);
#else /* HOSTAPD */
@@ -340,7 +345,8 @@
size_t buf_len);
#endif
-static int i802_set_freq(void *priv, struct hostapd_freq_params *freq);
+static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
+ struct hostapd_freq_params *freq);
static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
int ifindex, int disabled);
@@ -1038,6 +1044,7 @@
const struct ieee80211_mgmt *mgmt;
union wpa_event_data event;
+ 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 "
@@ -1049,6 +1056,8 @@
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;
@@ -1097,6 +1106,7 @@
union wpa_event_data event;
u16 status;
+ 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 "
@@ -1153,6 +1163,11 @@
return;
}
+ if (cmd == NL80211_CMD_CONNECT)
+ wpa_printf(MSG_DEBUG, "nl80211: Connect event");
+ else if (cmd == NL80211_CMD_ROAM)
+ wpa_printf(MSG_DEBUG, "nl80211: Roam event");
+
os_memset(&event, 0, sizeof(event));
if (cmd == NL80211_CMD_CONNECT &&
nla_get_u16(status) != WLAN_STATUS_SUCCESS) {
@@ -1191,6 +1206,7 @@
struct nlattr *by_ap)
{
union wpa_event_data data;
+ unsigned int locally_generated = by_ap == NULL;
if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
/*
@@ -1202,6 +1218,19 @@
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");
drv->associated = 0;
os_memset(&data, 0, sizeof(data));
if (reason)
@@ -1279,6 +1308,7 @@
u16 fc, stype;
int ssi_signal = 0;
+ wpa_printf(MSG_DEBUG, "nl80211: Frame event");
mgmt = (const struct ieee80211_mgmt *) frame;
if (len < 24) {
wpa_printf(MSG_DEBUG, "nl80211: Too short action frame");
@@ -1321,6 +1351,7 @@
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;
@@ -1360,6 +1391,11 @@
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;
@@ -1420,6 +1456,11 @@
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;
@@ -1502,7 +1543,7 @@
}
-static void mlme_event_michael_mic_failure(struct wpa_driver_nl80211_data *drv,
+static void mlme_event_michael_mic_failure(struct i802_bss *bss,
struct nlattr *tb[])
{
union wpa_event_data data;
@@ -1534,7 +1575,7 @@
wpa_printf(MSG_DEBUG, "nl80211: Key Id %d", key_id);
}
- wpa_supplicant_event(drv->ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+ wpa_supplicant_event(bss->ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
}
@@ -1603,6 +1644,34 @@
}
+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[])
{
@@ -2046,6 +2115,8 @@
};
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,
@@ -2071,6 +2142,8 @@
{
union wpa_event_data data;
+ wpa_printf(MSG_DEBUG, "nl80211: Probe client event");
+
if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_ACK])
return;
@@ -2082,6 +2155,80 @@
}
+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_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_spurious_frame(struct i802_bss *bss, struct nlattr **tb,
int wds)
{
@@ -2100,9 +2247,11 @@
}
-static void do_process_drv_event(struct wpa_driver_nl80211_data *drv,
- int cmd, struct nlattr **tb)
+static void do_process_drv_event(struct i802_bss *bss, int cmd,
+ struct nlattr **tb)
{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
(cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
cmd == NL80211_CMD_SCAN_ABORTED)) {
@@ -2113,29 +2262,30 @@
switch (cmd) {
case NL80211_CMD_TRIGGER_SCAN:
- wpa_printf(MSG_DEBUG, "nl80211: Scan trigger");
+ wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan trigger");
break;
case NL80211_CMD_START_SCHED_SCAN:
- wpa_printf(MSG_DEBUG, "nl80211: Sched scan started");
+ wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan started");
break;
case NL80211_CMD_SCHED_SCAN_STOPPED:
- wpa_printf(MSG_DEBUG, "nl80211: Sched scan stopped");
+ wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan stopped");
wpa_supplicant_event(drv->ctx, EVENT_SCHED_SCAN_STOPPED, NULL);
break;
case NL80211_CMD_NEW_SCAN_RESULTS:
- wpa_printf(MSG_DEBUG, "nl80211: New scan results available");
+ wpa_dbg(drv->ctx, MSG_DEBUG,
+ "nl80211: New scan results available");
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_printf(MSG_DEBUG,
- "nl80211: New sched scan results available");
+ wpa_dbg(drv->ctx, MSG_DEBUG,
+ "nl80211: New sched scan results available");
send_scan_event(drv, 0, tb);
break;
case NL80211_CMD_SCAN_ABORTED:
- wpa_printf(MSG_DEBUG, "nl80211: Scan aborted");
+ wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan aborted");
/*
* Need to indicate that scan results are available in order
* not to make wpa_supplicant stop its scanning.
@@ -2175,7 +2325,7 @@
tb[NL80211_ATTR_DISCONNECTED_BY_AP]);
break;
case NL80211_CMD_MICHAEL_MIC_FAILURE:
- mlme_event_michael_mic_failure(drv, tb);
+ mlme_event_michael_mic_failure(bss, tb);
break;
case NL80211_CMD_JOIN_IBSS:
mlme_event_join_ibss(drv, tb);
@@ -2214,9 +2364,18 @@
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;
default:
- wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
- "(cmd=%d)", cmd);
+ wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
+ "(cmd=%d)", cmd);
break;
}
}
@@ -2227,21 +2386,25 @@
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]) {
- int ifindex = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
- if (ifindex != drv->ifindex && !have_ifidx(drv, ifindex)) {
- wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d)"
- " for foreign interface (ifindex %d)",
- gnlh->cmd, ifindex);
+ 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;
}
}
- do_process_drv_event(drv, gnlh->cmd, tb);
+ wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d) for foreign "
+ "interface (ifindex %d)", gnlh->cmd, ifidx);
+
return NL_SKIP;
}
@@ -2253,6 +2416,7 @@
struct nlattr *tb[NL80211_ATTR_MAX + 1];
struct wpa_driver_nl80211_data *drv, *tmp;
int ifidx = -1;
+ struct i802_bss *bss;
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
genlmsg_attrlen(gnlh, 0), NULL);
@@ -2262,9 +2426,12 @@
dl_list_for_each_safe(drv, tmp, &global->interfaces,
struct wpa_driver_nl80211_data, list) {
- if (ifidx == -1 || ifidx == drv->ifindex ||
- have_ifidx(drv, ifidx))
- do_process_drv_event(drv, gnlh->cmd, tb);
+ 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;
+ }
+ }
}
return NL_SKIP;
@@ -2352,7 +2519,44 @@
}
+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 error:1;
@@ -2360,6 +2564,12 @@
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 p2p_multichan_concurrent:1;
};
@@ -2380,15 +2590,45 @@
}
-static int wiphy_info_handler(struct nl_msg *msg, void *arg)
+static void wiphy_info_supported_iftypes(struct wiphy_info_data *info,
+ struct nlattr *tb)
{
- struct nlattr *tb[NL80211_ATTR_MAX + 1];
- struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
- struct wiphy_info_data *info = arg;
- int p2p_go_supported = 0, p2p_client_supported = 0;
- int p2p_concurrent = 0, p2p_multichan_concurrent = 0;
- int auth_supported = 0, connect_supported = 0;
- struct wpa_driver_capa *capa = info->capa;
+ 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_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 },
@@ -2401,6 +2641,165 @@
[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 */
+
+ 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) {
+ info->p2p_concurrent = 1;
+ if (nla_get_u32(tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]) > 1)
+ info->p2p_multichan_concurrent = 1;
+ return 1;
+ }
+
+ 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;
+ }
+ }
+}
+
+
+static void wiphy_info_max_roc(struct wpa_driver_capa *capa,
+ struct nlattr *tb)
+{
+ /* default to 5000 since early versions of mac80211 don't set it */
+ capa->max_remain_on_chan = 5000;
+
+ 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;
+}
+
+
+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 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);
@@ -2416,109 +2815,9 @@
capa->max_match_sets =
nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]);
- if (tb[NL80211_ATTR_SUPPORTED_IFTYPES]) {
- struct nlattr *nl_mode;
- int i;
- nla_for_each_nested(nl_mode,
- tb[NL80211_ATTR_SUPPORTED_IFTYPES], i) {
- switch (nla_type(nl_mode)) {
- case NL80211_IFTYPE_AP:
- capa->flags |= WPA_DRIVER_FLAGS_AP;
- break;
- case NL80211_IFTYPE_P2P_GO:
- p2p_go_supported = 1;
- break;
- case NL80211_IFTYPE_P2P_CLIENT:
- p2p_client_supported = 1;
- break;
- case NL80211_IFTYPE_MONITOR:
- info->monitor_supported = 1;
- break;
- }
- }
- }
-
- if (tb[NL80211_ATTR_INTERFACE_COMBINATIONS]) {
- struct nlattr *nl_combi;
- int rem_combi;
-
- nla_for_each_nested(nl_combi,
- tb[NL80211_ATTR_INTERFACE_COMBINATIONS],
- rem_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;
-
- 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])
- goto broken_combination;
-
- 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])
- goto 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) {
- p2p_concurrent = 1;
- if (nla_get_u32(tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]) > 1)
- p2p_multichan_concurrent = 1;
- break;
- }
-
-broken_combination:
- ;
- }
- }
-
- if (tb[NL80211_ATTR_SUPPORTED_COMMANDS]) {
- struct nlattr *nl_cmd;
- int i;
-
- nla_for_each_nested(nl_cmd,
- tb[NL80211_ATTR_SUPPORTED_COMMANDS], i) {
- switch (nla_get_u32(nl_cmd)) {
- case NL80211_CMD_AUTHENTICATE:
- auth_supported = 1;
- break;
- case NL80211_CMD_CONNECT:
- connect_supported = 1;
- break;
- case NL80211_CMD_START_SCHED_SCAN:
- capa->sched_scan_supported = 1;
- break;
- case NL80211_CMD_PROBE_CLIENT:
- info->poll_command_supported = 1;
- break;
- }
- }
- }
+ 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]);
if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) {
wpa_printf(MSG_DEBUG, "nl80211: Using driver-based "
@@ -2531,72 +2830,44 @@
capa->flags |= WPA_DRIVER_FLAGS_BSS_SELECTION;
}
- /* default to 5000 since early versions of mac80211 don't set it */
- capa->max_remain_on_chan = 5000;
+ 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;
- if (tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION])
- capa->max_remain_on_chan =
- nla_get_u32(tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]);
-
- if (auth_supported)
- capa->flags |= WPA_DRIVER_FLAGS_SME;
- else if (!connect_supported) {
- wpa_printf(MSG_INFO, "nl80211: Driver does not support "
- "authentication/association or connect commands");
- info->error = 1;
- }
-
- if (p2p_go_supported && p2p_client_supported)
- capa->flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE;
- if (p2p_concurrent) {
- wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
- "interface (driver advertised support)");
- capa->flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
- capa->flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
-
- if (p2p_multichan_concurrent) {
- wpa_printf(MSG_DEBUG, "nl80211: Enable multi-channel "
- "concurrent (driver advertised support)");
- capa->flags |=
- WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT;
- }
- }
-
- if (tb[NL80211_ATTR_TDLS_SUPPORT]) {
- wpa_printf(MSG_DEBUG, "nl80211: TDLS supported");
- capa->flags |= WPA_DRIVER_FLAGS_TDLS_SUPPORT;
-
- if (tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]) {
- wpa_printf(MSG_DEBUG, "nl80211: TDLS external setup");
- capa->flags |=
- WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP;
- }
- }
+ 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;
- if (tb[NL80211_ATTR_FEATURE_FLAGS]) {
- u32 flags = nla_get_u32(tb[NL80211_ATTR_FEATURE_FLAGS]);
+ wiphy_info_feature_flags(info, tb[NL80211_ATTR_FEATURE_FLAGS]);
+ wiphy_info_probe_resp_offload(capa,
+ tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
- 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 (tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]) {
- int protocols =
- nla_get_u32(tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
- 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);
+ 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;
+ }
}
return NL_SKIP;
@@ -2606,22 +2877,51 @@
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;
- nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
+ 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);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->first_bss.ifindex);
- if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info) == 0)
- return 0;
- msg = NULL;
+ 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->p2p_multichan_concurrent) {
+ wpa_printf(MSG_DEBUG, "nl80211: Enable multi-channel "
+ "concurrent (driver advertised support)");
+ drv->capa.flags |= WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT;
+ }
+ return 0;
nla_put_failure:
nlmsg_free(msg);
return -1;
@@ -3001,6 +3301,8 @@
drv->ctx = ctx;
bss = &drv->first_bss;
bss->drv = drv;
+ bss->ctx = ctx;
+
os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname));
drv->monitor_ifidx = -1;
drv->monitor_sock = -1;
@@ -3198,6 +3500,9 @@
/* WNM - BSS Transition Management Request */
if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x07", 2) < 0)
return -1;
+ /* WNM-Sleep Mode Response */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x11", 2) < 0)
+ return -1;
return 0;
}
@@ -3397,14 +3702,13 @@
/**
* wpa_driver_nl80211_deinit - Deinitialize nl80211 driver interface
- * @priv: Pointer to private nl80211 data from wpa_driver_nl80211_init()
+ * @bss: Pointer to private nl80211 data from wpa_driver_nl80211_init()
*
* Shut down driver interface and processing of driver events. Free
* private data buffer if one was allocated in wpa_driver_nl80211_init().
*/
-static void wpa_driver_nl80211_deinit(void *priv)
+static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
{
- struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
bss->in_deinit = 1;
@@ -3440,7 +3744,7 @@
struct hostapd_freq_params freq;
os_memset(&freq, 0, sizeof(freq));
freq.freq = drv->last_freq;
- i802_set_freq(priv, &freq);
+ wpa_driver_nl80211_set_freq(bss, &freq);
}
if (drv->eapol_sock >= 0) {
@@ -3476,6 +3780,8 @@
if (drv->in_interface_list)
dl_list_del(&drv->list);
+ os_free(drv->extended_capa);
+ os_free(drv->extended_capa_mask);
os_free(drv);
}
@@ -3580,18 +3886,18 @@
/**
* wpa_driver_nl80211_scan - Request the driver to initiate scan
- * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
+ * @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(void *priv,
+static int wpa_driver_nl80211_scan(struct i802_bss *bss,
struct wpa_driver_scan_params *params)
{
- struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
int ret = -1, timeout;
struct nl_msg *msg, *rates = 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);
@@ -3635,7 +3941,7 @@
bss, NL80211_IFTYPE_STATION))
goto nla_put_failure;
- if (wpa_driver_nl80211_scan(drv, params)) {
+ if (wpa_driver_nl80211_scan(bss, params)) {
wpa_driver_nl80211_set_mode(bss, drv->nlmode);
goto nla_put_failure;
}
@@ -3693,6 +3999,8 @@
struct nl_msg *match_set_rssi = NULL;
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);
@@ -4172,13 +4480,12 @@
}
-static int wpa_driver_nl80211_set_key(const char *ifname, void *priv,
+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,
const u8 *seq, size_t seq_len,
const u8 *key, size_t key_len)
{
- struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
int ifindex = if_nametoindex(ifname);
struct nl_msg *msg;
@@ -4227,6 +4534,14 @@
NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
WLAN_CIPHER_SUITE_AES_CMAC);
break;
+ case WPA_ALG_SMS4:
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_SMS4);
+ break;
+ case WPA_ALG_KRK:
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_KRK);
+ break;
default:
wpa_printf(MSG_ERROR, "%s: Unsupported encryption "
"algorithm %d", __func__, alg);
@@ -4464,7 +4779,8 @@
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason_code);
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+ if (addr)
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
if (local_state_change)
NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE);
@@ -4485,23 +4801,23 @@
static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
- const u8 *addr, int reason_code)
+ int reason_code)
{
- wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)",
- __func__, MAC2STR(addr), reason_code);
+ wpa_printf(MSG_DEBUG, "%s(reason_code=%d)", __func__, reason_code);
drv->associated = 0;
- return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DISCONNECT,
+ drv->ignore_next_local_disconnect = 0;
+ /* Disconnect command doesn't need BSSID - it uses cached value */
+ return wpa_driver_nl80211_mlme(drv, NULL, NL80211_CMD_DISCONNECT,
reason_code, 0);
}
-static int wpa_driver_nl80211_deauthenticate(void *priv, const u8 *addr,
- int reason_code)
+static int wpa_driver_nl80211_deauthenticate(struct i802_bss *bss,
+ const u8 *addr, int reason_code)
{
- struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
- return wpa_driver_nl80211_disconnect(drv, addr, reason_code);
+ return wpa_driver_nl80211_disconnect(drv, reason_code);
wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)",
__func__, MAC2STR(addr), reason_code);
drv->associated = 0;
@@ -4512,20 +4828,6 @@
}
-static int wpa_driver_nl80211_disassociate(void *priv, const u8 *addr,
- int reason_code)
-{
- struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
- if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
- return wpa_driver_nl80211_disconnect(drv, addr, reason_code);
- wpa_printf(MSG_DEBUG, "%s", __func__);
- drv->associated = 0;
- return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DISASSOCIATE,
- reason_code, 0);
-}
-
-
static void nl80211_copy_auth_params(struct wpa_driver_nl80211_data *drv,
struct wpa_driver_auth_params *params)
{
@@ -4573,9 +4875,8 @@
static int wpa_driver_nl80211_authenticate(
- void *priv, struct wpa_driver_auth_params *params)
+ struct i802_bss *bss, struct wpa_driver_auth_params *params)
{
- struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
int ret = -1, i;
struct nl_msg *msg;
@@ -4593,7 +4894,7 @@
nlmode = params->p2p ?
NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
if (drv->nlmode != nlmode &&
- wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
+ wpa_driver_nl80211_set_mode(bss, nlmode) < 0)
return -1;
retry:
@@ -4609,7 +4910,7 @@
for (i = 0; i < 4; i++) {
if (!params->wep_key[i])
continue;
- wpa_driver_nl80211_set_key(bss->ifname, priv, WPA_ALG_WEP,
+ wpa_driver_nl80211_set_key(bss->ifname, bss, WPA_ALG_WEP,
NULL, i,
i == params->wep_tx_keyidx, NULL, 0,
params->wep_key[i],
@@ -4642,6 +4943,12 @@
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->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 (params->auth_alg & WPA_AUTH_ALG_OPEN)
type = NL80211_AUTHTYPE_OPEN_SYSTEM;
else if (params->auth_alg & WPA_AUTH_ALG_SHARED)
@@ -4650,6 +4957,8 @@
type = NL80211_AUTHTYPE_NETWORK_EAP;
else if (params->auth_alg & WPA_AUTH_ALG_FT)
type = NL80211_AUTHTYPE_FT;
+ else if (params->auth_alg & WPA_AUTH_ALG_SAE)
+ type = NL80211_AUTHTYPE_SAE;
else
goto nla_put_failure;
wpa_printf(MSG_DEBUG, " * Auth Type %d", type);
@@ -4778,17 +5087,99 @@
struct phy_info_arg {
u16 *num_modes;
struct hostapd_hw_modes *modes;
+ int last_mode, last_chan_idx;
};
-static int phy_info_handler(struct nl_msg *msg, void *arg)
+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)
{
- struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
- struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
- struct phy_info_arg *phy_info = arg;
+ if (capa)
+ mode->ht_capab = nla_get_u16(capa);
- struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
+ if (ampdu_factor)
+ mode->a_mpdu_params |= nla_get_u8(ampdu_factor) & 0x03;
- struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
+ 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[])
+{
+ enum hostapd_hw_mode m;
+
+ chan->freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
+ chan->flag = 0;
+
+ if (chan->freq < 4000)
+ m = HOSTAPD_MODE_IEEE80211B;
+ else if (chan->freq > 50000)
+ m = HOSTAPD_MODE_IEEE80211AD;
+ else
+ m = HOSTAPD_MODE_IEEE80211A;
+
+ switch (m) {
+ case HOSTAPD_MODE_IEEE80211AD:
+ chan->chan = (chan->freq - 56160) / 2160;
+ break;
+ case HOSTAPD_MODE_IEEE80211A:
+ chan->chan = chan->freq / 5 - 1000;
+ break;
+ case HOSTAPD_MODE_IEEE80211B:
+ case HOSTAPD_MODE_IEEE80211G:
+ if (chan->freq == 2484)
+ chan->chan = 14;
+ else
+ chan->chan = (chan->freq - 2407) / 5;
+ break;
+ default:
+ break;
+ }
+
+ if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
+ chan->flag |= HOSTAPD_CHAN_DISABLED;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN])
+ chan->flag |= HOSTAPD_CHAN_PASSIVE_SCAN;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS])
+ chan->flag |= HOSTAPD_CHAN_NO_IBSS;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR])
+ chan->flag |= HOSTAPD_CHAN_RADAR;
+
+ if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] &&
+ !tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
+ chan->max_tx_power = nla_get_u32(
+ tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]) / 100;
+}
+
+
+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 },
@@ -4797,27 +5188,99 @@
[NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
};
-
- struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1];
- 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 *nl_band;
+ int new_channels = 0;
+ struct hostapd_channel_data *channel;
+ struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
struct nlattr *nl_freq;
- struct nlattr *nl_rate;
- int rem_band, rem_freq, rem_rate;
- struct hostapd_hw_modes *mode;
- int idx, mode_is_set;
+ int rem_freq, idx;
- nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
- genlmsg_attrlen(gnlh, 0), NULL);
+ if (tb == NULL)
+ return NL_OK;
- if (!tb_msg[NL80211_ATTR_WIPHY_BANDS])
+ 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;
- nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) {
+ 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));
@@ -4825,155 +5288,87 @@
return NL_SKIP;
phy_info->modes = mode;
- mode_is_set = 0;
-
mode = &phy_info->modes[*(phy_info->num_modes)];
- memset(mode, 0, sizeof(*mode));
+ os_memset(mode, 0, sizeof(*mode));
+ mode->mode = NUM_HOSTAPD_MODES;
mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN;
*(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);
+ nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
+ nla_len(nl_band), NULL);
- if (tb_band[NL80211_BAND_ATTR_HT_CAPA]) {
- mode->ht_capab = nla_get_u16(
- tb_band[NL80211_BAND_ATTR_HT_CAPA]);
- }
+ 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;
- if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]) {
- mode->a_mpdu_params |= nla_get_u8(
- tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]) &
- 0x03;
- }
+ return NL_OK;
+}
- if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]) {
- mode->a_mpdu_params |= nla_get_u8(
- tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]) <<
- 2;
- }
- if (tb_band[NL80211_BAND_ATTR_HT_MCS_SET] &&
- nla_len(tb_band[NL80211_BAND_ATTR_HT_MCS_SET])) {
- u8 *mcs;
- mcs = nla_data(tb_band[NL80211_BAND_ATTR_HT_MCS_SET]);
- os_memcpy(mode->mcs_set, mcs, 16);
- }
+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;
- if (tb_band[NL80211_BAND_ATTR_VHT_CAPA]) {
- mode->vht_capab = nla_get_u32(
- tb_band[NL80211_BAND_ATTR_VHT_CAPA]);
- }
+ nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
- if (tb_band[NL80211_BAND_ATTR_VHT_MCS_SET] &&
- nla_len(tb_band[NL80211_BAND_ATTR_VHT_MCS_SET])) {
- u8 *mcs;
- mcs = nla_data(tb_band[NL80211_BAND_ATTR_VHT_MCS_SET]);
- os_memcpy(mode->vht_mcs_set, mcs, 8);
- }
+ if (!tb_msg[NL80211_ATTR_WIPHY_BANDS])
+ return NL_SKIP;
- nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], 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;
- mode->num_channels++;
- }
-
- mode->channels = os_calloc(mode->num_channels,
- sizeof(struct hostapd_channel_data));
- if (!mode->channels)
- return NL_SKIP;
-
- idx = 0;
-
- nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], 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;
-
- mode->channels[idx].freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
- mode->channels[idx].flag = 0;
-
- if (!mode_is_set) {
- /* crude heuristic */
- if (mode->channels[idx].freq < 4000)
- mode->mode = HOSTAPD_MODE_IEEE80211B;
- else
- mode->mode = HOSTAPD_MODE_IEEE80211A;
- mode_is_set = 1;
- }
-
- /* crude heuristic */
- if (mode->channels[idx].freq < 4000)
- if (mode->channels[idx].freq == 2484)
- mode->channels[idx].chan = 14;
- else
- mode->channels[idx].chan = (mode->channels[idx].freq - 2407) / 5;
- else
- mode->channels[idx].chan = mode->channels[idx].freq/5 - 1000;
-
- if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
- mode->channels[idx].flag |=
- HOSTAPD_CHAN_DISABLED;
- if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN])
- mode->channels[idx].flag |=
- HOSTAPD_CHAN_PASSIVE_SCAN;
- if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS])
- mode->channels[idx].flag |=
- HOSTAPD_CHAN_NO_IBSS;
- if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR])
- mode->channels[idx].flag |=
- HOSTAPD_CHAN_RADAR;
-
- if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] &&
- !tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
- mode->channels[idx].max_tx_power =
- nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]) / 100;
-
- idx++;
- }
-
- nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], 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_band[NL80211_BAND_ATTR_RATES], 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]);
-
- /* crude heuristic */
- if (mode->mode == HOSTAPD_MODE_IEEE80211B &&
- mode->rates[idx] > 200)
- mode->mode = HOSTAPD_MODE_IEEE80211G;
-
- idx++;
- }
+ 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_add_11b(struct hostapd_hw_modes *modes, u16 *num_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. */
@@ -5191,12 +5586,14 @@
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;
@@ -5206,13 +5603,19 @@
if (!msg)
return NULL;
- nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
+ 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);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) {
nl80211_set_ht40_flags(drv, &result);
- return wpa_driver_nl80211_add_11b(result.modes, num_modes);
+ return wpa_driver_nl80211_postprocess_modes(result.modes,
+ num_modes);
}
msg = NULL;
nla_put_failure:
@@ -5267,7 +5670,7 @@
if (noack)
txflags |= IEEE80211_RADIOTAP_F_TX_NOACK;
- *(le16 *) &rtap_hdr[12] = host_to_le16(txflags);
+ WPA_PUT_LE16(&rtap_hdr[12], txflags);
res = sendmsg(drv->monitor_sock, &msg, 0);
if (res < 0) {
@@ -5299,12 +5702,11 @@
}
-static int wpa_driver_nl80211_send_mlme_freq(struct i802_bss *bss,
- const u8 *data,
- size_t data_len, int noack,
- unsigned int freq, int no_cck,
- int offchanok,
- unsigned int wait_time)
+static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
+ size_t data_len, int noack,
+ unsigned int freq, int no_cck,
+ int offchanok,
+ unsigned int wait_time)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
struct ieee80211_mgmt *mgmt;
@@ -5360,15 +5762,6 @@
}
-static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
- size_t data_len, int noack)
-{
- struct i802_bss *bss = priv;
- return wpa_driver_nl80211_send_mlme_freq(bss, data, data_len, noack,
- 0, 0, 0, 0);
-}
-
-
static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
int slot, int ht_opmode, int ap_isolate,
int *basic_rates)
@@ -5440,32 +5833,49 @@
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: 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 (params->proberesp && params->proberesp_len)
+ 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);
+ }
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);
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);
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);
break;
}
+ wpa_printf(MSG_DEBUG, "nl80211: privacy=%d", params->privacy);
if (params->privacy)
NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY);
+ 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 */
@@ -5476,6 +5886,7 @@
NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE,
NL80211_AUTHTYPE_OPEN_SYSTEM);
+ wpa_printf(MSG_DEBUG, "nl80211: wpa_version=0x%x", params->wpa_version);
ver = 0;
if (params->wpa_version & WPA_PROTO_WPA)
ver |= NL80211_WPA_VERSION_1;
@@ -5484,6 +5895,8 @@
if (ver)
NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
+ wpa_printf(MSG_DEBUG, "nl80211: key_mgmt_suites=0x%x",
+ params->key_mgmt_suites);
num_suites = 0;
if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X)
suites[num_suites++] = WLAN_AKM_SUITE_8021X;
@@ -5498,6 +5911,8 @@
params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40))
NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT);
+ wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x",
+ params->pairwise_ciphers);
num_suites = 0;
if (params->pairwise_ciphers & WPA_CIPHER_CCMP)
suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP;
@@ -5514,6 +5929,8 @@
num_suites * sizeof(u32), suites);
}
+ wpa_printf(MSG_DEBUG, "nl80211: group_cipher=0x%x",
+ params->group_cipher);
switch (params->group_cipher) {
case WPA_CIPHER_CCMP:
NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
@@ -5538,21 +5955,29 @@
}
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 (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 (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 (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);
}
@@ -5575,16 +6000,16 @@
static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
- int freq, int ht_enabled,
- int sec_channel_offset)
+ struct hostapd_freq_params *freq)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
int ret;
- wpa_printf(MSG_DEBUG, "nl80211: Set freq %d (ht_enabled=%d "
- "sec_channel_offset=%d)",
- freq, ht_enabled, sec_channel_offset);
+ wpa_printf(MSG_DEBUG, "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)
return -1;
@@ -5592,9 +6017,38 @@
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_FREQ, freq);
- if (ht_enabled) {
- switch (sec_channel_offset) {
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq);
+ if (freq->vht_enabled) {
+ switch (freq->bandwidth) {
+ case 20:
+ NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
+ NL80211_CHAN_WIDTH_20);
+ break;
+ case 40:
+ NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
+ NL80211_CHAN_WIDTH_40);
+ break;
+ case 80:
+ if (freq->center_freq2)
+ NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
+ NL80211_CHAN_WIDTH_80P80);
+ else
+ NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
+ NL80211_CHAN_WIDTH_80);
+ break;
+ case 160:
+ NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
+ NL80211_CHAN_WIDTH_160);
+ break;
+ default:
+ return -1;
+ }
+ 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);
+ } else if (freq->ht_enabled) {
+ switch (freq->sec_channel_offset) {
case -1:
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
NL80211_CHAN_HT40MINUS);
@@ -5613,11 +6067,11 @@
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
msg = NULL;
if (ret == 0) {
- bss->freq = freq;
+ bss->freq = freq->freq;
return 0;
}
wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): "
- "%d (%s)", freq, ret, strerror(-ret));
+ "%d (%s)", freq->freq, ret, strerror(-ret));
nla_put_failure:
nlmsg_free(msg);
return -1;
@@ -5660,6 +6114,8 @@
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);
@@ -5667,20 +6123,49 @@
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) {
+ wpa_printf(MSG_DEBUG, " * aid=%u", params->aid);
NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
+ wpa_printf(MSG_DEBUG, " * listen_interval=%u",
+ params->listen_interval);
NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
params->listen_interval);
}
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);
+ }
+
+ 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);
+ }
+
os_memset(&upd, 0, sizeof(upd));
upd.mask = sta_flags_nl80211(params->flags);
upd.set = upd.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 (params->flags & WPA_STA_WMM) {
@@ -5688,10 +6173,11 @@
if (!wme)
goto nla_put_failure;
+ wpa_printf(MSG_DEBUG, " * qosinfo=0x%x", params->qosinfo);
NLA_PUT_U8(wme, NL80211_STA_WME_UAPSD_QUEUES,
params->qosinfo & WMM_QOSINFO_STA_AC_MASK);
NLA_PUT_U8(wme, NL80211_STA_WME_MAX_SP,
- (params->qosinfo > WMM_QOSINFO_STA_SP_SHIFT) &
+ (params->qosinfo >> WMM_QOSINFO_STA_SP_SHIFT) &
WMM_QOSINFO_STA_SP_MASK);
if (nla_put_nested(msg, NL80211_ATTR_STA_WME, wme) < 0)
goto nla_put_failure;
@@ -5712,9 +6198,8 @@
}
-static int wpa_driver_nl80211_sta_remove(void *priv, const u8 *addr)
+static int wpa_driver_nl80211_sta_remove(struct i802_bss *bss, const u8 *addr)
{
- struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
int ret;
@@ -6513,7 +6998,10 @@
static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
struct wpa_driver_associate_params *params)
{
- enum nl80211_iftype nlmode;
+ enum nl80211_iftype nlmode, old_mode;
+ struct hostapd_freq_params freq = {
+ .freq = params->freq,
+ };
if (params->p2p) {
wpa_printf(MSG_DEBUG, "nl80211: Setup AP operations for P2P "
@@ -6522,8 +7010,15 @@
} else
nlmode = NL80211_IFTYPE_AP;
- if (wpa_driver_nl80211_set_mode(&drv->first_bss, nlmode) ||
- wpa_driver_nl80211_set_freq(&drv->first_bss, params->freq, 0, 0)) {
+ old_mode = drv->nlmode;
+ if (wpa_driver_nl80211_set_mode(&drv->first_bss, nlmode)) {
+ nl80211_remove_monitor_interface(drv);
+ return -1;
+ }
+
+ if (wpa_driver_nl80211_set_freq(&drv->first_bss, &freq)) {
+ if (old_mode != nlmode)
+ wpa_driver_nl80211_set_mode(&drv->first_bss, old_mode);
nl80211_remove_monitor_interface(drv);
return -1;
}
@@ -6648,56 +7143,7 @@
}
-static unsigned int nl80211_get_assoc_bssid(struct wpa_driver_nl80211_data *drv,
- u8 *bssid)
-{
- struct nl_msg *msg;
- int ret;
- struct nl80211_bss_info_arg arg;
-
- 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) {
- if (is_zero_ether_addr(arg.assoc_bssid))
- return -ENOTCONN;
- os_memcpy(bssid, arg.assoc_bssid, ETH_ALEN);
- return 0;
- }
- 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 int nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
- const u8 *bssid)
-{
- u8 addr[ETH_ALEN];
-
- if (bssid == NULL) {
- int res = nl80211_get_assoc_bssid(drv, addr);
- if (res)
- return res;
- bssid = addr;
- }
-
- return wpa_driver_nl80211_disconnect(drv, bssid,
- WLAN_REASON_PREV_AUTH_NOT_VALID);
-}
-
-
-static int wpa_driver_nl80211_connect(
+static int wpa_driver_nl80211_try_connect(
struct wpa_driver_nl80211_data *drv,
struct wpa_driver_associate_params *params)
{
@@ -6788,6 +7234,9 @@
int cipher;
switch (params->pairwise_suite) {
+ case CIPHER_SMS4:
+ cipher = WLAN_CIPHER_SUITE_SMS4;
+ break;
case CIPHER_WEP40:
cipher = WLAN_CIPHER_SUITE_WEP40;
break;
@@ -6812,6 +7261,9 @@
int cipher;
switch (params->group_suite) {
+ case CIPHER_SMS4:
+ cipher = WLAN_CIPHER_SUITE_SMS4;
+ break;
case CIPHER_WEP40:
cipher = WLAN_CIPHER_SUITE_WEP40;
break;
@@ -6833,13 +7285,25 @@
}
if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
- params->key_mgmt_suite == KEY_MGMT_PSK) {
+ params->key_mgmt_suite == KEY_MGMT_PSK ||
+ params->key_mgmt_suite == KEY_MGMT_FT_802_1X ||
+ params->key_mgmt_suite == KEY_MGMT_FT_PSK ||
+ params->key_mgmt_suite == KEY_MGMT_CCKM) {
int mgmt = WLAN_AKM_SUITE_PSK;
switch (params->key_mgmt_suite) {
+ case KEY_MGMT_CCKM:
+ mgmt = WLAN_AKM_SUITE_CCKM;
+ break;
case KEY_MGMT_802_1X:
mgmt = WLAN_AKM_SUITE_8021X;
break;
+ case KEY_MGMT_FT_802_1X:
+ mgmt = WLAN_AKM_SUITE_FT_8021X;
+ break;
+ case KEY_MGMT_FT_PSK:
+ mgmt = WLAN_AKM_SUITE_FT_PSK;
+ break;
case KEY_MGMT_PSK:
default:
mgmt = WLAN_AKM_SUITE_PSK;
@@ -6848,6 +7312,11 @@
NLA_PUT_U32(msg, NL80211_ATTR_AKM_SUITES, mgmt);
}
+#ifdef CONFIG_IEEE80211W
+ if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED)
+ NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED);
+#endif /* CONFIG_IEEE80211W */
+
if (params->disable_ht)
NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_HT);
@@ -6858,6 +7327,20 @@
params->htcaps_mask);
}
+#ifdef CONFIG_VHT_OVERRIDES
+ if (params->disable_vht) {
+ wpa_printf(MSG_DEBUG, " * VHT disabled");
+ NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_VHT);
+ }
+
+ if (params->vhtcaps && params->vhtcaps_mask) {
+ int sz = sizeof(struct ieee80211_vht_capabilities);
+ NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY, sz, params->vhtcaps);
+ NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz,
+ params->vhtcaps_mask);
+ }
+#endif /* CONFIG_VHT_OVERRIDES */
+
ret = nl80211_set_conn_keys(params, msg);
if (ret)
goto nla_put_failure;
@@ -6867,14 +7350,6 @@
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
"(%s)", ret, strerror(-ret));
- /*
- * cfg80211 does not currently accept new connection if we are
- * already connected. As a workaround, force disconnection and
- * try again once the driver indicates it completed
- * disconnection.
- */
- if (ret == -EALREADY)
- nl80211_disconnect(drv, params->bssid);
goto nla_put_failure;
}
ret = 0;
@@ -6887,6 +7362,31 @@
}
+static int wpa_driver_nl80211_connect(
+ struct wpa_driver_nl80211_data *drv,
+ struct wpa_driver_associate_params *params)
+{
+ int ret = wpa_driver_nl80211_try_connect(drv, params);
+ if (ret == -EALREADY) {
+ /*
+ * cfg80211 does not currently accept new connections if
+ * we are already connected. As a workaround, force
+ * disconnection and try again.
+ */
+ wpa_printf(MSG_DEBUG, "nl80211: Explicitly "
+ "disconnecting before reassociation "
+ "attempt");
+ if (wpa_driver_nl80211_disconnect(
+ drv, WLAN_REASON_PREV_AUTH_NOT_VALID))
+ return -1;
+ /* Ignore the next local disconnect message. */
+ drv->ignore_next_local_disconnect = 1;
+ ret = wpa_driver_nl80211_try_connect(drv, params);
+ }
+ return ret;
+}
+
+
static int wpa_driver_nl80211_associate(
void *priv, struct wpa_driver_associate_params *params)
{
@@ -7027,6 +7527,20 @@
params->htcaps_mask);
}
+#ifdef CONFIG_VHT_OVERRIDES
+ if (params->disable_vht) {
+ wpa_printf(MSG_DEBUG, " * VHT disabled");
+ NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_VHT);
+ }
+
+ if (params->vhtcaps && params->vhtcaps_mask) {
+ int sz = sizeof(struct ieee80211_vht_capabilities);
+ NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY, sz, params->vhtcaps);
+ NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz,
+ params->vhtcaps_mask);
+ }
+#endif /* CONFIG_VHT_OVERRIDES */
+
if (params->p2p)
wpa_printf(MSG_DEBUG, " * P2P group");
@@ -7181,6 +7695,11 @@
if (!drv->has_capability)
return -1;
os_memcpy(capa, &drv->capa, sizeof(*capa));
+ if (drv->extended_capa && drv->extended_capa_mask) {
+ capa->extended_capa = drv->extended_capa;
+ capa->extended_capa_mask = drv->extended_capa_mask;
+ capa->extended_capa_len = drv->extended_capa_len;
+ }
return 0;
}
@@ -7232,8 +7751,7 @@
static int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
{
struct i802_bss *bss = priv;
- return wpa_driver_nl80211_set_freq(bss, freq->freq, freq->ht_enabled,
- freq->sec_channel_offset);
+ return wpa_driver_nl80211_set_freq(bss, freq);
}
@@ -7449,10 +7967,10 @@
return NL_SKIP;
}
-static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data,
+static int i802_read_sta_data(struct i802_bss *bss,
+ struct hostap_sta_driver_data *data,
const u8 *addr)
{
- struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
@@ -7534,10 +8052,9 @@
}
-static int i802_set_sta_vlan(void *priv, const u8 *addr,
+static int i802_set_sta_vlan(struct i802_bss *bss, const u8 *addr,
const char *ifname, int vlan_id)
{
- struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
int ret = -ENOBUFS;
@@ -7609,7 +8126,8 @@
mgmt.u.deauth.reason_code = host_to_le16(reason);
return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
IEEE80211_HDRLEN +
- sizeof(mgmt.u.deauth), 0);
+ sizeof(mgmt.u.deauth), 0, 0, 0, 0,
+ 0);
}
@@ -7632,7 +8150,8 @@
mgmt.u.disassoc.reason_code = host_to_le16(reason);
return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
IEEE80211_HDRLEN +
- sizeof(mgmt.u.disassoc), 0);
+ sizeof(mgmt.u.disassoc), 0, 0, 0, 0,
+ 0);
}
#endif /* HOSTAPD || CONFIG_AP */
@@ -7716,7 +8235,7 @@
if (!if_nametoindex(name)) {
if (nl80211_create_iface(drv, name,
NL80211_IFTYPE_AP_VLAN,
- NULL, 1) < 0)
+ bss->addr, 1) < 0)
return -1;
if (bridge_ifname &&
linux_br_add_if(drv->global->ioctl_sock,
@@ -7910,7 +8429,8 @@
static void i802_deinit(void *priv)
{
- wpa_driver_nl80211_deinit(priv);
+ struct i802_bss *bss = priv;
+ wpa_driver_nl80211_deinit(bss);
}
#endif /* HOSTAPD */
@@ -8069,6 +8589,7 @@
new_bss->drv = drv;
new_bss->next = drv->first_bss.next;
new_bss->freq = drv->first_bss.freq;
+ new_bss->ctx = bss_ctx;
drv->first_bss.next = new_bss;
if (drv_priv)
*drv_priv = new_bss;
@@ -8087,11 +8608,10 @@
}
-static int wpa_driver_nl80211_if_remove(void *priv,
+static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
enum wpa_driver_if_type type,
const char *ifname)
{
- struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
int ifindex = if_nametoindex(ifname);
@@ -8212,14 +8732,14 @@
}
-static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq,
+static int wpa_driver_nl80211_send_action(struct i802_bss *bss,
+ unsigned int freq,
unsigned int wait_time,
const u8 *dst, const u8 *src,
const u8 *bssid,
const u8 *data, size_t data_len,
int no_cck)
{
- struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
int ret = -1;
u8 *buf;
@@ -8241,10 +8761,9 @@
os_memcpy(hdr->addr3, bssid, ETH_ALEN);
if (is_ap_interface(drv->nlmode))
- ret = wpa_driver_nl80211_send_mlme_freq(priv, buf,
- 24 + data_len,
- 0, freq, no_cck, 1,
- wait_time);
+ ret = wpa_driver_nl80211_send_mlme(bss, buf, 24 + data_len,
+ 0, freq, no_cck, 1,
+ wait_time);
else
ret = nl80211_send_frame_cmd(bss, freq, wait_time, buf,
24 + data_len,
@@ -8267,6 +8786,8 @@
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);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
@@ -8360,9 +8881,8 @@
}
-static int wpa_driver_nl80211_probe_req_report(void *priv, int report)
+static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss, int report)
{
- struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
if (!report) {
@@ -8877,7 +9397,8 @@
os_memcpy(nulldata.hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
- if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0) < 0)
+ if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0, 0, 0,
+ 0, 0) < 0)
wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to "
"send poll frame");
}
@@ -9175,35 +9696,173 @@
#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,
+ const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ struct i802_bss *bss = priv;
+ return wpa_driver_nl80211_set_key(ifname, bss, alg, addr, key_idx,
+ set_tx, seq, seq_len, key, key_len);
+}
+
+
+static int driver_nl80211_scan2(void *priv,
+ struct wpa_driver_scan_params *params)
+{
+ struct i802_bss *bss = priv;
+ return wpa_driver_nl80211_scan(bss, params);
+}
+
+
+static int driver_nl80211_deauthenticate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct i802_bss *bss = priv;
+ return wpa_driver_nl80211_deauthenticate(bss, addr, reason_code);
+}
+
+
+static int driver_nl80211_authenticate(void *priv,
+ struct wpa_driver_auth_params *params)
+{
+ struct i802_bss *bss = priv;
+ return wpa_driver_nl80211_authenticate(bss, params);
+}
+
+
+static void driver_nl80211_deinit(void *priv)
+{
+ struct i802_bss *bss = priv;
+ wpa_driver_nl80211_deinit(bss);
+}
+
+
+static int driver_nl80211_if_remove(void *priv, enum wpa_driver_if_type type,
+ const char *ifname)
+{
+ struct i802_bss *bss = priv;
+ return wpa_driver_nl80211_if_remove(bss, type, ifname);
+}
+
+
+static int driver_nl80211_send_mlme(void *priv, const u8 *data,
+ size_t data_len, int noack)
+{
+ struct i802_bss *bss = priv;
+ return wpa_driver_nl80211_send_mlme(bss, data, data_len, noack,
+ 0, 0, 0, 0);
+}
+
+
+static int driver_nl80211_sta_remove(void *priv, const u8 *addr)
+{
+ struct i802_bss *bss = priv;
+ return wpa_driver_nl80211_sta_remove(bss, addr);
+}
+
+
+#if defined(HOSTAPD) || defined(CONFIG_AP)
+static int driver_nl80211_set_sta_vlan(void *priv, const u8 *addr,
+ const char *ifname, int vlan_id)
+{
+ struct i802_bss *bss = priv;
+ return i802_set_sta_vlan(bss, addr, ifname, vlan_id);
+}
+#endif /* HOSTAPD || CONFIG_AP */
+
+
+static int driver_nl80211_read_sta_data(void *priv,
+ struct hostap_sta_driver_data *data,
+ const u8 *addr)
+{
+ struct i802_bss *bss = priv;
+ return i802_read_sta_data(bss, data, addr);
+}
+
+
+static int driver_nl80211_send_action(void *priv, unsigned int freq,
+ unsigned int wait_time,
+ const u8 *dst, const u8 *src,
+ const u8 *bssid,
+ const u8 *data, size_t data_len,
+ int no_cck)
+{
+ struct i802_bss *bss = priv;
+ return wpa_driver_nl80211_send_action(bss, freq, wait_time, dst, src,
+ bssid, data, data_len, no_cck);
+}
+
+
+static int driver_nl80211_probe_req_report(void *priv, int report)
+{
+ struct i802_bss *bss = priv;
+ return wpa_driver_nl80211_probe_req_report(bss, report);
+}
+
+
+static int wpa_driver_nl80211_update_ft_ies(void *priv, const u8 *md,
+ const u8 *ies, size_t ies_len)
+{
+ int ret;
+ struct nl_msg *msg;
+ struct i802_bss *bss = priv;
+ 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);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: update_ft_ies failed "
+ "err=%d (%s)", ret, strerror(-ret));
+ }
+
+ return ret;
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return -ENOBUFS;
+}
+
+
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.name = "nl80211",
.desc = "Linux nl80211/cfg80211",
.get_bssid = wpa_driver_nl80211_get_bssid,
.get_ssid = wpa_driver_nl80211_get_ssid,
- .set_key = wpa_driver_nl80211_set_key,
- .scan2 = wpa_driver_nl80211_scan,
+ .set_key = driver_nl80211_set_key,
+ .scan2 = driver_nl80211_scan2,
.sched_scan = wpa_driver_nl80211_sched_scan,
.stop_sched_scan = wpa_driver_nl80211_stop_sched_scan,
.get_scan_results2 = wpa_driver_nl80211_get_scan_results,
- .deauthenticate = wpa_driver_nl80211_deauthenticate,
- .disassociate = wpa_driver_nl80211_disassociate,
- .authenticate = wpa_driver_nl80211_authenticate,
+ .deauthenticate = driver_nl80211_deauthenticate,
+ .authenticate = driver_nl80211_authenticate,
.associate = wpa_driver_nl80211_associate,
.global_init = nl80211_global_init,
.global_deinit = nl80211_global_deinit,
.init2 = wpa_driver_nl80211_init,
- .deinit = wpa_driver_nl80211_deinit,
+ .deinit = driver_nl80211_deinit,
.get_capa = wpa_driver_nl80211_get_capa,
.set_operstate = wpa_driver_nl80211_set_operstate,
.set_supp_port = wpa_driver_nl80211_set_supp_port,
.set_country = wpa_driver_nl80211_set_country,
.set_ap = wpa_driver_nl80211_set_ap,
.if_add = wpa_driver_nl80211_if_add,
- .if_remove = wpa_driver_nl80211_if_remove,
- .send_mlme = wpa_driver_nl80211_send_mlme,
+ .if_remove = driver_nl80211_if_remove,
+ .send_mlme = driver_nl80211_send_mlme,
.get_hw_feature_data = wpa_driver_nl80211_get_hw_feature_data,
.sta_add = wpa_driver_nl80211_sta_add,
- .sta_remove = wpa_driver_nl80211_sta_remove,
+ .sta_remove = driver_nl80211_sta_remove,
.hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,
.sta_set_flags = wpa_driver_nl80211_sta_set_flags,
#ifdef HOSTAPD
@@ -9219,18 +9878,18 @@
.set_rts = i802_set_rts,
.set_frag = i802_set_frag,
.set_tx_queue_params = i802_set_tx_queue_params,
- .set_sta_vlan = i802_set_sta_vlan,
+ .set_sta_vlan = driver_nl80211_set_sta_vlan,
.sta_deauth = i802_sta_deauth,
.sta_disassoc = i802_sta_disassoc,
#endif /* HOSTAPD || CONFIG_AP */
- .read_sta_data = i802_read_sta_data,
+ .read_sta_data = driver_nl80211_read_sta_data,
.set_freq = i802_set_freq,
- .send_action = wpa_driver_nl80211_send_action,
+ .send_action = driver_nl80211_send_action,
.send_action_cancel_wait = wpa_driver_nl80211_send_action_cancel_wait,
.remain_on_channel = wpa_driver_nl80211_remain_on_channel,
.cancel_remain_on_channel =
wpa_driver_nl80211_cancel_remain_on_channel,
- .probe_req_report = wpa_driver_nl80211_probe_req_report,
+ .probe_req_report = driver_nl80211_probe_req_report,
.deinit_ap = wpa_driver_nl80211_deinit_ap,
.deinit_p2p_cli = wpa_driver_nl80211_deinit_p2p_cli,
.resume = wpa_driver_nl80211_resume,
@@ -9251,6 +9910,7 @@
.send_tdls_mgmt = nl80211_send_tdls_mgmt,
.tdls_oper = nl80211_tdls_oper,
#endif /* CONFIG_TDLS */
+ .update_ft_ies = wpa_driver_nl80211_update_ft_ies,
#ifdef ANDROID_P2P
.set_noa = wpa_driver_set_p2p_noa,
.get_noa = wpa_driver_get_p2p_noa,
diff --git a/src/drivers/driver_openbsd.c b/src/drivers/driver_openbsd.c
new file mode 100644
index 0000000..e94eda0
--- /dev/null
+++ b/src/drivers/driver_openbsd.c
@@ -0,0 +1,136 @@
+/*
+ * Driver interaction with OpenBSD net80211 layer
+ * Copyright (c) 2013, Mark Kettenis
+ *
+ * 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 <net80211/ieee80211.h>
+#include <net80211/ieee80211_crypto.h>
+#include <net80211/ieee80211_ioctl.h>
+
+#include "common.h"
+#include "driver.h"
+
+struct openbsd_driver_data {
+ char ifname[IFNAMSIZ + 1];
+ void *ctx;
+
+ int sock; /* open socket for 802.11 ioctls */
+};
+
+
+static int
+wpa_driver_openbsd_get_ssid(void *priv, u8 *ssid)
+{
+ struct openbsd_driver_data *drv = priv;
+ struct ieee80211_nwid nwid;
+ struct ifreq ifr;
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
+ ifr.ifr_data = (void *)&nwid;
+ if (ioctl(drv->sock, SIOCG80211NWID, &ifr) < 0 ||
+ nwid.i_len > IEEE80211_NWID_LEN)
+ return -1;
+
+ os_memcpy(ssid, nwid.i_nwid, nwid.i_len);
+ return nwid.i_len;
+}
+
+static int
+wpa_driver_openbsd_get_bssid(void *priv, u8 *bssid)
+{
+ struct openbsd_driver_data *drv = priv;
+ struct ieee80211_bssid id;
+
+ os_strlcpy(id.i_name, drv->ifname, sizeof(id.i_name));
+ if (ioctl(drv->sock, SIOCG80211BSSID, &id) < 0)
+ return -1;
+
+ os_memcpy(bssid, id.i_bssid, IEEE80211_ADDR_LEN);
+ return 0;
+}
+
+
+static int
+wpa_driver_openbsd_get_capa(void *priv, struct wpa_driver_capa *capa)
+{
+ os_memset(capa, 0, sizeof(*capa));
+ capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
+ return 0;
+}
+
+
+static int
+wpa_driver_openbsd_set_key(const char *ifname, void *priv, enum wpa_alg alg,
+ const unsigned char *addr, int key_idx, int set_tx, const u8 *seq,
+ size_t seq_len, const u8 *key, size_t key_len)
+{
+ struct openbsd_driver_data *drv = priv;
+ struct ieee80211_keyavail keyavail;
+
+ if (alg != WPA_ALG_PMK || key_len > IEEE80211_PMK_LEN)
+ return -1;
+
+ memset(&keyavail, 0, sizeof(keyavail));
+ os_strlcpy(keyavail.i_name, drv->ifname, sizeof(keyavail.i_name));
+ if (wpa_driver_openbsd_get_bssid(priv, keyavail.i_macaddr) < 0)
+ return -1;
+ memcpy(keyavail.i_key, key, key_len);
+
+ if (ioctl(drv->sock, SIOCS80211KEYAVAIL, &keyavail) < 0)
+ return -1;
+
+ return 0;
+}
+
+static void *
+wpa_driver_openbsd_init(void *ctx, const char *ifname)
+{
+ struct openbsd_driver_data *drv;
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+
+ drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->sock < 0)
+ goto fail;
+
+ drv->ctx = ctx;
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+
+ return drv;
+
+fail:
+ os_free(drv);
+ return NULL;
+}
+
+
+static void
+wpa_driver_openbsd_deinit(void *priv)
+{
+ struct openbsd_driver_data *drv = priv;
+
+ close(drv->sock);
+ os_free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_openbsd_ops = {
+ .name = "openbsd",
+ .desc = "OpenBSD 802.11 support",
+ .get_ssid = wpa_driver_openbsd_get_ssid,
+ .get_bssid = wpa_driver_openbsd_get_bssid,
+ .get_capa = wpa_driver_openbsd_get_capa,
+ .set_key = wpa_driver_openbsd_set_key,
+ .init = wpa_driver_openbsd_init,
+ .deinit = wpa_driver_openbsd_deinit,
+};
diff --git a/src/drivers/driver_privsep.c b/src/drivers/driver_privsep.c
index 9481cbf..ed88e71 100644
--- a/src/drivers/driver_privsep.c
+++ b/src/drivers/driver_privsep.c
@@ -304,17 +304,6 @@
}
-static int wpa_driver_privsep_disassociate(void *priv, const u8 *addr,
- int reason_code)
-{
- //struct wpa_driver_privsep_data *drv = priv;
- wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d",
- __func__, MAC2STR(addr), reason_code);
- wpa_printf(MSG_DEBUG, "%s - TODO", __func__);
- return 0;
-}
-
-
static void wpa_driver_privsep_event_assoc(void *ctx,
enum wpa_event_type event,
u8 *buf, size_t len)
@@ -736,7 +725,6 @@
.set_param = wpa_driver_privsep_set_param,
.scan2 = wpa_driver_privsep_scan,
.deauthenticate = wpa_driver_privsep_deauthenticate,
- .disassociate = wpa_driver_privsep_disassociate,
.associate = wpa_driver_privsep_associate,
.get_capa = wpa_driver_privsep_get_capa,
.get_mac_addr = wpa_driver_privsep_get_mac_addr,
diff --git a/src/drivers/driver_test.c b/src/drivers/driver_test.c
index e7bf195..c99802a 100644
--- a/src/drivers/driver_test.c
+++ b/src/drivers/driver_test.c
@@ -1318,10 +1318,12 @@
if (drv->pending_p2p_scan && drv->p2p) {
#ifdef CONFIG_P2P
size_t i;
+ struct os_time now;
+ os_get_time(&now);
for (i = 0; i < drv->num_scanres; i++) {
struct wpa_scan_res *bss = drv->scanres[i];
if (p2p_scan_res_handler(drv->p2p, bss->bssid,
- bss->freq, bss->level,
+ bss->freq, &now, bss->level,
(const u8 *) (bss + 1),
bss->ie_len) > 0)
return;
@@ -1714,20 +1716,6 @@
}
-static int wpa_driver_test_disassociate(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;
@@ -2870,7 +2858,7 @@
return -1;
return p2p_connect(drv->p2p, peer_addr, wps_method, go_intent,
own_interface_addr, force_freq, persistent_group,
- NULL, 0, 0);
+ NULL, 0, 0, 0);
}
@@ -3299,7 +3287,6 @@
.deinit = wpa_driver_test_deinit,
.set_param = wpa_driver_test_set_param,
.deauthenticate = wpa_driver_test_deauthenticate,
- .disassociate = wpa_driver_test_disassociate,
.associate = wpa_driver_test_associate,
.get_capa = wpa_driver_test_get_capa,
.get_mac_addr = wpa_driver_test_get_mac_addr,
diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
index bd37ca1..9733e01 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -1938,18 +1938,6 @@
}
-static int wpa_driver_wext_disassociate(void *priv, const u8 *addr,
- int reason_code)
-{
- struct wpa_driver_wext_data *drv = priv;
- int ret;
- wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
- ret = wpa_driver_wext_mlme(drv, addr, IW_MLME_DISASSOC, reason_code);
- wpa_driver_wext_disconnect(drv);
- return ret;
-}
-
-
static int wpa_driver_wext_set_gen_ie(void *priv, const u8 *ie,
size_t ie_len)
{
@@ -2485,7 +2473,6 @@
.scan2 = wpa_driver_wext_scan,
.get_scan_results2 = wpa_driver_wext_get_scan_results,
.deauthenticate = wpa_driver_wext_deauthenticate,
- .disassociate = wpa_driver_wext_disassociate,
.associate = wpa_driver_wext_associate,
.init = wpa_driver_wext_init,
.deinit = wpa_driver_wext_deinit,
diff --git a/src/drivers/drivers.c b/src/drivers/drivers.c
index a92eddf..1d0ff6e 100644
--- a/src/drivers/drivers.c
+++ b/src/drivers/drivers.c
@@ -24,6 +24,9 @@
#ifdef CONFIG_DRIVER_BSD
extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */
#endif /* CONFIG_DRIVER_BSD */
+#ifdef CONFIG_DRIVER_OPENBSD
+extern struct wpa_driver_ops wpa_driver_openbsd_ops; /* driver_openbsd.c */
+#endif /* CONFIG_DRIVER_OPENBSD */
#ifdef CONFIG_DRIVER_NDIS
extern struct wpa_driver_ops wpa_driver_ndis_ops; /* driver_ndis.c */
#endif /* CONFIG_DRIVER_NDIS */
@@ -62,6 +65,9 @@
#ifdef CONFIG_DRIVER_BSD
&wpa_driver_bsd_ops,
#endif /* CONFIG_DRIVER_BSD */
+#ifdef CONFIG_DRIVER_OPENBSD
+ &wpa_driver_openbsd_ops,
+#endif /* CONFIG_DRIVER_OPENBSD */
#ifdef CONFIG_DRIVER_NDIS
&wpa_driver_ndis_ops,
#endif /* CONFIG_DRIVER_NDIS */
diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak
index c7a98d3..68ff910 100644
--- a/src/drivers/drivers.mak
+++ b/src/drivers/drivers.mak
@@ -55,6 +55,14 @@
CONFIG_DNET_PCAP=y
endif
+ifdef CONFIG_DRIVER_OPENBSD
+ifndef CONFIG_L2_PACKET
+CONFIG_L2_PACKET=freebsd
+endif
+DRV_CFLAGS += -DCONFIG_DRIVER_OPENBSD
+DRV_OBJS += ../src/drivers/driver_openbsd.o
+endif
+
ifdef CONFIG_DRIVER_TEST
DRV_CFLAGS += -DCONFIG_DRIVER_TEST
DRV_OBJS += ../src/drivers/driver_test.o
diff --git a/src/drivers/drivers.mk b/src/drivers/drivers.mk
index 23fcbb7..db8561a 100644
--- a/src/drivers/drivers.mk
+++ b/src/drivers/drivers.mk
@@ -55,6 +55,14 @@
CONFIG_DNET_PCAP=y
endif
+ifdef CONFIG_DRIVER_OPENBSD
+ifndef CONFIG_L2_PACKET
+CONFIG_L2_PACKET=freebsd
+endif
+DRV_CFLAGS += -DCONFIG_DRIVER_OPENBSD
+DRV_OBJS += src/drivers/driver_openbsd.c
+endif
+
ifdef CONFIG_DRIVER_TEST
DRV_CFLAGS += -DCONFIG_DRIVER_TEST
DRV_OBJS += src/drivers/driver_test.c
diff --git a/src/drivers/netlink.c b/src/drivers/netlink.c
index dd662f3..6c60550 100644
--- a/src/drivers/netlink.c
+++ b/src/drivers/netlink.c
@@ -97,8 +97,6 @@
if (netlink == NULL)
return NULL;
- netlink->cfg = cfg;
-
netlink->sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (netlink->sock < 0) {
wpa_printf(MSG_ERROR, "netlink: Failed to open netlink "
@@ -121,6 +119,8 @@
eloop_register_read_sock(netlink->sock, netlink_receive, netlink,
NULL);
+ netlink->cfg = cfg;
+
return netlink;
}
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 2f38788..79da871 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -36,7 +36,21 @@
* The station is still assumed to belong to the AP interface it was added
* to.
*
- * TODO: need more info?
+ * Station handling varies per interface type and depending on the driver's
+ * capabilities.
+ *
+ * For drivers supporting TDLS with external setup (WIPHY_FLAG_SUPPORTS_TDLS
+ * and WIPHY_FLAG_TDLS_EXTERNAL_SETUP), the station lifetime is as follows:
+ * - a setup station entry is added, not yet authorized, without any rate
+ * or capability information, this just exists to avoid race conditions
+ * - when the TDLS setup is done, a single NL80211_CMD_SET_STATION is valid
+ * to add rate and capability information to the station and at the same
+ * time mark it authorized.
+ * - %NL80211_TDLS_ENABLE_LINK is then used
+ * - after this, the only valid operation is to remove it by tearing down
+ * the TDLS link (%NL80211_TDLS_DISABLE_LINK)
+ *
+ * TODO: need more info for other interface types
*/
/**
@@ -118,8 +132,9 @@
* to get a list of all present wiphys.
* @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or
* %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME,
- * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ,
- * %NL80211_ATTR_WIPHY_CHANNEL_TYPE, %NL80211_ATTR_WIPHY_RETRY_SHORT,
+ * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ (and the
+ * attributes determining the channel width; this is used for setting
+ * monitor mode channel), %NL80211_ATTR_WIPHY_RETRY_SHORT,
* %NL80211_ATTR_WIPHY_RETRY_LONG, %NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
* and/or %NL80211_ATTR_WIPHY_RTS_THRESHOLD.
* However, for setting the channel, see %NL80211_CMD_SET_CHANNEL
@@ -169,9 +184,10 @@
* %NL80211_ATTR_HIDDEN_SSID, %NL80211_ATTR_CIPHERS_PAIRWISE,
* %NL80211_ATTR_CIPHER_GROUP, %NL80211_ATTR_WPA_VERSIONS,
* %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY,
- * %NL80211_ATTR_AUTH_TYPE and %NL80211_ATTR_INACTIVITY_TIMEOUT.
+ * %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_INACTIVITY_TIMEOUT,
+ * %NL80211_ATTR_ACL_POLICY and %NL80211_ATTR_MAC_ADDRS.
* The channel to use can be set on the interface or be given using the
- * %NL80211_ATTR_WIPHY_FREQ and %NL80211_ATTR_WIPHY_CHANNEL_TYPE attrs.
+ * %NL80211_ATTR_WIPHY_FREQ and the attributes determining channel width.
* @NL80211_CMD_NEW_BEACON: old alias for %NL80211_CMD_START_AP
* @NL80211_CMD_STOP_AP: Stop AP operation on the given interface
* @NL80211_CMD_DEL_BEACON: old alias for %NL80211_CMD_STOP_AP
@@ -373,8 +389,8 @@
* requests to connect to a specified network but without separating
* auth and assoc steps. For this, you need to specify the SSID in a
* %NL80211_ATTR_SSID attribute, and can optionally specify the association
- * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_MAC,
- * %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
+ * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP,
+ * %NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
* %NL80211_ATTR_CONTROL_PORT_ETHERTYPE and
* %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT.
* Background scan period can optionally be
@@ -401,8 +417,7 @@
* a response while being associated to an AP on another channel.
* %NL80211_ATTR_IFINDEX is used to specify which interface (and thus
* radio) is used. %NL80211_ATTR_WIPHY_FREQ is used to specify the
- * frequency for the operation and %NL80211_ATTR_WIPHY_CHANNEL_TYPE may be
- * optionally used to specify additional channel parameters.
+ * frequency for the operation.
* %NL80211_ATTR_DURATION is used to specify the duration in milliseconds
* to remain on the channel. This command is also used as an event to
* notify when the requested duration starts (it may take a while for the
@@ -440,12 +455,11 @@
* as an event indicating reception of a frame that was not processed in
* kernel code, but is for us (i.e., which may need to be processed in a
* user space application). %NL80211_ATTR_FRAME is used to specify the
- * frame contents (including header). %NL80211_ATTR_WIPHY_FREQ (and
- * optionally %NL80211_ATTR_WIPHY_CHANNEL_TYPE) is used to indicate on
- * which channel the frame is to be transmitted or was received. If this
- * channel is not the current channel (remain-on-channel or the
- * operational channel) the device will switch to the given channel and
- * transmit the frame, optionally waiting for a response for the time
+ * frame contents (including header). %NL80211_ATTR_WIPHY_FREQ is used
+ * to indicate on which channel the frame is to be transmitted or was
+ * received. If this channel is not the current channel (remain-on-channel
+ * or the operational channel) the device will switch to the given channel
+ * and transmit the frame, optionally waiting for a response for the time
* specified using %NL80211_ATTR_DURATION. When called, this operation
* returns a cookie (%NL80211_ATTR_COOKIE) that will be included with the
* TX status event pertaining to the TX request.
@@ -473,8 +487,8 @@
* command is used as an event to indicate the that a trigger level was
* reached.
* @NL80211_CMD_SET_CHANNEL: Set the channel (using %NL80211_ATTR_WIPHY_FREQ
- * and %NL80211_ATTR_WIPHY_CHANNEL_TYPE) the given interface (identifed
- * by %NL80211_ATTR_IFINDEX) shall operate on.
+ * and the attributes determining channel width) the given interface
+ * (identifed by %NL80211_ATTR_IFINDEX) shall operate on.
* In case multiple channels are supported by the device, the mechanism
* with which it switches channels is implementation-defined.
* When a monitor interface is given, it can only switch channel while
@@ -499,9 +513,11 @@
* @NL80211_CMD_NEW_PEER_CANDIDATE: Notification on the reception of a
* beacon or probe response from a compatible mesh peer. This is only
* sent while no station information (sta_info) exists for the new peer
- * candidate and when @NL80211_MESH_SETUP_USERSPACE_AUTH is set. On
- * reception of this notification, userspace may decide to create a new
- * station (@NL80211_CMD_NEW_STATION). To stop this notification from
+ * candidate and when @NL80211_MESH_SETUP_USERSPACE_AUTH,
+ * @NL80211_MESH_SETUP_USERSPACE_AMPE, or
+ * @NL80211_MESH_SETUP_USERSPACE_MPM is set. On reception of this
+ * notification, userspace may decide to create a new station
+ * (@NL80211_CMD_NEW_STATION). To stop this notification from
* reoccurring, the userspace authentication daemon may want to create the
* new station with the AUTHENTICATED flag unset and maybe change it later
* depending on the authentication result.
@@ -513,6 +529,12 @@
* command with the %NL80211_ATTR_WOWLAN_TRIGGERS attribute. For
* more background information, see
* http://wireless.kernel.org/en/users/Documentation/WoWLAN.
+ * The @NL80211_CMD_SET_WOWLAN command can also be used as a notification
+ * from the driver reporting the wakeup reason. In this case, the
+ * @NL80211_ATTR_WOWLAN_TRIGGERS attribute will contain the reason
+ * for the wakeup, if it was caused by wireless. If it is not present
+ * in the wakeup notification, the wireless device didn't cause the
+ * wakeup but reports that it was woken up.
*
* @NL80211_CMD_SET_REKEY_OFFLOAD: This command is used give the driver
* the necessary information for supporting GTK rekey offload. This
@@ -526,6 +548,12 @@
* of PMKSA caching dandidates.
*
* @NL80211_CMD_TDLS_OPER: Perform a high-level TDLS command (e.g. link setup).
+ * In addition, this can be used as an event to request userspace to take
+ * actions on TDLS links (set up a new link or tear down an existing one).
+ * In such events, %NL80211_ATTR_TDLS_OPERATION indicates the requested
+ * operation, %NL80211_ATTR_MAC contains the peer MAC address, and
+ * %NL80211_ATTR_REASON_CODE the reason code to be used (only with
+ * %NL80211_TDLS_TEARDOWN).
* @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame.
*
* @NL80211_CMD_UNEXPECTED_FRAME: Used by an application controlling an AP
@@ -562,8 +590,54 @@
*
* @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 with
- * %NL80211_ATTR_WIPHY_CHANNEL_TYPE.
+ * %NL80211_ATTR_IFINDEX is now on %NL80211_ATTR_WIPHY_FREQ and the
+ * attributes determining channel width.
+ *
+ * @NL80211_CMD_START_P2P_DEVICE: Start the given P2P Device, identified by
+ * its %NL80211_ATTR_WDEV identifier. It must have been created with
+ * %NL80211_CMD_NEW_INTERFACE previously. After it has been started, the
+ * P2P Device can be used for P2P operations, e.g. remain-on-channel and
+ * public action frame TX.
+ * @NL80211_CMD_STOP_P2P_DEVICE: Stop the given P2P Device, identified by
+ * its %NL80211_ATTR_WDEV identifier.
+ *
+ * @NL80211_CMD_CONN_FAILED: connection request to an AP failed; used to
+ * notify userspace that AP has rejected the connection request from a
+ * station, due to particular reason. %NL80211_ATTR_CONN_FAILED_REASON
+ * is used for this.
+ *
+ * @NL80211_CMD_SET_MCAST_RATE: Change the rate used to send multicast frames
+ * for IBSS or MESH vif.
+ *
+ * @NL80211_CMD_SET_MAC_ACL: sets ACL for MAC address based access control.
+ * This is to be used with the drivers advertising the support of MAC
+ * address based access control. List of MAC addresses is passed in
+ * %NL80211_ATTR_MAC_ADDRS and ACL policy is passed in
+ * %NL80211_ATTR_ACL_POLICY. Driver will enable ACL with this list, if it
+ * is not already done. The new list will replace any existing list. Driver
+ * will clear its ACL when the list of MAC addresses passed is empty. This
+ * command is used in AP/P2P GO mode. Driver has to make sure to clear its
+ * ACL list during %NL80211_CMD_STOP_AP.
+ *
+ * @NL80211_CMD_RADAR_DETECT: Start a Channel availability check (CAC). Once
+ * a radar is detected or the channel availability scan (CAC) has finished
+ * or was aborted, or a radar was detected, usermode will be notified with
+ * this event. This command is also used to notify userspace about radars
+ * while operating on this channel.
+ * %NL80211_ATTR_RADAR_EVENT is used to inform about the type of the
+ * event.
+ *
+ * @NL80211_CMD_GET_PROTOCOL_FEATURES: Get global nl80211 protocol features,
+ * i.e. features for the nl80211 protocol rather than device features.
+ * Returns the features in the %NL80211_ATTR_PROTOCOL_FEATURES bitmap.
+ *
+ * @NL80211_CMD_UPDATE_FT_IES: Pass down the most up-to-date Fast Transition
+ * Information Element to the WLAN driver
+ *
+ * @NL80211_CMD_FT_EVENT: Send a Fast transition event from the WLAN driver
+ * to the supplicant. This will carry the target AP's MAC address along
+ * with the relevant Information Elements. This event is used to report
+ * received FT IEs (MDIE, FTIE, RSN IE, TIE, RICIE).
*
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
@@ -708,6 +782,22 @@
NL80211_CMD_CH_SWITCH_NOTIFY,
+ NL80211_CMD_START_P2P_DEVICE,
+ NL80211_CMD_STOP_P2P_DEVICE,
+
+ NL80211_CMD_CONN_FAILED,
+
+ NL80211_CMD_SET_MCAST_RATE,
+
+ NL80211_CMD_SET_MAC_ACL,
+
+ NL80211_CMD_RADAR_DETECT,
+
+ NL80211_CMD_GET_PROTOCOL_FEATURES,
+
+ NL80211_CMD_UPDATE_FT_IES,
+ NL80211_CMD_FT_EVENT,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -744,14 +834,26 @@
* /sys/class/ieee80211/<phyname>/index
* @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming)
* @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters
- * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz
+ * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz,
+ * defines the channel together with the (deprecated)
+ * %NL80211_ATTR_WIPHY_CHANNEL_TYPE attribute or the attributes
+ * %NL80211_ATTR_CHANNEL_WIDTH and if needed %NL80211_ATTR_CENTER_FREQ1
+ * and %NL80211_ATTR_CENTER_FREQ2
+ * @NL80211_ATTR_CHANNEL_WIDTH: u32 attribute containing one of the values
+ * of &enum nl80211_chan_width, describing the channel width. See the
+ * documentation of the enum for more information.
+ * @NL80211_ATTR_CENTER_FREQ1: Center frequency of the first part of the
+ * channel, used for anything but 20 MHz bandwidth
+ * @NL80211_ATTR_CENTER_FREQ2: Center frequency of the second part of the
+ * channel, used only for 80+80 MHz bandwidth
* @NL80211_ATTR_WIPHY_CHANNEL_TYPE: included with NL80211_ATTR_WIPHY_FREQ
- * if HT20 or HT40 are allowed (i.e., 802.11n disabled if not included):
+ * if HT20 or HT40 are to be used (i.e., HT disabled if not included):
* NL80211_CHAN_NO_HT = HT not allowed (i.e., same as not including
* this attribute)
* NL80211_CHAN_HT20 = HT20 only
* NL80211_CHAN_HT40MINUS = secondary channel is below the primary channel
* NL80211_CHAN_HT40PLUS = secondary channel is above the primary channel
+ * This attribute is now deprecated.
* @NL80211_ATTR_WIPHY_RETRY_SHORT: TX retry limit for frames whose length is
* less than or equal to the RTS threshold; allowed range: 1..255;
* dot11ShortRetryLimit; u8
@@ -815,7 +917,8 @@
* consisting of a nested array.
*
* @NL80211_ATTR_MESH_ID: mesh id (1-32 bytes).
- * @NL80211_ATTR_STA_PLINK_ACTION: action to perform on the mesh peer link.
+ * @NL80211_ATTR_STA_PLINK_ACTION: action to perform on the mesh peer link
+ * (see &enum nl80211_plink_action).
* @NL80211_ATTR_MPATH_NEXT_HOP: MAC address of the next hop for a mesh path.
* @NL80211_ATTR_MPATH_INFO: information about a mesh_path, part of mesh path
* info given for %NL80211_CMD_GET_MPATH, nested attribute described at
@@ -918,7 +1021,7 @@
* @NL80211_ATTR_USE_MFP: Whether management frame protection (IEEE 802.11w) is
* used for the association (&enum nl80211_mfp, represented as a u32);
* this attribute can be used
- * with %NL80211_CMD_ASSOCIATE request
+ * with %NL80211_CMD_ASSOCIATE and %NL80211_CMD_CONNECT requests
*
* @NL80211_ATTR_STA_FLAGS2: Attribute containing a
* &struct nl80211_sta_flag_update.
@@ -1098,10 +1201,10 @@
* @NL80211_ATTR_SUPPORT_MESH_AUTH: Currently, this means the underlying driver
* allows auth frames in a mesh to be passed to userspace for processing via
* the @NL80211_MESH_SETUP_USERSPACE_AUTH flag.
- * @NL80211_ATTR_STA_PLINK_STATE: The state of a mesh peer link as
- * defined in &enum nl80211_plink_state. Used when userspace is
- * driving the peer link management state machine.
- * @NL80211_MESH_SETUP_USERSPACE_AMPE must be enabled.
+ * @NL80211_ATTR_STA_PLINK_STATE: The state of a mesh peer link as defined in
+ * &enum nl80211_plink_state. Used when userspace is driving the peer link
+ * management state machine. @NL80211_MESH_SETUP_USERSPACE_AMPE or
+ * @NL80211_MESH_SETUP_USERSPACE_MPM must be enabled.
*
* @NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED: indicates, as part of the wiphy
* capabilities, the supported WoWLAN triggers
@@ -1251,6 +1354,66 @@
* was used to provide the hint. For the different types of
* allowed user regulatory hints see nl80211_user_reg_hint_type.
*
+ * @NL80211_ATTR_CONN_FAILED_REASON: The reason for which AP has rejected
+ * the connection request from a station. nl80211_connect_failed_reason
+ * enum has different reasons of connection failure.
+ *
+ * @NL80211_ATTR_SAE_DATA: SAE elements in Authentication frames. This starts
+ * with the Authentication transaction sequence number field.
+ *
+ * @NL80211_ATTR_VHT_CAPABILITY: VHT Capability information element (from
+ * association request when used with NL80211_CMD_NEW_STATION)
+ *
+ * @NL80211_ATTR_SCAN_FLAGS: scan request control flags (u32)
+ *
+ * @NL80211_ATTR_P2P_CTWINDOW: P2P GO Client Traffic Window (u8), used with
+ * the START_AP and SET_BSS commands
+ * @NL80211_ATTR_P2P_OPPPS: P2P GO opportunistic PS (u8), used with the
+ * START_AP and SET_BSS commands. This can have the values 0 or 1;
+ * if not given in START_AP 0 is assumed, if not given in SET_BSS
+ * no change is made.
+ *
+ * @NL80211_ATTR_LOCAL_MESH_POWER_MODE: local mesh STA link-specific power mode
+ * defined in &enum nl80211_mesh_power_mode.
+ *
+ * @NL80211_ATTR_ACL_POLICY: ACL policy, see &enum nl80211_acl_policy,
+ * carried in a u32 attribute
+ *
+ * @NL80211_ATTR_MAC_ADDRS: Array of nested MAC addresses, used for
+ * MAC ACL.
+ *
+ * @NL80211_ATTR_MAC_ACL_MAX: u32 attribute to advertise the maximum
+ * number of MAC addresses that a device can support for MAC
+ * ACL.
+ *
+ * @NL80211_ATTR_RADAR_EVENT: Type of radar event for notification to userspace,
+ * contains a value of enum nl80211_radar_event (u32).
+ *
+ * @NL80211_ATTR_EXT_CAPA: 802.11 extended capabilities that the kernel driver
+ * has and handles. The format is the same as the IE contents. See
+ * 802.11-2012 8.4.2.29 for more information.
+ * @NL80211_ATTR_EXT_CAPA_MASK: Extended capabilities that the kernel driver
+ * has set in the %NL80211_ATTR_EXT_CAPA value, for multibit fields.
+ *
+ * @NL80211_ATTR_STA_CAPABILITY: Station capabilities (u16) are advertised to
+ * the driver, e.g., to enable TDLS power save (PU-APSD).
+ *
+ * @NL80211_ATTR_STA_EXT_CAPABILITY: Station extended capabilities are
+ * advertised to the driver, e.g., to enable TDLS off channel operations
+ * and PU-APSD.
+ *
+ * @NL80211_ATTR_PROTOCOL_FEATURES: global nl80211 feature flags, see
+ * &enum nl80211_protocol_features, the attribute is a u32.
+ *
+ * @NL80211_ATTR_SPLIT_WIPHY_DUMP: flag attribute, userspace supports
+ * receiving the data for a single wiphy split across multiple
+ * messages, given with wiphy dump message
+ *
+ * @NL80211_ATTR_MDID: Mobility Domain Identifier
+ *
+ * @NL80211_ATTR_IE_RIC: Resource Information Container Information
+ * Element
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -1506,6 +1669,46 @@
NL80211_ATTR_USER_REG_HINT_TYPE,
+ NL80211_ATTR_CONN_FAILED_REASON,
+
+ NL80211_ATTR_SAE_DATA,
+
+ NL80211_ATTR_VHT_CAPABILITY,
+
+ NL80211_ATTR_SCAN_FLAGS,
+
+ NL80211_ATTR_CHANNEL_WIDTH,
+ NL80211_ATTR_CENTER_FREQ1,
+ NL80211_ATTR_CENTER_FREQ2,
+
+ NL80211_ATTR_P2P_CTWINDOW,
+ NL80211_ATTR_P2P_OPPPS,
+
+ NL80211_ATTR_LOCAL_MESH_POWER_MODE,
+
+ NL80211_ATTR_ACL_POLICY,
+
+ NL80211_ATTR_MAC_ADDRS,
+
+ NL80211_ATTR_MAC_ACL_MAX,
+
+ NL80211_ATTR_RADAR_EVENT,
+
+ NL80211_ATTR_EXT_CAPA,
+ NL80211_ATTR_EXT_CAPA_MASK,
+
+ NL80211_ATTR_STA_CAPABILITY,
+ NL80211_ATTR_STA_EXT_CAPABILITY,
+
+ NL80211_ATTR_PROTOCOL_FEATURES,
+ NL80211_ATTR_SPLIT_WIPHY_DUMP,
+
+ NL80211_ATTR_DISABLE_VHT,
+ NL80211_ATTR_VHT_CAPABILITY_MASK,
+
+ NL80211_ATTR_MDID,
+ NL80211_ATTR_IE_RIC,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -1549,6 +1752,7 @@
#define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16
#define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24
#define NL80211_HT_CAPABILITY_LEN 26
+#define NL80211_VHT_CAPABILITY_LEN 12
#define NL80211_MAX_NR_CIPHER_SUITES 5
#define NL80211_MAX_NR_AKM_SUITES 2
@@ -1575,6 +1779,10 @@
* @NL80211_IFTYPE_MESH_POINT: mesh point
* @NL80211_IFTYPE_P2P_CLIENT: P2P client
* @NL80211_IFTYPE_P2P_GO: P2P group owner
+ * @NL80211_IFTYPE_P2P_DEVICE: P2P device interface type, this is not a netdev
+ * 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_IFTYPE_MAX: highest interface type number currently defined
* @NUM_NL80211_IFTYPES: number of defined interface types
*
@@ -1593,6 +1801,7 @@
NL80211_IFTYPE_MESH_POINT,
NL80211_IFTYPE_P2P_CLIENT,
NL80211_IFTYPE_P2P_GO,
+ NL80211_IFTYPE_P2P_DEVICE,
/* keep last */
NUM_NL80211_IFTYPES,
@@ -1617,6 +1826,9 @@
* flag can't be changed, it is only valid while adding a station, and
* attempts to change it will silently be ignored (rather than rejected
* as errors.)
+ * @NL80211_STA_FLAG_ASSOCIATED: station is associated; used with drivers
+ * that support %NL80211_FEATURE_FULL_AP_CLIENT_STATE to transition a
+ * previously added station into associated state
* @NL80211_STA_FLAG_MAX: highest station flag number currently defined
* @__NL80211_STA_FLAG_AFTER_LAST: internal use
*/
@@ -1628,6 +1840,7 @@
NL80211_STA_FLAG_MFP,
NL80211_STA_FLAG_AUTHENTICATED,
NL80211_STA_FLAG_TDLS_PEER,
+ NL80211_STA_FLAG_ASSOCIATED,
/* keep last */
__NL80211_STA_FLAG_AFTER_LAST,
@@ -1664,10 +1877,15 @@
* @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved
* @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s)
* @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8)
- * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate
+ * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 MHz dualchannel bitrate
* @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval
* @NL80211_RATE_INFO_BITRATE32: total bitrate (u32, 100kbit/s)
* @NL80211_RATE_INFO_MAX: highest rate_info number currently defined
+ * @NL80211_RATE_INFO_VHT_MCS: MCS index for VHT (u8)
+ * @NL80211_RATE_INFO_VHT_NSS: number of streams in VHT (u8)
+ * @NL80211_RATE_INFO_80_MHZ_WIDTH: 80 MHz VHT rate
+ * @NL80211_RATE_INFO_80P80_MHZ_WIDTH: 80+80 MHz VHT rate
+ * @NL80211_RATE_INFO_160_MHZ_WIDTH: 160 MHz VHT rate
* @__NL80211_RATE_INFO_AFTER_LAST: internal use
*/
enum nl80211_rate_info {
@@ -1677,6 +1895,11 @@
NL80211_RATE_INFO_40_MHZ_WIDTH,
NL80211_RATE_INFO_SHORT_GI,
NL80211_RATE_INFO_BITRATE32,
+ NL80211_RATE_INFO_VHT_MCS,
+ NL80211_RATE_INFO_VHT_NSS,
+ NL80211_RATE_INFO_80_MHZ_WIDTH,
+ NL80211_RATE_INFO_80P80_MHZ_WIDTH,
+ NL80211_RATE_INFO_160_MHZ_WIDTH,
/* keep last */
__NL80211_RATE_INFO_AFTER_LAST,
@@ -1723,6 +1946,8 @@
* @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs)
* @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station)
* @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station)
+ * @NL80211_STA_INFO_RX_BYTES64: total received bytes (u64, from this station)
+ * @NL80211_STA_INFO_TX_BYTES64: total transmitted bytes (u64, to this station)
* @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm)
* @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute
* containing info as possible, see &enum nl80211_rate_info
@@ -1744,6 +1969,10 @@
* @NL80211_STA_INFO_STA_FLAGS: Contains a struct nl80211_sta_flag_update.
* @NL80211_STA_INFO_BEACON_LOSS: count of times beacon loss was detected (u32)
* @NL80211_STA_INFO_T_OFFSET: timing offset with respect to this STA (s64)
+ * @NL80211_STA_INFO_LOCAL_PM: local mesh STA link-specific power mode
+ * @NL80211_STA_INFO_PEER_PM: peer mesh STA link-specific power mode
+ * @NL80211_STA_INFO_NONPEER_PM: neighbor mesh STA power save mode towards
+ * non-peer STA
* @__NL80211_STA_INFO_AFTER_LAST: internal
* @NL80211_STA_INFO_MAX: highest possible station info attribute
*/
@@ -1768,6 +1997,11 @@
NL80211_STA_INFO_STA_FLAGS,
NL80211_STA_INFO_BEACON_LOSS,
NL80211_STA_INFO_T_OFFSET,
+ NL80211_STA_INFO_LOCAL_PM,
+ NL80211_STA_INFO_PEER_PM,
+ NL80211_STA_INFO_NONPEER_PM,
+ NL80211_STA_INFO_RX_BYTES64,
+ NL80211_STA_INFO_TX_BYTES64,
/* keep last */
__NL80211_STA_INFO_AFTER_LAST,
@@ -1877,6 +2111,20 @@
* on this channel in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm
* (100 * dBm).
+ * @NL80211_FREQUENCY_ATTR_DFS_STATE: current state for DFS
+ * (enum nl80211_dfs_state)
+ * @NL80211_FREQUENCY_ATTR_DFS_TIME: time in miliseconds for how long
+ * this channel is in this DFS state.
+ * @NL80211_FREQUENCY_ATTR_NO_HT40_MINUS: HT40- isn't possible with this
+ * channel as the control channel
+ * @NL80211_FREQUENCY_ATTR_NO_HT40_PLUS: HT40+ isn't possible with this
+ * channel as the control channel
+ * @NL80211_FREQUENCY_ATTR_NO_80MHZ: any 80 MHz channel using this channel
+ * as the primary or any of the secondary channels isn't possible,
+ * this includes 80+80 channels
+ * @NL80211_FREQUENCY_ATTR_NO_160MHZ: any 160 MHz (but not 80+80) channel
+ * using this channel as the primary or any of the secondary channels
+ * isn't possible
* @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
* currently defined
* @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
@@ -1889,6 +2137,12 @@
NL80211_FREQUENCY_ATTR_NO_IBSS,
NL80211_FREQUENCY_ATTR_RADAR,
NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
+ NL80211_FREQUENCY_ATTR_DFS_STATE,
+ NL80211_FREQUENCY_ATTR_DFS_TIME,
+ NL80211_FREQUENCY_ATTR_NO_HT40_MINUS,
+ NL80211_FREQUENCY_ATTR_NO_HT40_PLUS,
+ NL80211_FREQUENCY_ATTR_NO_80MHZ,
+ NL80211_FREQUENCY_ATTR_NO_160MHZ,
/* keep last */
__NL80211_FREQUENCY_ATTR_AFTER_LAST,
@@ -2159,6 +2413,34 @@
};
/**
+ * enum nl80211_mesh_power_mode - mesh power save modes
+ *
+ * @NL80211_MESH_POWER_UNKNOWN: The mesh power mode of the mesh STA is
+ * not known or has not been set yet.
+ * @NL80211_MESH_POWER_ACTIVE: Active mesh power mode. The mesh STA is
+ * in Awake state all the time.
+ * @NL80211_MESH_POWER_LIGHT_SLEEP: Light sleep mode. The mesh STA will
+ * alternate between Active and Doze states, but will wake up for
+ * neighbor's beacons.
+ * @NL80211_MESH_POWER_DEEP_SLEEP: Deep sleep mode. The mesh STA will
+ * alternate between Active and Doze states, but may not wake up
+ * for neighbor's beacons.
+ *
+ * @__NL80211_MESH_POWER_AFTER_LAST - internal use
+ * @NL80211_MESH_POWER_MAX - highest possible power save level
+ */
+
+enum nl80211_mesh_power_mode {
+ NL80211_MESH_POWER_UNKNOWN,
+ NL80211_MESH_POWER_ACTIVE,
+ NL80211_MESH_POWER_LIGHT_SLEEP,
+ NL80211_MESH_POWER_DEEP_SLEEP,
+
+ __NL80211_MESH_POWER_AFTER_LAST,
+ NL80211_MESH_POWER_MAX = __NL80211_MESH_POWER_AFTER_LAST - 1
+};
+
+/**
* enum nl80211_meshconf_params - mesh configuration parameters
*
* Mesh configuration parameters. These can be changed while the mesh is
@@ -2185,8 +2467,10 @@
* @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh
* point.
*
- * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically
- * open peer links when we detect compatible mesh peers.
+ * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically open
+ * peer links when we detect compatible mesh peers. Disabled if
+ * @NL80211_MESH_SETUP_USERSPACE_MPM or @NL80211_MESH_SETUP_USERSPACE_AMPE are
+ * set.
*
* @NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES: the number of action frames
* containing a PREQ that an MP can send to a particular destination (path
@@ -2252,6 +2536,11 @@
* (in TUs) during which a mesh STA can send only one Action frame
* containing a PREQ element for root path confirmation.
*
+ * @NL80211_MESHCONF_POWER_MODE: Default mesh power mode for new peer links.
+ * type &enum nl80211_mesh_power_mode (u32)
+ *
+ * @NL80211_MESHCONF_AWAKE_WINDOW: awake window duration (in TUs)
+ *
* @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
*/
enum nl80211_meshconf_params {
@@ -2281,6 +2570,8 @@
NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
+ NL80211_MESHCONF_POWER_MODE,
+ NL80211_MESHCONF_AWAKE_WINDOW,
/* keep last */
__NL80211_MESHCONF_ATTR_AFTER_LAST,
@@ -2325,6 +2616,9 @@
* vendor specific synchronization method or disable it to use the default
* neighbor offset synchronization
*
+ * @NL80211_MESH_SETUP_USERSPACE_MPM: Enable this option if userspace will
+ * implement an MPM which handles peer allocation and state.
+ *
* @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number
*
* @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use
@@ -2337,6 +2631,7 @@
NL80211_MESH_SETUP_USERSPACE_AUTH,
NL80211_MESH_SETUP_USERSPACE_AMPE,
NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC,
+ NL80211_MESH_SETUP_USERSPACE_MPM,
/* keep last */
__NL80211_MESH_SETUP_ATTR_AFTER_LAST,
@@ -2385,6 +2680,15 @@
#define NL80211_TXQ_Q_BE NL80211_AC_BE
#define NL80211_TXQ_Q_BK NL80211_AC_BK
+/**
+ * enum nl80211_channel_type - channel type
+ * @NL80211_CHAN_NO_HT: 20 MHz, non-HT channel
+ * @NL80211_CHAN_HT20: 20 MHz HT channel
+ * @NL80211_CHAN_HT40MINUS: HT40 channel, secondary channel
+ * below the control channel
+ * @NL80211_CHAN_HT40PLUS: HT40 channel, secondary channel
+ * above the control channel
+ */
enum nl80211_channel_type {
NL80211_CHAN_NO_HT,
NL80211_CHAN_HT20,
@@ -2393,6 +2697,32 @@
};
/**
+ * enum nl80211_chan_width - channel width definitions
+ *
+ * These values are used with the %NL80211_ATTR_CHANNEL_WIDTH
+ * attribute.
+ *
+ * @NL80211_CHAN_WIDTH_20_NOHT: 20 MHz, non-HT channel
+ * @NL80211_CHAN_WIDTH_20: 20 MHz HT channel
+ * @NL80211_CHAN_WIDTH_40: 40 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
+ * attribute must be provided as well
+ * @NL80211_CHAN_WIDTH_80: 80 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
+ * attribute must be provided as well
+ * @NL80211_CHAN_WIDTH_80P80: 80+80 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
+ * and %NL80211_ATTR_CENTER_FREQ2 attributes must be provided as well
+ * @NL80211_CHAN_WIDTH_160: 160 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
+ * attribute must be provided as well
+ */
+enum nl80211_chan_width {
+ NL80211_CHAN_WIDTH_20_NOHT,
+ NL80211_CHAN_WIDTH_20,
+ NL80211_CHAN_WIDTH_40,
+ NL80211_CHAN_WIDTH_80,
+ NL80211_CHAN_WIDTH_80P80,
+ NL80211_CHAN_WIDTH_160,
+};
+
+/**
* enum nl80211_bss - netlink attributes for a BSS
*
* @__NL80211_BSS_INVALID: invalid
@@ -2460,6 +2790,7 @@
* @NL80211_AUTHTYPE_SHARED_KEY: Shared Key authentication (WEP only)
* @NL80211_AUTHTYPE_FT: Fast BSS Transition (IEEE 802.11r)
* @NL80211_AUTHTYPE_NETWORK_EAP: Network EAP (some Cisco APs and mainly LEAP)
+ * @NL80211_AUTHTYPE_SAE: Simultaneous authentication of equals
* @__NL80211_AUTHTYPE_NUM: internal
* @NL80211_AUTHTYPE_MAX: maximum valid auth algorithm
* @NL80211_AUTHTYPE_AUTOMATIC: determine automatically (if necessary by
@@ -2471,6 +2802,7 @@
NL80211_AUTHTYPE_SHARED_KEY,
NL80211_AUTHTYPE_FT,
NL80211_AUTHTYPE_NETWORK_EAP,
+ NL80211_AUTHTYPE_SAE,
/* keep last */
__NL80211_AUTHTYPE_NUM,
@@ -2689,10 +3021,12 @@
* corresponds to the lowest-order bit in the second byte of the mask.
* For example: The match 00:xx:00:00:xx:00:00:00:00:xx:xx:xx (where
* xx indicates "don't care") would be represented by a pattern of
- * twelve zero bytes, and a mask of "0xed,0x07".
+ * twelve zero bytes, and a mask of "0xed,0x01".
* Note that the pattern matching is done as though frames were not
* 802.11 frames but 802.3 frames, i.e. the frame is fully unpacked
* first (including SNAP header unpacking) and then matched.
+ * @NL80211_WOWLAN_PKTPAT_OFFSET: packet offset, pattern is matched after
+ * these fixed number of bytes of received packet
* @NUM_NL80211_WOWLAN_PKTPAT: number of attributes
* @MAX_NL80211_WOWLAN_PKTPAT: max attribute number
*/
@@ -2700,6 +3034,7 @@
__NL80211_WOWLAN_PKTPAT_INVALID,
NL80211_WOWLAN_PKTPAT_MASK,
NL80211_WOWLAN_PKTPAT_PATTERN,
+ NL80211_WOWLAN_PKTPAT_OFFSET,
NUM_NL80211_WOWLAN_PKTPAT,
MAX_NL80211_WOWLAN_PKTPAT = NUM_NL80211_WOWLAN_PKTPAT - 1,
@@ -2710,6 +3045,7 @@
* @max_patterns: maximum number of patterns supported
* @min_pattern_len: minimum length of each pattern
* @max_pattern_len: maximum length of each pattern
+ * @max_pkt_offset: maximum Rx packet offset
*
* This struct is carried in %NL80211_WOWLAN_TRIG_PKT_PATTERN when
* that is part of %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED in the
@@ -2719,6 +3055,7 @@
__u32 max_patterns;
__u32 min_pattern_len;
__u32 max_pattern_len;
+ __u32 max_pkt_offset;
} __attribute__((packed));
/**
@@ -2734,12 +3071,17 @@
* @NL80211_WOWLAN_TRIG_PKT_PATTERN: wake up on the specified packet patterns
* which are passed in an array of nested attributes, each nested attribute
* defining a with attributes from &struct nl80211_wowlan_trig_pkt_pattern.
- * Each pattern defines a wakeup packet. The matching is done on the MSDU,
- * i.e. as though the packet was an 802.3 packet, so the pattern matching
- * is done after the packet is converted to the MSDU.
+ * Each pattern defines a wakeup packet. Packet offset is associated with
+ * each pattern which is used while matching the pattern. The matching is
+ * done on the MSDU, i.e. as though the packet was an 802.3 packet, so the
+ * pattern matching is done after the packet is converted to the MSDU.
*
* In %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, it is a binary attribute
* carrying a &struct nl80211_wowlan_pattern_support.
+ *
+ * When reporting wakeup. it is a u32 attribute containing the 0-based
+ * index of the pattern that caused the wakeup, in the patterns passed
+ * to the kernel when configuring.
* @NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED: Not a real trigger, and cannot be
* used when setting, used only to indicate that GTK rekeying is supported
* by the device (flag)
@@ -2750,8 +3092,36 @@
* @NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE: wake up on 4-way handshake (flag)
* @NL80211_WOWLAN_TRIG_RFKILL_RELEASE: wake up when rfkill is released
* (on devices that have rfkill in the device) (flag)
+ * @NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211: For wakeup reporting only, contains
+ * the 802.11 packet that caused the wakeup, e.g. a deauth frame. The frame
+ * may be truncated, the @NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN
+ * attribute contains the original length.
+ * @NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN: Original length of the 802.11
+ * packet, may be bigger than the @NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211
+ * attribute if the packet was truncated somewhere.
+ * @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023: For wakeup reporting only, contains the
+ * 802.11 packet that caused the wakeup, e.g. a magic packet. The frame may
+ * be truncated, the @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN attribute
+ * contains the original length.
+ * @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN: Original length of the 802.3
+ * packet, may be bigger than the @NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023
+ * attribute if the packet was truncated somewhere.
+ * @NL80211_WOWLAN_TRIG_TCP_CONNECTION: TCP connection wake, see DOC section
+ * "TCP connection wakeup" for more details. This is a nested attribute
+ * containing the exact information for establishing and keeping alive
+ * the TCP connection.
+ * @NL80211_WOWLAN_TRIG_TCP_WAKEUP_MATCH: For wakeup reporting only, the
+ * wakeup packet was received on the TCP connection
+ * @NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST: For wakeup reporting only, the
+ * TCP connection was lost or failed to be established
+ * @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
* @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers
* @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number
+ *
+ * These nested attributes are used to configure the wakeup triggers and
+ * to report the wakeup reason(s).
*/
enum nl80211_wowlan_triggers {
__NL80211_WOWLAN_TRIG_INVALID,
@@ -2764,6 +3134,14 @@
NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST,
NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE,
NL80211_WOWLAN_TRIG_RFKILL_RELEASE,
+ NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211,
+ NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN,
+ NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023,
+ NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023_LEN,
+ NL80211_WOWLAN_TRIG_TCP_CONNECTION,
+ NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH,
+ NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST,
+ NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS,
/* keep last */
NUM_NL80211_WOWLAN_TRIG,
@@ -2771,6 +3149,116 @@
};
/**
+ * DOC: TCP connection wakeup
+ *
+ * Some devices can establish a TCP connection in order to be woken up by a
+ * packet coming in from outside their network segment, or behind NAT. If
+ * configured, the device will establish a TCP connection to the given
+ * service, and periodically send data to that service. The first data
+ * packet is usually transmitted after SYN/ACK, also ACKing the SYN/ACK.
+ * The data packets can optionally include a (little endian) sequence
+ * number (in the TCP payload!) that is generated by the device, and, also
+ * optionally, a token from a list of tokens. This serves as a keep-alive
+ * with the service, and for NATed connections, etc.
+ *
+ * During this keep-alive period, the server doesn't send any data to the
+ * client. When receiving data, it is compared against the wakeup pattern
+ * (and mask) and if it matches, the host is woken up. Similarly, if the
+ * connection breaks or cannot be established to start with, the host is
+ * also woken up.
+ *
+ * Developer's note: ARP offload is required for this, otherwise TCP
+ * response packets might not go through correctly.
+ */
+
+/**
+ * struct nl80211_wowlan_tcp_data_seq - WoWLAN TCP data sequence
+ * @start: starting value
+ * @offset: offset of sequence number in packet
+ * @len: length of the sequence value to write, 1 through 4
+ *
+ * Note: don't confuse with the TCP sequence number(s), this is for the
+ * keepalive packet payload. The actual value is written into the packet
+ * in little endian.
+ */
+struct nl80211_wowlan_tcp_data_seq {
+ __u32 start, offset, len;
+};
+
+/**
+ * struct nl80211_wowlan_tcp_data_token - WoWLAN TCP data token config
+ * @offset: offset of token in packet
+ * @len: length of each token
+ * @token_stream: stream of data to be used for the tokens, the length must
+ * be a multiple of @len for this to make sense
+ */
+struct nl80211_wowlan_tcp_data_token {
+ __u32 offset, len;
+ __u8 token_stream[];
+};
+
+/**
+ * struct nl80211_wowlan_tcp_data_token_feature - data token features
+ * @min_len: minimum token length
+ * @max_len: maximum token length
+ * @bufsize: total available token buffer size (max size of @token_stream)
+ */
+struct nl80211_wowlan_tcp_data_token_feature {
+ __u32 min_len, max_len, bufsize;
+};
+
+/**
+ * enum nl80211_wowlan_tcp_attrs - WoWLAN TCP connection parameters
+ * @__NL80211_WOWLAN_TCP_INVALID: invalid number for nested attributes
+ * @NL80211_WOWLAN_TCP_SRC_IPV4: source IPv4 address (in network byte order)
+ * @NL80211_WOWLAN_TCP_DST_IPV4: destination IPv4 address
+ * (in network byte order)
+ * @NL80211_WOWLAN_TCP_DST_MAC: destination MAC address, this is given because
+ * route lookup when configured might be invalid by the time we suspend,
+ * and doing a route lookup when suspending is no longer possible as it
+ * might require ARP querying.
+ * @NL80211_WOWLAN_TCP_SRC_PORT: source port (u16); optional, if not given a
+ * socket and port will be allocated
+ * @NL80211_WOWLAN_TCP_DST_PORT: destination port (u16)
+ * @NL80211_WOWLAN_TCP_DATA_PAYLOAD: data packet payload, at least one byte.
+ * For feature advertising, a u32 attribute holding the maximum length
+ * of the data payload.
+ * @NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ: data packet sequence configuration
+ * (if desired), a &struct nl80211_wowlan_tcp_data_seq. For feature
+ * advertising it is just a flag
+ * @NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN: data packet token configuration,
+ * see &struct nl80211_wowlan_tcp_data_token and for advertising see
+ * &struct nl80211_wowlan_tcp_data_token_feature.
+ * @NL80211_WOWLAN_TCP_DATA_INTERVAL: data interval in seconds, maximum
+ * interval in feature advertising (u32)
+ * @NL80211_WOWLAN_TCP_WAKE_PAYLOAD: wake packet payload, for advertising a
+ * u32 attribute holding the maximum length
+ * @NL80211_WOWLAN_TCP_WAKE_MASK: Wake packet payload mask, not used for
+ * feature advertising. The mask works like @NL80211_WOWLAN_PKTPAT_MASK
+ * but on the TCP payload only.
+ * @NUM_NL80211_WOWLAN_TCP: number of TCP attributes
+ * @MAX_NL80211_WOWLAN_TCP: highest attribute number
+ */
+enum nl80211_wowlan_tcp_attrs {
+ __NL80211_WOWLAN_TCP_INVALID,
+ NL80211_WOWLAN_TCP_SRC_IPV4,
+ NL80211_WOWLAN_TCP_DST_IPV4,
+ NL80211_WOWLAN_TCP_DST_MAC,
+ NL80211_WOWLAN_TCP_SRC_PORT,
+ NL80211_WOWLAN_TCP_DST_PORT,
+ NL80211_WOWLAN_TCP_DATA_PAYLOAD,
+ NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ,
+ NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN,
+ NL80211_WOWLAN_TCP_DATA_INTERVAL,
+ NL80211_WOWLAN_TCP_WAKE_PAYLOAD,
+ NL80211_WOWLAN_TCP_WAKE_MASK,
+
+ /* keep last */
+ NUM_NL80211_WOWLAN_TCP,
+ MAX_NL80211_WOWLAN_TCP = NUM_NL80211_WOWLAN_TCP - 1
+};
+
+/**
* enum nl80211_iface_limit_attrs - limit attributes
* @NL80211_IFACE_LIMIT_UNSPEC: (reserved)
* @NL80211_IFACE_LIMIT_MAX: maximum number of interfaces that
@@ -2806,6 +3294,8 @@
* the infrastructure network's beacon interval.
* @NL80211_IFACE_COMB_NUM_CHANNELS: u32 attribute specifying how many
* different channels may be used within this group.
+ * @NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS: u32 attribute containing the bitmap
+ * of supported channel widths for radar detection.
* @NUM_NL80211_IFACE_COMB: number of attributes
* @MAX_NL80211_IFACE_COMB: highest attribute number
*
@@ -2838,6 +3328,7 @@
NL80211_IFACE_COMB_MAXNUM,
NL80211_IFACE_COMB_STA_AP_BI_MATCH,
NL80211_IFACE_COMB_NUM_CHANNELS,
+ NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
/* keep last */
NUM_NL80211_IFACE_COMB,
@@ -2877,6 +3368,23 @@
MAX_NL80211_PLINK_STATES = NUM_NL80211_PLINK_STATES - 1
};
+/**
+ * enum nl80211_plink_action - actions to perform in mesh peers
+ *
+ * @NL80211_PLINK_ACTION_NO_ACTION: perform no action
+ * @NL80211_PLINK_ACTION_OPEN: start mesh peer link establishment
+ * @NL80211_PLINK_ACTION_BLOCK: block traffic from this mesh peer
+ * @NUM_NL80211_PLINK_ACTIONS: number of possible actions
+ */
+enum plink_actions {
+ NL80211_PLINK_ACTION_NO_ACTION,
+ NL80211_PLINK_ACTION_OPEN,
+ NL80211_PLINK_ACTION_BLOCK,
+
+ NUM_NL80211_PLINK_ACTIONS,
+};
+
+
#define NL80211_KCK_LEN 16
#define NL80211_KEK_LEN 16
#define NL80211_REPLAY_CTR_LEN 8
@@ -2994,12 +3502,61 @@
* @NL80211_FEATURE_CELL_BASE_REG_HINTS: This driver has been tested
* to work properly to suppport receiving regulatory hints from
* cellular base stations.
+ * @NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL: If this is set, an active
+ * P2P Device (%NL80211_IFTYPE_P2P_DEVICE) requires its own channel
+ * in the interface combinations, even when it's only used for scan
+ * and remain-on-channel. This could be due to, for example, the
+ * remain-on-channel implementation requiring a channel context.
+ * @NL80211_FEATURE_SAE: This driver supports simultaneous authentication of
+ * equals (SAE) with user space SME (NL80211_CMD_AUTHENTICATE) in station
+ * mode
+ * @NL80211_FEATURE_LOW_PRIORITY_SCAN: This driver supports low priority scan
+ * @NL80211_FEATURE_SCAN_FLUSH: Scan flush is supported
+ * @NL80211_FEATURE_AP_SCAN: Support scanning using an AP vif
+ * @NL80211_FEATURE_VIF_TXPOWER: The driver supports per-vif TX power setting
+ * @NL80211_FEATURE_NEED_OBSS_SCAN: The driver expects userspace to perform
+ * OBSS scans and generate 20/40 BSS coex reports. This flag is used only
+ * for drivers implementing the CONNECT API, for AUTH/ASSOC it is implied.
+ * @NL80211_FEATURE_P2P_GO_CTWIN: P2P GO implementation supports CT Window
+ * setting
+ * @NL80211_FEATURE_P2P_GO_OPPPS: P2P GO implementation supports opportunistic
+ * powersave
+ * @NL80211_FEATURE_FULL_AP_CLIENT_STATE: The driver supports full state
+ * transitions for AP clients. Without this flag (and if the driver
+ * doesn't have the AP SME in the device) the driver supports adding
+ * stations only when they're associated and adds them in associated
+ * state (to later be transitioned into authorized), with this flag
+ * they should be added before even sending the authentication reply
+ * and then transitioned into authenticated, associated and authorized
+ * states using station flags.
+ * Note that even for drivers that support this, the default is to add
+ * stations in authenticated/associated state, so to add unauthenticated
+ * stations the authenticated/associated bits have to be set in the mask.
+ * @NL80211_FEATURE_ADVERTISE_CHAN_LIMITS: cfg80211 advertises channel limits
+ * (HT40, VHT 80/160 MHz) if this flag is set
+ * @NL80211_FEATURE_USERSPACE_MPM: This driver supports a userspace Mesh
+ * Peering Management entity which may be implemented by registering for
+ * beacons or NL80211_CMD_NEW_PEER_CANDIDATE events. The mesh beacon is
+ * still generated by the driver.
*/
enum nl80211_feature_flags {
- NL80211_FEATURE_SK_TX_STATUS = 1 << 0,
- NL80211_FEATURE_HT_IBSS = 1 << 1,
- NL80211_FEATURE_INACTIVITY_TIMER = 1 << 2,
- NL80211_FEATURE_CELL_BASE_REG_HINTS = 1 << 3,
+ NL80211_FEATURE_SK_TX_STATUS = 1 << 0,
+ NL80211_FEATURE_HT_IBSS = 1 << 1,
+ NL80211_FEATURE_INACTIVITY_TIMER = 1 << 2,
+ NL80211_FEATURE_CELL_BASE_REG_HINTS = 1 << 3,
+ NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL = 1 << 4,
+ NL80211_FEATURE_SAE = 1 << 5,
+ NL80211_FEATURE_LOW_PRIORITY_SCAN = 1 << 6,
+ NL80211_FEATURE_SCAN_FLUSH = 1 << 7,
+ NL80211_FEATURE_AP_SCAN = 1 << 8,
+ NL80211_FEATURE_VIF_TXPOWER = 1 << 9,
+ NL80211_FEATURE_NEED_OBSS_SCAN = 1 << 10,
+ NL80211_FEATURE_P2P_GO_CTWIN = 1 << 11,
+ NL80211_FEATURE_P2P_GO_OPPPS = 1 << 12,
+ /* bit 13 is reserved */
+ NL80211_FEATURE_ADVERTISE_CHAN_LIMITS = 1 << 14,
+ NL80211_FEATURE_FULL_AP_CLIENT_STATE = 1 << 15,
+ NL80211_FEATURE_USERSPACE_MPM = 1 << 16,
};
/**
@@ -3023,4 +3580,106 @@
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U = 1<<3,
};
+/**
+ * enum nl80211_connect_failed_reason - connection request failed reasons
+ * @NL80211_CONN_FAIL_MAX_CLIENTS: Maximum number of clients that can be
+ * handled by the AP is reached.
+ * @NL80211_CONN_FAIL_BLOCKED_CLIENT: Connection request is rejected due to ACL.
+ */
+enum nl80211_connect_failed_reason {
+ NL80211_CONN_FAIL_MAX_CLIENTS,
+ NL80211_CONN_FAIL_BLOCKED_CLIENT,
+};
+
+/**
+ * enum nl80211_scan_flags - scan request control flags
+ *
+ * Scan request control flags are used to control the handling
+ * of NL80211_CMD_TRIGGER_SCAN and NL80211_CMD_START_SCHED_SCAN
+ * requests.
+ *
+ * @NL80211_SCAN_FLAG_LOW_PRIORITY: scan request has low priority
+ * @NL80211_SCAN_FLAG_FLUSH: flush cache before scanning
+ * @NL80211_SCAN_FLAG_AP: force a scan even if the interface is configured
+ * as AP and the beaconing has already been configured. This attribute is
+ * 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
+ */
+enum nl80211_scan_flags {
+ NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0,
+ NL80211_SCAN_FLAG_FLUSH = 1<<1,
+ NL80211_SCAN_FLAG_AP = 1<<2,
+};
+
+/**
+ * enum nl80211_acl_policy - access control policy
+ *
+ * Access control policy is applied on a MAC list set by
+ * %NL80211_CMD_START_AP and %NL80211_CMD_SET_MAC_ACL, to
+ * be used with %NL80211_ATTR_ACL_POLICY.
+ *
+ * @NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED: Deny stations which are
+ * listed in ACL, i.e. allow all the stations which are not listed
+ * in ACL to authenticate.
+ * @NL80211_ACL_POLICY_DENY_UNLESS_LISTED: Allow the stations which are listed
+ * in ACL, i.e. deny all the stations which are not listed in ACL.
+ */
+enum nl80211_acl_policy {
+ NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED,
+ NL80211_ACL_POLICY_DENY_UNLESS_LISTED,
+};
+
+/**
+ * enum nl80211_radar_event - type of radar event for DFS operation
+ *
+ * Type of event to be used with NL80211_ATTR_RADAR_EVENT to inform userspace
+ * about detected radars or success of the channel available check (CAC)
+ *
+ * @NL80211_RADAR_DETECTED: A radar pattern has been detected. The channel is
+ * now unusable.
+ * @NL80211_RADAR_CAC_FINISHED: Channel Availability Check has been finished,
+ * the channel is now available.
+ * @NL80211_RADAR_CAC_ABORTED: Channel Availability Check has been aborted, no
+ * change to the channel status.
+ * @NL80211_RADAR_NOP_FINISHED: The Non-Occupancy Period for this channel is
+ * over, channel becomes usable.
+ */
+enum nl80211_radar_event {
+ NL80211_RADAR_DETECTED,
+ NL80211_RADAR_CAC_FINISHED,
+ NL80211_RADAR_CAC_ABORTED,
+ NL80211_RADAR_NOP_FINISHED,
+};
+
+/**
+ * enum nl80211_dfs_state - DFS states for channels
+ *
+ * Channel states used by the DFS code.
+ *
+ * @IEEE80211_DFS_USABLE: The channel can be used, but channel availability
+ * check (CAC) must be performed before using it for AP or IBSS.
+ * @IEEE80211_DFS_UNAVAILABLE: A radar has been detected on this channel, it
+ * is therefore marked as not available.
+ * @IEEE80211_DFS_AVAILABLE: The channel has been CAC checked and is available.
+ */
+
+enum nl80211_dfs_state {
+ NL80211_DFS_USABLE,
+ NL80211_DFS_UNAVAILABLE,
+ NL80211_DFS_AVAILABLE,
+};
+
+/**
+ * enum enum nl80211_protocol_features - nl80211 protocol features
+ * @NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP: nl80211 supports splitting
+ * wiphy dumps (if requested by the application with the attribute
+ * %NL80211_ATTR_SPLIT_WIPHY_DUMP. Also supported is filtering the
+ * wiphy dump by %NL80211_ATTR_WIPHY, %NL80211_ATTR_IFINDEX or
+ * %NL80211_ATTR_WDEV.
+ */
+enum nl80211_protocol_features {
+ NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP = 1 << 0,
+};
+
#endif /* __LINUX_NL80211_H */
diff --git a/src/eap_common/eap_gpsk_common.c b/src/eap_common/eap_gpsk_common.c
index 7d106dd..7a33215 100644
--- a/src/eap_common/eap_gpsk_common.c
+++ b/src/eap_common/eap_gpsk_common.c
@@ -340,6 +340,141 @@
}
+static int eap_gpsk_derive_mid_helper(u32 csuite_specifier,
+ u8 *kdf_out, size_t kdf_out_len,
+ const u8 *psk, const u8 *seed,
+ size_t seed_len, u8 method_type)
+{
+ u8 *pos, *data;
+ size_t data_len;
+ int (*gkdf)(const u8 *_psk, const u8 *_data, size_t _data_len,
+ u8 *buf, size_t len);
+
+ gkdf = NULL;
+ switch (csuite_specifier) {
+ case EAP_GPSK_CIPHER_AES:
+ gkdf = eap_gpsk_gkdf_cmac;
+ break;
+#ifdef EAP_GPSK_SHA256
+ case EAP_GPSK_CIPHER_SHA256:
+ gkdf = eap_gpsk_gkdf_sha256;
+ break;
+#endif /* EAP_GPSK_SHA256 */
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown cipher %d used in "
+ "Session-Id derivation", csuite_specifier);
+ return -1;
+ }
+
+#define SID_LABEL "Method ID"
+ /* "Method ID" || EAP_Method_Type || CSuite_Sel || inputString */
+ data_len = strlen(SID_LABEL) + 1 + 6 + seed_len;
+ data = os_malloc(data_len);
+ if (data == NULL)
+ return -1;
+ pos = data;
+ os_memcpy(pos, SID_LABEL, strlen(SID_LABEL));
+ pos += strlen(SID_LABEL);
+#undef SID_LABEL
+ os_memcpy(pos, &method_type, 1);
+ pos += 1;
+ WPA_PUT_BE32(pos, EAP_GPSK_VENDOR_IETF); /* CSuite/Vendor = IETF */
+ pos += 4;
+ WPA_PUT_BE16(pos, csuite_specifier); /* CSuite/Specifier */
+ pos += 2;
+ os_memcpy(pos, seed, seed_len); /* inputString */
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Data to Method ID derivation",
+ data, data_len);
+
+ if (gkdf(psk, data, data_len, kdf_out, kdf_out_len) < 0) {
+ os_free(data);
+ return -1;
+ }
+ os_free(data);
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Method ID", kdf_out, kdf_out_len);
+
+ return 0;
+}
+
+
+/**
+ * eap_gpsk_session_id - Derive EAP-GPSK Session ID
+ * @psk: Pre-shared key
+ * @psk_len: Length of psk in bytes
+ * @vendor: CSuite/Vendor
+ * @specifier: CSuite/Specifier
+ * @rand_peer: 32-byte RAND_Peer
+ * @rand_server: 32-byte RAND_Server
+ * @id_peer: ID_Peer
+ * @id_peer_len: Length of ID_Peer
+ * @id_server: ID_Server
+ * @id_server_len: Length of ID_Server
+ * @method_type: EAP Authentication Method Type
+ * @sid: Buffer for 17-byte Session ID
+ * @sid_len: Buffer for returning length of Session ID
+ * Returns: 0 on success, -1 on failure
+ */
+int eap_gpsk_derive_session_id(const u8 *psk, size_t psk_len, int vendor,
+ int specifier,
+ const u8 *rand_peer, const u8 *rand_server,
+ const u8 *id_peer, size_t id_peer_len,
+ const u8 *id_server, size_t id_server_len,
+ u8 method_type, u8 *sid, size_t *sid_len)
+{
+ u8 *seed, *pos;
+ u8 kdf_out[16];
+ size_t seed_len;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Deriving Session ID(%d:%d)",
+ vendor, specifier);
+
+ if (vendor != EAP_GPSK_VENDOR_IETF)
+ return -1;
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PSK", psk, psk_len);
+
+ /*
+ * inputString = RAND_Peer || ID_Peer || RAND_Server || ID_Server
+ * (= seed)
+ * KS = 16, CSuite_Sel = 0x00000000 0x0001
+ * Method-ID = GKDF-16 (zero, "Method ID" || EAP_Method_Type ||
+ * CSuite_Sel || inputString)
+ */
+ seed_len = 2 * EAP_GPSK_RAND_LEN + id_server_len + id_peer_len;
+ seed = os_malloc(seed_len);
+ if (seed == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to allocate memory "
+ "for Session-Id derivation");
+ return -1;
+ }
+
+ pos = seed;
+ os_memcpy(pos, rand_peer, EAP_GPSK_RAND_LEN);
+ pos += EAP_GPSK_RAND_LEN;
+ os_memcpy(pos, id_peer, id_peer_len);
+ pos += id_peer_len;
+ os_memcpy(pos, rand_server, EAP_GPSK_RAND_LEN);
+ pos += EAP_GPSK_RAND_LEN;
+ os_memcpy(pos, id_server, id_server_len);
+ pos += id_server_len;
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Seed", seed, seed_len);
+
+ ret = eap_gpsk_derive_mid_helper(specifier,
+ kdf_out, sizeof(kdf_out),
+ psk, seed, seed_len,
+ method_type);
+
+ sid[0] = method_type;
+ os_memcpy(sid + 1, kdf_out, sizeof(kdf_out));
+ *sid_len = 1 + sizeof(kdf_out);
+
+ os_free(seed);
+
+ return ret;
+}
+
+
/**
* eap_gpsk_mic_len - Get the length of the MIC
* @vendor: CSuite/Vendor
diff --git a/src/eap_common/eap_gpsk_common.h b/src/eap_common/eap_gpsk_common.h
index e3d2b6b..fbcd547 100644
--- a/src/eap_common/eap_gpsk_common.h
+++ b/src/eap_common/eap_gpsk_common.h
@@ -53,6 +53,12 @@
const u8 *id_server, size_t id_server_len,
u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len,
u8 *pk, size_t *pk_len);
+int eap_gpsk_derive_session_id(const u8 *psk, size_t psk_len, int vendor,
+ int specifier,
+ const u8 *rand_peer, const u8 *rand_server,
+ const u8 *id_peer, size_t id_peer_len,
+ const u8 *id_server, size_t id_server_len,
+ u8 method_type, u8 *sid, size_t *sid_len);
size_t eap_gpsk_mic_len(int vendor, int specifier);
int eap_gpsk_compute_mic(const u8 *sk, size_t sk_len, int vendor,
int specifier, const u8 *data, size_t len, u8 *mic);
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index a4c9b25..4df8853 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -161,6 +161,8 @@
eapol_set_bool(sm, EAPOL_eapFail, FALSE);
os_free(sm->eapKeyData);
sm->eapKeyData = NULL;
+ os_free(sm->eapSessionId);
+ sm->eapSessionId = NULL;
sm->eapKeyAvailable = FALSE;
eapol_set_bool(sm, EAPOL_eapRestart, FALSE);
sm->lastId = -1; /* new session - make sure this does not match with
@@ -403,6 +405,13 @@
os_free(sm->eapKeyData);
sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv,
&sm->eapKeyDataLen);
+ os_free(sm->eapSessionId);
+ sm->eapSessionId = sm->m->getSessionId(sm, sm->eap_method_priv,
+ &sm->eapSessionIdLen);
+ if (sm->eapSessionId) {
+ wpa_hexdump(MSG_DEBUG, "EAP: Session-Id",
+ sm->eapSessionId, sm->eapSessionIdLen);
+ }
}
}
@@ -891,6 +900,7 @@
wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED
"EAP authentication started");
+ eap_notify_status(sm, "started", "");
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, req,
&msg_len);
@@ -1461,6 +1471,8 @@
sm->eapRespData = NULL;
os_free(sm->eapKeyData);
sm->eapKeyData = NULL;
+ os_free(sm->eapSessionId);
+ sm->eapSessionId = NULL;
/* This is not clearly specified in the EAP statemachines draft, but
* it seems necessary to make sure that some of the EAPOL variables get
@@ -2158,6 +2170,28 @@
/**
+ * eap_get_eapSessionId - Get Session-Id from EAP state machine
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @len: Pointer to variable that will be set to number of bytes in the session
+ * Returns: Pointer to the EAP Session-Id or %NULL on failure
+ *
+ * Fetch EAP Session-Id from the EAP state machine. The Session-Id is available
+ * only after a successful authentication. EAP state machine continues to manage
+ * the Session-Id and the caller must not change or free the returned data.
+ */
+const u8 * eap_get_eapSessionId(struct eap_sm *sm, size_t *len)
+{
+ if (sm == NULL || sm->eapSessionId == NULL) {
+ *len = 0;
+ return NULL;
+ }
+
+ *len = sm->eapSessionIdLen;
+ return sm->eapSessionId;
+}
+
+
+/**
* eap_get_eapKeyData - Get master session key (MSK) from EAP state machine
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
* @len: Pointer to variable that will be set to number of bytes in the key
diff --git a/src/eap_peer/eap.h b/src/eap_peer/eap.h
index 8bccef1..f87f9b3 100644
--- a/src/eap_peer/eap.h
+++ b/src/eap_peer/eap.h
@@ -306,6 +306,7 @@
int eap_key_available(struct eap_sm *sm);
void eap_notify_success(struct eap_sm *sm);
void eap_notify_lower_layer_success(struct eap_sm *sm);
+const u8 * eap_get_eapSessionId(struct eap_sm *sm, size_t *len);
const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len);
struct wpabuf * eap_get_eapRespData(struct eap_sm *sm);
void eap_register_scard_ctx(struct eap_sm *sm, void *ctx);
diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c
index 59861cb..dc424d7 100644
--- a/src/eap_peer/eap_aka.c
+++ b/src/eap_peer/eap_aka.c
@@ -1340,6 +1340,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;
+}
+
+
static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_aka_data *data = priv;
@@ -1374,6 +1396,7 @@
eap->process = eap_aka_process;
eap->isKeyAvailable = eap_aka_isKeyAvailable;
eap->getKey = eap_aka_getKey;
+ eap->getSessionId = eap_aka_get_session_id;
eap->has_reauth_data = eap_aka_has_reauth_data;
eap->deinit_for_reauth = eap_aka_deinit_for_reauth;
eap->init_for_reauth = eap_aka_init_for_reauth;
@@ -1404,6 +1427,7 @@
eap->process = eap_aka_process;
eap->isKeyAvailable = eap_aka_isKeyAvailable;
eap->getKey = eap_aka_getKey;
+ eap->getSessionId = eap_aka_get_session_id;
eap->has_reauth_data = eap_aka_has_reauth_data;
eap->deinit_for_reauth = eap_aka_deinit_for_reauth;
eap->init_for_reauth = eap_aka_init_for_reauth;
diff --git a/src/eap_peer/eap_fast.c b/src/eap_peer/eap_fast.c
index 7ca5288..3b8d803 100644
--- a/src/eap_peer/eap_fast.c
+++ b/src/eap_peer/eap_fast.c
@@ -53,6 +53,8 @@
int session_ticket_used;
u8 key_data[EAP_FAST_KEY_LEN];
+ u8 *session_id;
+ size_t id_len;
u8 emsk[EAP_EMSK_LEN];
int success;
@@ -238,6 +240,7 @@
pac = pac->next;
eap_fast_free_pac(prev);
}
+ os_free(data->session_id);
wpabuf_free(data->pending_phase2_req);
os_free(data);
}
@@ -785,6 +788,21 @@
return NULL;
}
+ if (!data->anon_provisioning && data->phase2_success) {
+ os_free(data->session_id);
+ data->session_id = eap_peer_tls_derive_session_id(
+ sm, &data->ssl, EAP_TYPE_FAST, &data->id_len);
+ if (data->session_id) {
+ wpa_hexdump(MSG_DEBUG, "EAP-FAST: Derived Session-Id",
+ data->session_id, data->id_len);
+ } else {
+ wpa_printf(MSG_ERROR, "EAP-FAST: Failed to derive "
+ "Session-Id");
+ wpabuf_free(resp);
+ return NULL;
+ }
+ }
+
pos = wpabuf_put(resp, sizeof(struct eap_tlv_crypto_binding_tlv));
eap_fast_write_crypto_binding((struct eap_tlv_crypto_binding_tlv *)
pos, _bind, cmk);
@@ -1604,6 +1622,8 @@
os_free(data);
return NULL;
}
+ os_free(data->session_id);
+ data->session_id = NULL;
if (data->phase2_priv && data->phase2_method &&
data->phase2_method->init_for_reauth)
data->phase2_method->init_for_reauth(sm, data->phase2_priv);
@@ -1662,6 +1682,25 @@
}
+static u8 * eap_fast_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_fast_data *data = priv;
+ u8 *id;
+
+ if (!data->success)
+ return NULL;
+
+ id = os_malloc(data->id_len);
+ if (id == NULL)
+ return NULL;
+
+ *len = data->id_len;
+ os_memcpy(id, data->session_id, data->id_len);
+
+ return id;
+}
+
+
static u8 * eap_fast_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_fast_data *data = priv;
@@ -1696,6 +1735,7 @@
eap->process = eap_fast_process;
eap->isKeyAvailable = eap_fast_isKeyAvailable;
eap->getKey = eap_fast_getKey;
+ eap->getSessionId = eap_fast_get_session_id;
eap->get_status = eap_fast_get_status;
#if 0
eap->has_reauth_data = eap_fast_has_reauth_data;
diff --git a/src/eap_peer/eap_fast_pac.c b/src/eap_peer/eap_fast_pac.c
index fc987da..8c480b9 100644
--- a/src/eap_peer/eap_fast_pac.c
+++ b/src/eap_peer/eap_fast_pac.c
@@ -422,8 +422,12 @@
if (eap_fast_init_pac_data(sm, pac_file, &rc) < 0)
return 0;
- if (eap_fast_read_line(&rc, &pos) < 0 ||
- os_strcmp(pac_file_hdr, rc.buf) != 0)
+ if (eap_fast_read_line(&rc, &pos) < 0) {
+ /* empty file - assume it is fine to overwrite */
+ eap_fast_deinit_pac_data(&rc);
+ return 0;
+ }
+ if (os_strcmp(pac_file_hdr, rc.buf) != 0)
err = "Unrecognized header line";
while (!err && eap_fast_read_line(&rc, &pos) == 0) {
diff --git a/src/eap_peer/eap_gpsk.c b/src/eap_peer/eap_gpsk.c
index 2bd0d48..8a0644d 100644
--- a/src/eap_peer/eap_gpsk.c
+++ b/src/eap_peer/eap_gpsk.c
@@ -23,8 +23,8 @@
size_t sk_len;
u8 pk[EAP_GPSK_MAX_PK_LEN];
size_t pk_len;
- u8 session_id;
- int session_id_set;
+ u8 session_id[128];
+ size_t id_len;
u8 *id_peer;
size_t id_peer_len;
u8 *id_server;
@@ -354,6 +354,21 @@
return NULL;
}
+ if (eap_gpsk_derive_session_id(data->psk, data->psk_len,
+ data->vendor, data->specifier,
+ data->rand_peer, data->rand_server,
+ data->id_peer, data->id_peer_len,
+ data->id_server, data->id_server_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);
+ wpabuf_free(resp);
+ return NULL;
+ }
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Derived Session-Id",
+ data->session_id, data->id_len);
+
/* No PD_Payload_1 */
wpabuf_put_be16(resp, 0);
@@ -708,6 +723,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_peer_gpsk_register(void)
{
struct eap_method *eap;
@@ -724,6 +757,7 @@
eap->isKeyAvailable = eap_gpsk_isKeyAvailable;
eap->getKey = eap_gpsk_getKey;
eap->get_emsk = eap_gpsk_get_emsk;
+ eap->getSessionId = eap_gpsk_get_session_id;
ret = eap_peer_method_register(eap);
if (ret)
diff --git a/src/eap_peer/eap_i.h b/src/eap_peer/eap_i.h
index dd94317..62c867c 100644
--- a/src/eap_peer/eap_i.h
+++ b/src/eap_peer/eap_i.h
@@ -261,6 +261,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_peer_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);
};
@@ -298,6 +311,8 @@
Boolean eapKeyAvailable; /* peer to lower layer */
u8 *eapKeyData; /* peer to lower layer */
size_t eapKeyDataLen; /* peer to lower layer */
+ u8 *eapSessionId; /* peer to lower layer */
+ size_t eapSessionIdLen; /* peer to lower layer */
const struct eap_method *m; /* selected EAP method */
/* not defined in RFC 4137 */
Boolean changed;
diff --git a/src/eap_peer/eap_ikev2.c b/src/eap_peer/eap_ikev2.c
index a227f8b..09a655e 100644
--- a/src/eap_peer/eap_ikev2.c
+++ b/src/eap_peer/eap_ikev2.c
@@ -475,6 +475,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_peer_ikev2_register(void)
{
struct eap_method *eap;
@@ -492,6 +522,7 @@
eap->isKeyAvailable = eap_ikev2_isKeyAvailable;
eap->getKey = eap_ikev2_getKey;
eap->get_emsk = eap_ikev2_get_emsk;
+ eap->getSessionId = eap_ikev2_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 7fff145..3b93209 100644
--- a/src/eap_peer/eap_peap.c
+++ b/src/eap_peer/eap_peap.c
@@ -56,6 +56,8 @@
int resuming; /* starting a resumed session */
int reauth; /* reauthentication */
u8 *key_data;
+ u8 *session_id;
+ size_t id_len;
struct wpabuf *pending_phase2_req;
enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;
@@ -179,6 +181,7 @@
os_free(data->phase2_types);
eap_peer_tls_ssl_deinit(sm, &data->ssl);
os_free(data->key_data);
+ os_free(data->session_id);
wpabuf_free(data->pending_phase2_req);
os_free(data);
}
@@ -1107,6 +1110,20 @@
"derive key");
}
+ os_free(data->session_id);
+ data->session_id =
+ eap_peer_tls_derive_session_id(sm, &data->ssl,
+ EAP_TYPE_PEAP,
+ &data->id_len);
+ if (data->session_id) {
+ wpa_hexdump(MSG_DEBUG,
+ "EAP-PEAP: Derived Session-Id",
+ data->session_id, data->id_len);
+ } else {
+ wpa_printf(MSG_ERROR, "EAP-PEAP: Failed to "
+ "derive Session-Id");
+ }
+
if (sm->workaround && data->resuming) {
/*
* At least few RADIUS servers (Aegis v1.1.6;
@@ -1178,6 +1195,8 @@
struct eap_peap_data *data = priv;
os_free(data->key_data);
data->key_data = NULL;
+ os_free(data->session_id);
+ data->session_id = NULL;
if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
os_free(data);
return NULL;
@@ -1260,6 +1279,25 @@
}
+static u8 * eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_peap_data *data = priv;
+ u8 *id;
+
+ if (data->session_id == NULL || !data->phase2_success)
+ return NULL;
+
+ id = os_malloc(data->id_len);
+ if (id == NULL)
+ return NULL;
+
+ *len = data->id_len;
+ os_memcpy(id, data->session_id, data->id_len);
+
+ return id;
+}
+
+
int eap_peer_peap_register(void)
{
struct eap_method *eap;
@@ -1279,6 +1317,7 @@
eap->has_reauth_data = eap_peap_has_reauth_data;
eap->deinit_for_reauth = eap_peap_deinit_for_reauth;
eap->init_for_reauth = eap_peap_init_for_reauth;
+ eap->getSessionId = eap_peap_get_session_id;
ret = eap_peer_method_register(eap);
if (ret)
diff --git a/src/eap_peer/eap_proxy.h b/src/eap_peer/eap_proxy.h
new file mode 100644
index 0000000..3b4dcef
--- /dev/null
+++ b/src/eap_peer/eap_proxy.h
@@ -0,0 +1,48 @@
+/*
+ * EAP proxy definitions
+ * Copyright (c) 2011-2013 Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_PROXY_H
+#define EAP_PROXY_H
+
+struct eap_proxy_sm;
+struct eapol_callbacks;
+struct eap_sm;
+struct eap_peer_config;
+
+enum eap_proxy_status {
+ EAP_PROXY_FAILURE = 0x00,
+ EAP_PROXY_SUCCESS
+};
+
+struct eap_proxy_sm *
+eap_proxy_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
+ void *msg_ctx);
+
+void eap_proxy_deinit(struct eap_proxy_sm *eap_proxy);
+
+int eap_proxy_key_available(struct eap_proxy_sm *sm);
+
+const u8 * eap_proxy_get_eapKeyData(struct eap_proxy_sm *sm, size_t *len);
+
+struct wpabuf * eap_proxy_get_eapRespData(struct eap_proxy_sm *sm);
+
+int eap_proxy_sm_step(struct eap_proxy_sm *sm, struct eap_sm *eap_sm);
+
+enum eap_proxy_status
+eap_proxy_packet_update(struct eap_proxy_sm *eap_proxy, u8 *eapReqData,
+ int eapReqDataLen);
+
+int eap_proxy_sm_get_status(struct eap_proxy_sm *sm, char *buf, size_t buflen,
+ int verbose);
+
+int eap_proxy_get_imsi(char *imsi_buf, size_t *imsi_len);
+
+int eap_proxy_notify_config(struct eap_proxy_sm *sm,
+ struct eap_peer_config *config);
+
+#endif /* EAP_PROXY_H */
diff --git a/src/eap_peer/eap_proxy_dummy.c b/src/eap_peer/eap_proxy_dummy.c
new file mode 100644
index 0000000..cd97fb6
--- /dev/null
+++ b/src/eap_peer/eap_proxy_dummy.c
@@ -0,0 +1,76 @@
+/*
+ * EAP proxy - dummy implementation for build testing
+ * Copyright (c) 2013 Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eap_proxy.h"
+
+struct eap_proxy_sm *
+eap_proxy_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
+ void *msg_ctx)
+{
+ return NULL;
+}
+
+
+void eap_proxy_deinit(struct eap_proxy_sm *eap_proxy)
+{
+}
+
+
+int eap_proxy_key_available(struct eap_proxy_sm *sm)
+{
+ return 0;
+}
+
+
+const u8 * eap_proxy_get_eapKeyData(struct eap_proxy_sm *sm, size_t *len)
+{
+ return NULL;
+}
+
+
+struct wpabuf * eap_proxy_get_eapRespData(struct eap_proxy_sm *sm)
+{
+ return NULL;
+}
+
+
+int eap_proxy_sm_step(struct eap_proxy_sm *sm, struct eap_sm *eap_sm)
+{
+ return 0;
+}
+
+
+enum eap_proxy_status
+eap_proxy_packet_update(struct eap_proxy_sm *eap_proxy, u8 *eapReqData,
+ int eapReqDataLen)
+{
+ return EAP_PROXY_FAILURE;
+}
+
+
+int eap_proxy_sm_get_status(struct eap_proxy_sm *sm, char *buf, size_t buflen,
+ int verbose)
+{
+ return 0;
+}
+
+
+int eap_proxy_get_imsi(char *imsi_buf, size_t *imsi_len)
+{
+ return -1;
+}
+
+
+int eap_proxy_notify_config(struct eap_proxy_sm *sm,
+ struct eap_peer_config *config)
+{
+ return -1;
+}
diff --git a/src/eap_peer/eap_psk.c b/src/eap_peer/eap_psk.c
index d618fcf..cd0e3f9 100644
--- a/src/eap_peer/eap_psk.c
+++ b/src/eap_peer/eap_psk.c
@@ -21,6 +21,7 @@
struct eap_psk_data {
enum { PSK_INIT, PSK_MAC_SENT, PSK_DONE } state;
u8 rand_p[EAP_PSK_RAND_LEN];
+ u8 rand_s[EAP_PSK_RAND_LEN];
u8 ak[EAP_PSK_AK_LEN], kdk[EAP_PSK_KDK_LEN], tek[EAP_PSK_TEK_LEN];
u8 *id_s, *id_p;
size_t id_s_len, id_p_len;
@@ -112,6 +113,7 @@
}
wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr1->rand_s,
EAP_PSK_RAND_LEN);
+ os_memcpy(data->rand_s, hdr1->rand_s, EAP_PSK_RAND_LEN);
os_free(data->id_s);
data->id_s_len = len - sizeof(*hdr1);
data->id_s = os_malloc(data->id_s_len);
@@ -434,6 +436,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 != PSK_DONE)
+ 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;
+}
+
+
static u8 * eap_psk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_psk_data *data = priv;
@@ -468,6 +492,7 @@
eap->process = eap_psk_process;
eap->isKeyAvailable = eap_psk_isKeyAvailable;
eap->getKey = eap_psk_getKey;
+ eap->getSessionId = eap_psk_get_session_id;
eap->get_emsk = eap_psk_get_emsk;
ret = eap_peer_method_register(eap);
diff --git a/src/eap_peer/eap_sake.c b/src/eap_peer/eap_sake.c
index e072f46..431519c 100644
--- a/src/eap_peer/eap_sake.c
+++ b/src/eap_peer/eap_sake.c
@@ -452,6 +452,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;
+}
+
+
static u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_sake_data *data = priv;
@@ -485,6 +507,7 @@
eap->process = eap_sake_process;
eap->isKeyAvailable = eap_sake_isKeyAvailable;
eap->getKey = eap_sake_getKey;
+ eap->getSessionId = eap_sake_get_session_id;
eap->get_emsk = eap_sake_get_emsk;
ret = eap_peer_method_register(eap);
diff --git a/src/eap_peer/eap_sim.c b/src/eap_peer/eap_sim.c
index c936a44..82ea18d 100644
--- a/src/eap_peer/eap_sim.c
+++ b/src/eap_peer/eap_sim.c
@@ -1084,6 +1084,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;
+}
+
+
static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_sim_data *data = priv;
@@ -1118,6 +1141,7 @@
eap->process = eap_sim_process;
eap->isKeyAvailable = eap_sim_isKeyAvailable;
eap->getKey = eap_sim_getKey;
+ eap->getSessionId = eap_sim_get_session_id;
eap->has_reauth_data = eap_sim_has_reauth_data;
eap->deinit_for_reauth = eap_sim_deinit_for_reauth;
eap->init_for_reauth = eap_sim_init_for_reauth;
diff --git a/src/eap_peer/eap_tls.c b/src/eap_peer/eap_tls.c
index 061a72b..d2066cd 100644
--- a/src/eap_peer/eap_tls.c
+++ b/src/eap_peer/eap_tls.c
@@ -21,6 +21,8 @@
struct eap_tls_data {
struct eap_ssl_data ssl;
u8 *key_data;
+ u8 *session_id;
+ size_t id_len;
void *ssl_ctx;
u8 eap_type;
};
@@ -103,6 +105,7 @@
return;
eap_peer_tls_ssl_deinit(sm, &data->ssl);
os_free(data->key_data);
+ os_free(data->session_id);
os_free(data);
}
@@ -165,6 +168,17 @@
} else {
wpa_printf(MSG_INFO, "EAP-TLS: Failed to derive key");
}
+
+ os_free(data->session_id);
+ data->session_id = eap_peer_tls_derive_session_id(sm, &data->ssl,
+ EAP_TYPE_TLS,
+ &data->id_len);
+ if (data->session_id) {
+ wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived Session-Id",
+ data->session_id, data->id_len);
+ } else {
+ wpa_printf(MSG_ERROR, "EAP-TLS: Failed to derive Session-Id");
+ }
}
@@ -228,6 +242,8 @@
struct eap_tls_data *data = priv;
os_free(data->key_data);
data->key_data = NULL;
+ os_free(data->session_id);
+ data->session_id = NULL;
if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
os_free(data);
return NULL;
@@ -289,6 +305,25 @@
}
+static u8 * eap_tls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_tls_data *data = priv;
+ u8 *id;
+
+ if (data->session_id == NULL)
+ return NULL;
+
+ id = os_malloc(data->id_len);
+ if (id == NULL)
+ return NULL;
+
+ *len = data->id_len;
+ os_memcpy(id, data->session_id, data->id_len);
+
+ return id;
+}
+
+
int eap_peer_tls_register(void)
{
struct eap_method *eap;
@@ -304,6 +339,7 @@
eap->process = eap_tls_process;
eap->isKeyAvailable = eap_tls_isKeyAvailable;
eap->getKey = eap_tls_getKey;
+ eap->getSessionId = eap_tls_get_session_id;
eap->get_status = eap_tls_get_status;
eap->has_reauth_data = eap_tls_has_reauth_data;
eap->deinit_for_reauth = eap_tls_deinit_for_reauth;
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index 7eefe8c..a777bb0 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -340,6 +340,52 @@
/**
+ * eap_peer_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_peer_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;
+
+ /*
+ * 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)
+ 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;
+}
+
+
+/**
* eap_peer_tls_reassemble_fragment - Reassemble a received fragment
* @data: Data for TLS processing
* @in_data: Next incoming TLS segment
@@ -829,6 +875,14 @@
}
pos += 4;
left -= 4;
+
+ if (left > tls_msg_len) {
+ wpa_printf(MSG_INFO, "SSL: TLS Message Length (%d "
+ "bytes) smaller than this fragment (%d "
+ "bytes)", (int) tls_msg_len, (int) left);
+ ret->ignore = TRUE;
+ return NULL;
+ }
}
ret->ignore = FALSE;
diff --git a/src/eap_peer/eap_tls_common.h b/src/eap_peer/eap_tls_common.h
index 91d3a25..1a5e0f8 100644
--- a/src/eap_peer/eap_tls_common.h
+++ b/src/eap_peer/eap_tls_common.h
@@ -94,6 +94,9 @@
void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data);
u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
const char *label, size_t len);
+u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm,
+ struct eap_ssl_data *data, u8 eap_type,
+ size_t *len);
int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
EapType eap_type, int peap_version,
u8 id, const u8 *in_data, size_t in_len,
diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c
index 9360a42..5091bf0 100644
--- a/src/eap_peer/eap_ttls.c
+++ b/src/eap_peer/eap_ttls.c
@@ -54,6 +54,8 @@
int resuming; /* starting a resumed session */
int reauth; /* reauthentication */
u8 *key_data;
+ u8 *session_id;
+ size_t id_len;
struct wpabuf *pending_phase2_req;
@@ -140,6 +142,7 @@
os_free(data->phase2_eap_types);
eap_peer_tls_ssl_deinit(sm, &data->ssl);
os_free(data->key_data);
+ os_free(data->session_id);
wpabuf_free(data->pending_phase2_req);
os_free(data);
}
@@ -222,6 +225,17 @@
wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key",
data->key_data, EAP_TLS_KEY_LEN);
+ os_free(data->session_id);
+ data->session_id = eap_peer_tls_derive_session_id(sm, &data->ssl,
+ EAP_TYPE_TTLS,
+ &data->id_len);
+ if (data->session_id) {
+ wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Derived Session-Id",
+ data->session_id, data->id_len);
+ } else {
+ wpa_printf(MSG_ERROR, "EAP-TTLS: Failed to derive Session-Id");
+ }
+
return 0;
}
@@ -1528,6 +1542,8 @@
struct eap_ttls_data *data = priv;
os_free(data->key_data);
data->key_data = NULL;
+ os_free(data->session_id);
+ data->session_id = NULL;
if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
os_free(data);
return NULL;
@@ -1612,6 +1628,25 @@
}
+static u8 * eap_ttls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_ttls_data *data = priv;
+ u8 *id;
+
+ if (data->session_id == NULL || !data->phase2_success)
+ return NULL;
+
+ id = os_malloc(data->id_len);
+ if (id == NULL)
+ return NULL;
+
+ *len = data->id_len;
+ os_memcpy(id, data->session_id, data->id_len);
+
+ return id;
+}
+
+
int eap_peer_ttls_register(void)
{
struct eap_method *eap;
@@ -1627,6 +1662,7 @@
eap->process = eap_ttls_process;
eap->isKeyAvailable = eap_ttls_isKeyAvailable;
eap->getKey = eap_ttls_getKey;
+ eap->getSessionId = eap_ttls_get_session_id;
eap->get_status = eap_ttls_get_status;
eap->has_reauth_data = eap_ttls_has_reauth_data;
eap->deinit_for_reauth = eap_ttls_deinit_for_reauth;
diff --git a/src/eap_peer/eap_wsc.c b/src/eap_peer/eap_wsc.c
index d007a57..8edb1ca 100644
--- a/src/eap_peer/eap_wsc.c
+++ b/src/eap_peer/eap_wsc.c
@@ -77,25 +77,33 @@
else
len = end - pos;
if ((len & 1) || len > 2 * sizeof(cred->ssid) ||
- hexstr2bin(pos, cred->ssid, len / 2))
+ hexstr2bin(pos, cred->ssid, len / 2)) {
+ wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid new_ssid");
return -1;
+ }
cred->ssid_len = len / 2;
pos = os_strstr(params, "new_auth=");
- if (pos == NULL)
+ if (pos == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-WSC: Missing new_auth");
return -1;
+ }
if (os_strncmp(pos + 9, "OPEN", 4) == 0)
cred->auth_type = WPS_AUTH_OPEN;
else if (os_strncmp(pos + 9, "WPAPSK", 6) == 0)
cred->auth_type = WPS_AUTH_WPAPSK;
else if (os_strncmp(pos + 9, "WPA2PSK", 7) == 0)
cred->auth_type = WPS_AUTH_WPA2PSK;
- else
+ else {
+ wpa_printf(MSG_DEBUG, "EAP-WSC: Unknown new_auth");
return -1;
+ }
pos = os_strstr(params, "new_encr=");
- if (pos == NULL)
+ if (pos == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-WSC: Missing new_encr");
return -1;
+ }
if (os_strncmp(pos + 9, "NONE", 4) == 0)
cred->encr_type = WPS_ENCR_NONE;
else if (os_strncmp(pos + 9, "WEP", 3) == 0)
@@ -104,8 +112,10 @@
cred->encr_type = WPS_ENCR_TKIP;
else if (os_strncmp(pos + 9, "CCMP", 4) == 0)
cred->encr_type = WPS_ENCR_AES;
- else
+ else {
+ wpa_printf(MSG_DEBUG, "EAP-WSC: Unknown new_encr");
return -1;
+ }
pos = os_strstr(params, "new_key=");
if (pos == NULL)
@@ -117,8 +127,10 @@
else
len = end - pos;
if ((len & 1) || len > 2 * sizeof(cred->key) ||
- hexstr2bin(pos, cred->key, len / 2))
+ hexstr2bin(pos, cred->key, len / 2)) {
+ wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid new_key");
return -1;
+ }
cred->key_len = len / 2;
return 1;
@@ -137,7 +149,6 @@
struct wps_context *wps;
struct wps_credential new_ap_settings;
int res;
- u8 dev_pw[WPS_OOB_DEVICE_PASSWORD_LEN];
int nfc = 0;
wps = sm->wps;
@@ -186,15 +197,8 @@
while (*pos != '\0' && *pos != ' ')
pos++;
cfg.pin_len = pos - (const char *) cfg.pin;
- if (cfg.pin_len >= WPS_OOB_DEVICE_PASSWORD_MIN_LEN * 2 &&
- cfg.pin_len <= WPS_OOB_DEVICE_PASSWORD_LEN * 2 &&
- hexstr2bin((const char *) cfg.pin, dev_pw,
- cfg.pin_len / 2) == 0) {
- /* Convert OOB Device Password to binary */
- cfg.pin = dev_pw;
- cfg.pin_len /= 2;
- }
- if (cfg.pin_len == 6 && os_strncmp(pos, "nfc-pw", 6) == 0) {
+ if (cfg.pin_len == 6 &&
+ os_strncmp((const char *) cfg.pin, "nfc-pw", 6) == 0) {
cfg.pin = NULL;
cfg.pin_len = 0;
nfc = 1;
@@ -219,6 +223,8 @@
res = eap_wsc_new_ap_settings(&new_ap_settings, phase1);
if (res < 0) {
os_free(data);
+ wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to parse new AP "
+ "settings");
return NULL;
}
if (res == 1) {
@@ -230,6 +236,7 @@
data->wps = wps_init(&cfg);
if (data->wps == NULL) {
os_free(data);
+ wpa_printf(MSG_DEBUG, "EAP-WSC: wps_init failed");
return NULL;
}
res = eap_get_config_fragment_size(sm);
diff --git a/src/eap_server/eap_server_aka.c b/src/eap_server/eap_server_aka.c
index a965cac..469b9a0 100644
--- a/src/eap_server/eap_server_aka.c
+++ b/src/eap_server/eap_server_aka.c
@@ -365,6 +365,7 @@
eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0);
} else if (data->identity_round > 3) {
/* Cannot use more than three rounds of Identity messages */
+ eap_sim_msg_free(msg);
return NULL;
} else if (sm->identity && sm->identity_len > 0 &&
(sm->identity[0] == EAP_AKA_REAUTH_ID_PREFIX ||
@@ -730,6 +731,17 @@
return;
}
+ if (((data->eap_method == EAP_TYPE_AKA_PRIME &&
+ username[0] == EAP_AKA_PRIME_REAUTH_ID_PREFIX) ||
+ (data->eap_method == EAP_TYPE_AKA &&
+ username[0] == EAP_AKA_REAUTH_ID_PREFIX)) &&
+ data->identity_round == 1) {
+ /* Remain in IDENTITY state for another round to request full
+ * auth identity since we did not recognize reauth id */
+ os_free(username);
+ return;
+ }
+
if ((data->eap_method == EAP_TYPE_AKA_PRIME &&
username[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) ||
(data->eap_method == EAP_TYPE_AKA &&
diff --git a/src/eap_server/eap_server_sim.c b/src/eap_server/eap_server_sim.c
index f83c3cb..b531241 100644
--- a/src/eap_server/eap_server_sim.c
+++ b/src/eap_server/eap_server_sim.c
@@ -117,6 +117,7 @@
eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0);
} else if (data->start_round > 3) {
/* Cannot use more than three rounds of Start messages */
+ eap_sim_msg_free(msg);
return NULL;
} else if (data->start_round == 0) {
/*
diff --git a/src/eap_server/eap_server_tls_common.c b/src/eap_server/eap_server_tls_common.c
index 31be2ec..9efb5b2 100644
--- a/src/eap_server/eap_server_tls_common.c
+++ b/src/eap_server/eap_server_tls_common.c
@@ -228,6 +228,14 @@
return -1;
}
+ if (len > message_length) {
+ wpa_printf(MSG_INFO, "SSL: Too much data (%d bytes) in "
+ "first fragment of frame (TLS Message "
+ "Length %d bytes)",
+ (int) len, (int) message_length);
+ return -1;
+ }
+
data->tls_in = wpabuf_alloc(message_length);
if (data->tls_in == NULL) {
wpa_printf(MSG_DEBUG, "SSL: No memory for message");
@@ -289,6 +297,13 @@
tls_msg_len);
*pos += 4;
*left -= 4;
+
+ if (*left > tls_msg_len) {
+ wpa_printf(MSG_INFO, "SSL: TLS Message Length (%d "
+ "bytes) smaller than this fragment (%d "
+ "bytes)", (int) tls_msg_len, (int) *left);
+ return -1;
+ }
}
wpa_printf(MSG_DEBUG, "SSL: Received packet: Flags 0x%x "
diff --git a/src/eap_server/ikev2.c b/src/eap_server/ikev2.c
index 0e77efb..512ba30 100644
--- a/src/eap_server/ikev2.c
+++ b/src/eap_server/ikev2.c
@@ -990,7 +990,7 @@
*/
wpabuf_put(msg, data->dh->prime_len - wpabuf_len(pv));
wpabuf_put_buf(msg, pv);
- os_free(pv);
+ wpabuf_free(pv);
plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr;
WPA_PUT_BE16(phdr->payload_length, plen);
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index 851cf49..2e56086 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -16,6 +16,7 @@
#include "crypto/md5.h"
#include "common/eapol_common.h"
#include "eap_peer/eap.h"
+#include "eap_peer/eap_proxy.h"
#include "eapol_supp_sm.h"
#define STATE_MACHINE_DATA struct eapol_sm
@@ -136,6 +137,10 @@
Boolean cached_pmk;
Boolean unicast_key_received, broadcast_key_received;
+#ifdef CONFIG_EAP_PROXY
+ Boolean use_eap_proxy;
+ struct eap_proxy_sm *eap_proxy;
+#endif /* CONFIG_EAP_PROXY */
};
@@ -463,6 +468,17 @@
sm->keyRun = TRUE;
sm->suppSuccess = TRUE;
+#ifdef CONFIG_EAP_PROXY
+ if (sm->use_eap_proxy) {
+ if (eap_proxy_key_available(sm->eap_proxy)) {
+ /* New key received - clear IEEE 802.1X EAPOL-Key replay
+ * counter */
+ sm->replay_counter_valid = FALSE;
+ }
+ return;
+ }
+#endif /* CONFIG_EAP_PROXY */
+
if (eap_key_available(sm->eap)) {
/* New key received - clear IEEE 802.1X EAPOL-Key replay
* counter */
@@ -806,6 +822,19 @@
struct wpabuf *resp;
wpa_printf(MSG_DEBUG, "EAPOL: txSuppRsp");
+
+#ifdef CONFIG_EAP_PROXY
+ if (sm->use_eap_proxy) {
+ /* Get EAP Response from EAP Proxy */
+ resp = eap_proxy_get_eapRespData(sm->eap_proxy);
+ if (resp == NULL) {
+ wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP Proxy "
+ "response data not available");
+ return;
+ }
+ } else
+#endif /* CONFIG_EAP_PROXY */
+
resp = eap_get_eapRespData(sm->eap);
if (resp == NULL) {
wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP response data "
@@ -883,6 +912,13 @@
SM_STEP_RUN(SUPP_PAE);
SM_STEP_RUN(KEY_RX);
SM_STEP_RUN(SUPP_BE);
+#ifdef CONFIG_EAP_PROXY
+ if (sm->use_eap_proxy) {
+ /* Drive the EAP proxy state machine */
+ if (eap_proxy_sm_step(sm->eap_proxy, sm->eap))
+ sm->changed = TRUE;
+ } else
+#endif /* CONFIG_EAP_PROXY */
if (eap_peer_sm_step(sm->eap))
sm->changed = TRUE;
if (!sm->changed)
@@ -1070,6 +1106,13 @@
len += ret;
}
+#ifdef CONFIG_EAP_PROXY
+ if (sm->use_eap_proxy)
+ len += eap_proxy_sm_get_status(sm->eap_proxy,
+ buf + len, buflen - len,
+ verbose);
+ else
+#endif /* CONFIG_EAP_PROXY */
len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose);
return len;
@@ -1227,6 +1270,16 @@
wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet "
"frame");
sm->eapolEap = TRUE;
+#ifdef CONFIG_EAP_PROXY
+ if (sm->use_eap_proxy) {
+ eap_proxy_packet_update(
+ sm->eap_proxy,
+ wpabuf_mhead_u8(sm->eapReqData),
+ wpabuf_len(sm->eapReqData));
+ wpa_printf(MSG_DEBUG, "EAPOL: eap_proxy "
+ "EAP Req updated");
+ }
+#endif /* CONFIG_EAP_PROXY */
eapol_sm_step(sm);
}
break;
@@ -1387,6 +1440,9 @@
return;
sm->config = config;
+#ifdef CONFIG_EAP_PROXY
+ sm->use_eap_proxy = eap_proxy_notify_config(sm->eap_proxy, config) > 0;
+#endif /* CONFIG_EAP_PROXY */
if (conf == NULL)
return;
@@ -1395,6 +1451,12 @@
sm->conf.required_keys = conf->required_keys;
sm->conf.fast_reauth = conf->fast_reauth;
sm->conf.workaround = conf->workaround;
+#ifdef CONFIG_EAP_PROXY
+ if (sm->use_eap_proxy) {
+ /* Using EAP Proxy, so skip EAP state machine update */
+ return;
+ }
+#endif /* CONFIG_EAP_PROXY */
if (sm->eap) {
eap_set_fast_reauth(sm->eap, conf->fast_reauth);
eap_set_workaround(sm->eap, conf->workaround);
@@ -1419,6 +1481,22 @@
const u8 *eap_key;
size_t eap_len;
+#ifdef CONFIG_EAP_PROXY
+ if (sm->use_eap_proxy) {
+ /* Get key from EAP proxy */
+ if (sm == NULL || !eap_proxy_key_available(sm->eap_proxy)) {
+ wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
+ return -1;
+ }
+ eap_key = eap_proxy_get_eapKeyData(sm->eap_proxy, &eap_len);
+ if (eap_key == NULL) {
+ wpa_printf(MSG_DEBUG, "EAPOL: Failed to get "
+ "eapKeyData");
+ return -1;
+ }
+ goto key_fetched;
+ }
+#endif /* CONFIG_EAP_PROXY */
if (sm == NULL || !eap_key_available(sm->eap)) {
wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
return -1;
@@ -1428,6 +1506,9 @@
wpa_printf(MSG_DEBUG, "EAPOL: Failed to get eapKeyData");
return -1;
}
+#ifdef CONFIG_EAP_PROXY
+key_fetched:
+#endif /* CONFIG_EAP_PROXY */
if (len > eap_len) {
wpa_printf(MSG_DEBUG, "EAPOL: Requested key length (%lu) not "
"available (len=%lu)",
@@ -1469,10 +1550,7 @@
if (sm == NULL)
return;
wpa_printf(MSG_DEBUG, "EAPOL: PMKSA caching was used - skip EAPOL");
- sm->SUPP_PAE_state = SUPP_PAE_AUTHENTICATED;
- sm->suppPortStatus = Authorized;
- eapol_sm_set_port_authorized(sm);
- sm->portValid = TRUE;
+ sm->eapSuccess = TRUE;
eap_notify_success(sm->eap);
eapol_sm_step(sm);
}
@@ -1892,6 +1970,14 @@
return NULL;
}
+#ifdef CONFIG_EAP_PROXY
+ sm->use_eap_proxy = FALSE;
+ sm->eap_proxy = eap_proxy_init(sm, &eapol_cb, sm->ctx->msg_ctx);
+ if (sm->eap_proxy == NULL) {
+ wpa_printf(MSG_ERROR, "Unable to initialize EAP Proxy");
+ }
+#endif /* CONFIG_EAP_PROXY */
+
/* Initialize EAPOL state machines */
sm->initialize = TRUE;
eapol_sm_step(sm);
@@ -1918,6 +2004,9 @@
eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
eap_peer_sm_deinit(sm->eap);
+#ifdef CONFIG_EAP_PROXY
+ eap_proxy_deinit(sm->eap_proxy);
+#endif /* CONFIG_EAP_PROXY */
os_free(sm->last_rx_key);
wpabuf_free(sm->eapReqData);
os_free(sm->ctx);
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index a3eaa8c..2b5e5bd 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -240,8 +240,10 @@
struct p2p_go_neg_results res;
p2p_clear_timeout(p2p);
p2p_set_state(p2p, P2P_IDLE);
- if (p2p->go_neg_peer)
+ 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 = NULL;
os_memset(&res, 0, sizeof(res));
@@ -256,7 +258,7 @@
}
-static void p2p_listen_in_find(struct p2p_data *p2p)
+static void p2p_listen_in_find(struct p2p_data *p2p, int dev_disc)
{
unsigned int r, tu;
int freq;
@@ -277,6 +279,19 @@
os_get_random((u8 *) &r, sizeof(r));
tu = (r % ((p2p->max_disc_int - p2p->min_disc_int) + 1) +
p2p->min_disc_int) * 100;
+ if (p2p->max_disc_tu >= 0 && tu > (unsigned int) p2p->max_disc_tu)
+ tu = p2p->max_disc_tu;
+ if (!dev_disc && tu < 100)
+ tu = 100; /* Need to wait in non-device discovery use cases */
+ if (p2p->cfg->max_listen && 1024 * tu / 1000 > p2p->cfg->max_listen)
+ tu = p2p->cfg->max_listen * 1000 / 1024;
+
+ if (tu == 0) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Skip listen state "
+ "since duration was 0 TU");
+ p2p_set_timeout(p2p, 0, 0);
+ return;
+ }
p2p->pending_listen_freq = freq;
p2p->pending_listen_sec = 0;
@@ -604,8 +619,18 @@
}
if (!probe_req) {
- dev->info.config_methods = msg->config_methods ?
+ u16 new_config_methods;
+ new_config_methods = msg->config_methods ?
msg->config_methods : msg->wps_config_methods;
+ if (new_config_methods &&
+ dev->info.config_methods != new_config_methods) {
+ wpa_printf(MSG_DEBUG, "P2P: Update peer " MACSTR
+ " config_methods 0x%x -> 0x%x",
+ MAC2STR(dev->info.p2p_device_addr),
+ dev->info.config_methods,
+ new_config_methods);
+ dev->info.config_methods = new_config_methods;
+ }
}
}
@@ -617,6 +642,7 @@
* P2P Device Address or P2P Interface Address)
* @level: Signal level (signal strength of the received frame from the peer)
* @freq: Frequency on which the Beacon or Probe Response frame was received
+ * @rx_time: Time when the result was received
* @ies: IEs from the Beacon or Probe Response frame
* @ies_len: Length of ies buffer in octets
* @scan_res: Whether this was based on scan results
@@ -627,13 +653,15 @@
* like Provision Discovery Request that contains P2P Capability and P2P Device
* Info attributes.
*/
-int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, int level,
- const u8 *ies, size_t ies_len, int scan_res)
+int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
+ struct os_time *rx_time, int level, const u8 *ies,
+ size_t ies_len, int scan_res)
{
struct p2p_device *dev;
struct p2p_message msg;
const u8 *p2p_dev_addr;
int i;
+ struct os_time time_now;
os_memset(&msg, 0, sizeof(msg));
if (p2p_parse_ies(ies, ies_len, &msg)) {
@@ -660,6 +688,7 @@
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Do not add peer "
"filter for " MACSTR " due to peer filter",
MAC2STR(p2p_dev_addr));
+ p2p_parse_free(&msg);
return 0;
}
@@ -668,7 +697,31 @@
p2p_parse_free(&msg);
return -1;
}
- os_get_time(&dev->last_seen);
+
+ if (rx_time == NULL) {
+ os_get_time(&time_now);
+ rx_time = &time_now;
+ }
+
+ /*
+ * Update the device entry only if the new peer
+ * entry is newer than the one previously stored.
+ */
+ if (dev->last_seen.sec > 0 &&
+ os_time_before(rx_time, &dev->last_seen)) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Do not update peer "
+ "entry based on old frame (rx_time=%u.%06u "
+ "last_seen=%u.%06u)",
+ (unsigned int) rx_time->sec,
+ (unsigned int) rx_time->usec,
+ (unsigned int) dev->last_seen.sec,
+ (unsigned int) dev->last_seen.usec);
+ p2p_parse_free(&msg);
+ return -1;
+ }
+
+ os_memcpy(&dev->last_seen, rx_time, sizeof(struct os_time));
+
dev->flags &= ~(P2P_DEV_PROBE_REQ_ONLY | P2P_DEV_GROUP_CLIENT_ONLY);
if (os_memcmp(addr, p2p_dev_addr, ETH_ALEN) != 0)
@@ -746,13 +799,37 @@
return 0;
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Peer found with Listen frequency %d MHz", freq);
+ "P2P: Peer found with Listen frequency %d MHz "
+ "(rx_time=%u.%06u)", freq, (unsigned int) rx_time->sec,
+ (unsigned int) rx_time->usec);
if (dev->flags & P2P_DEV_USER_REJECTED) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Do not report rejected device");
return 0;
}
+ if (dev->info.config_methods == 0 &&
+ (freq == 2412 || freq == 2437 || freq == 2462)) {
+ /*
+ * If we have only seen a Beacon frame from a GO, we do not yet
+ * know what WPS config methods it supports. Since some
+ * applications use config_methods value from P2P-DEVICE-FOUND
+ * events, postpone reporting this peer until we've fully
+ * discovered its capabilities.
+ *
+ * At least for now, do this only if the peer was detected on
+ * one of the social channels since that peer can be easily be
+ * found again and there are no limitations of having to use
+ * passive scan on this channels, so this can be done through
+ * Probe Response frame that includes the config_methods
+ * information.
+ */
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+ "P2P: Do not report peer " MACSTR " with unknown "
+ "config methods", MAC2STR(addr));
+ return 0;
+ }
+
p2p->cfg->dev_found(p2p->cfg->cb_ctx, addr, &dev->info,
!(dev->flags & P2P_DEV_REPORTED_ONCE));
dev->flags |= P2P_DEV_REPORTED | P2P_DEV_REPORTED_ONCE;
@@ -997,6 +1074,7 @@
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting find (type=%d)",
type);
+ os_get_time(&p2p->find_start);
if (p2p->p2p_scan_running) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: p2p_scan is "
"already running");
@@ -1099,8 +1177,10 @@
"now that previous scan was completed");
if (p2p_find(p2p, p2p->last_p2p_find_timeout, p2p->find_type,
p2p->num_req_dev_types, p2p->req_dev_types,
- p2p->find_dev_id, p2p->search_delay) < 0)
+ p2p->find_dev_id, p2p->search_delay) < 0) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_INFO, P2P_EVENT_FIND_STOPPED);
return 0;
+ }
return 1;
}
@@ -1110,11 +1190,15 @@
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Stopping find");
eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
p2p_clear_timeout(p2p);
- if (p2p->state == P2P_SEARCH)
+ if (p2p->state == P2P_SEARCH ||
+ p2p->state == P2P_CONTINUE_SEARCH_WHEN_READY ||
+ p2p->state == P2P_SEARCH_WHEN_READY)
wpa_msg(p2p->cfg->msg_ctx, MSG_INFO, P2P_EVENT_FIND_STOPPED);
p2p_set_state(p2p, P2P_IDLE);
p2p_free_req_dev_types(p2p);
p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
+ if (p2p->go_neg_peer)
+ p2p->go_neg_peer->flags &= ~P2P_DEV_PEER_WAITING_RESPONSE;
p2p->go_neg_peer = NULL;
p2p->sd_peer = NULL;
p2p->invite_peer = NULL;
@@ -1153,103 +1237,115 @@
}
-static int p2p_prepare_channel(struct p2p_data *p2p, unsigned int force_freq)
+static int p2p_prepare_channel_pref(struct p2p_data *p2p,
+ unsigned int force_freq,
+ unsigned int pref_freq)
{
+ u8 op_class, op_channel;
+ unsigned int freq = force_freq ? force_freq : pref_freq;
+
+ if (p2p_freq_to_channel(p2p->cfg->country, freq,
+ &op_class, &op_channel) < 0) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+ "P2P: Unsupported frequency %u MHz", freq);
+ return -1;
+ }
+
+ if (!p2p_channels_includes(&p2p->cfg->channels, op_class, op_channel)) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+ "P2P: Frequency %u MHz (oper_class %u channel %u) not "
+ "allowed for P2P", freq, op_class, op_channel);
+ return -1;
+ }
+
+ p2p->op_reg_class = op_class;
+ p2p->op_channel = op_channel;
+
if (force_freq) {
- u8 op_reg_class, op_channel;
- if (p2p_freq_to_channel(p2p->cfg->country, force_freq,
- &op_reg_class, &op_channel) < 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported frequency %u MHz",
- force_freq);
- return -1;
- }
- if (!p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
- op_channel)) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Frequency %u MHz (oper_class %u "
- "channel %u) not allowed for P2P",
- force_freq, op_reg_class, op_channel);
- return -1;
- }
- p2p->op_reg_class = op_reg_class;
- p2p->op_channel = op_channel;
-#ifndef ANDROID_P2P
p2p->channels.reg_classes = 1;
p2p->channels.reg_class[0].channels = 1;
p2p->channels.reg_class[0].reg_class = p2p->op_reg_class;
p2p->channels.reg_class[0].channel[0] = p2p->op_channel;
-#else
- if(p2p->cfg->p2p_concurrency == P2P_MULTI_CHANNEL_CONCURRENT) {
- /* We we are requesting for a preferred channel. But since
- * are multichannel concurrent, we have to poplulate the
- * p2p_channels with list of channels that we support.
- */
-#ifdef ANDROID_P2P
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "Full channel list");
-#endif
- os_memcpy(&p2p->channels, &p2p->cfg->channels,
- sizeof(struct p2p_channels));
- } else {
-#ifdef ANDROID_P2P
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "Single channel list %d", p2p->op_channel);
-#endif
- p2p->channels.reg_classes = 1;
- p2p->channels.reg_class[0].channels = 1;
- p2p->channels.reg_class[0].reg_class = p2p->op_reg_class;
- p2p->channels.reg_class[0].channel[0] = p2p->op_channel;
- }
-#endif
} else {
- u8 op_reg_class, op_channel;
-
- if (!p2p->cfg->cfg_op_channel && p2p->best_freq_overall > 0 &&
- p2p_supported_freq(p2p, p2p->best_freq_overall) &&
- p2p_freq_to_channel(p2p->cfg->country,
- p2p->best_freq_overall,
- &op_reg_class, &op_channel) == 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Select best overall channel as "
- "operating channel preference");
- p2p->op_reg_class = op_reg_class;
- p2p->op_channel = op_channel;
- } else if (!p2p->cfg->cfg_op_channel && p2p->best_freq_5 > 0 &&
- p2p_supported_freq(p2p, p2p->best_freq_5) &&
- p2p_freq_to_channel(p2p->cfg->country,
- p2p->best_freq_5,
- &op_reg_class, &op_channel) ==
- 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Select best 5 GHz channel as "
- "operating channel preference");
- p2p->op_reg_class = op_reg_class;
- p2p->op_channel = op_channel;
- } else if (!p2p->cfg->cfg_op_channel &&
- p2p->best_freq_24 > 0 &&
- p2p_supported_freq(p2p, p2p->best_freq_24) &&
- p2p_freq_to_channel(p2p->cfg->country,
- p2p->best_freq_24,
- &op_reg_class, &op_channel) ==
- 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Select best 2.4 GHz channel as "
- "operating channel preference");
- p2p->op_reg_class = op_reg_class;
- p2p->op_channel = op_channel;
- } else {
- p2p->op_reg_class = p2p->cfg->op_reg_class;
- p2p->op_channel = p2p->cfg->op_channel;
- }
-
os_memcpy(&p2p->channels, &p2p->cfg->channels,
sizeof(struct p2p_channels));
}
+
+ return 0;
+}
+
+
+static void p2p_prepare_channel_best(struct p2p_data *p2p)
+{
+ u8 op_class, op_channel;
+
+ if (!p2p->cfg->cfg_op_channel && p2p->best_freq_overall > 0 &&
+ p2p_supported_freq(p2p, p2p->best_freq_overall) &&
+ p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_overall,
+ &op_class, &op_channel) == 0) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Select best "
+ "overall channel as operating channel preference");
+ p2p->op_reg_class = op_class;
+ p2p->op_channel = op_channel;
+ } else if (!p2p->cfg->cfg_op_channel && p2p->best_freq_5 > 0 &&
+ p2p_supported_freq(p2p, p2p->best_freq_5) &&
+ p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_5,
+ &op_class, &op_channel) == 0) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Select best 5 GHz "
+ "channel as operating channel preference");
+ p2p->op_reg_class = op_class;
+ p2p->op_channel = op_channel;
+ } else if (!p2p->cfg->cfg_op_channel && p2p->best_freq_24 > 0 &&
+ p2p_supported_freq(p2p, p2p->best_freq_24) &&
+ p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_24,
+ &op_class, &op_channel) == 0) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Select best 2.4 "
+ "GHz channel as operating channel preference");
+ p2p->op_reg_class = op_class;
+ p2p->op_channel = op_channel;
+ } else {
+ p2p->op_reg_class = p2p->cfg->op_reg_class;
+ p2p->op_channel = p2p->cfg->op_channel;
+ }
+
+ os_memcpy(&p2p->channels, &p2p->cfg->channels,
+ sizeof(struct p2p_channels));
+}
+
+
+/**
+ * p2p_prepare_channel - Select operating channel for GO Negotiation
+ * @p2p: P2P module context from p2p_init()
+ * @dev: Selected peer device
+ * @force_freq: Forced frequency in MHz or 0 if not forced
+ * @pref_freq: Preferred frequency in MHz or 0 if no preference
+ * Returns: 0 on success, -1 on failure (channel not supported for P2P)
+ *
+ * This function is used to do initial operating channel selection for GO
+ * Negotiation prior to having received peer information. The selected channel
+ * may be further optimized in p2p_reselect_channel() once the peer information
+ * is available.
+ */
+int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
+ unsigned int force_freq, unsigned int pref_freq)
+{
+ if (force_freq || pref_freq) {
+ if (p2p_prepare_channel_pref(p2p, force_freq, pref_freq) < 0)
+ return -1;
+ } else {
+ p2p_prepare_channel_best(p2p);
+ }
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Own preference for operation channel: "
"Operating Class %u Channel %u%s",
p2p->op_reg_class, p2p->op_channel,
force_freq ? " (forced)" : "");
+ if (force_freq)
+ dev->flags |= P2P_DEV_FORCE_FREQ;
+ else
+ dev->flags &= ~P2P_DEV_FORCE_FREQ;
+
return 0;
}
@@ -1279,19 +1375,16 @@
int go_intent, const u8 *own_interface_addr,
unsigned int force_freq, int persistent_group,
const u8 *force_ssid, size_t force_ssid_len,
- int pd_before_go_neg)
+ int pd_before_go_neg, unsigned int pref_freq)
{
struct p2p_device *dev;
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Request to start group negotiation - peer=" MACSTR
" GO Intent=%d Intended Interface Address=" MACSTR
- " wps_method=%d persistent_group=%d pd_before_go_neg=%d force_freq %d",
+ " wps_method=%d persistent_group=%d pd_before_go_neg=%d",
MAC2STR(peer_addr), go_intent, MAC2STR(own_interface_addr),
- wps_method, persistent_group, pd_before_go_neg, force_freq);
-
- if (p2p_prepare_channel(p2p, force_freq) < 0)
- return -1;
+ wps_method, persistent_group, pd_before_go_neg);
dev = p2p_get_device(p2p, peer_addr);
if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
@@ -1301,6 +1394,9 @@
return -1;
}
+ if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq) < 0)
+ return -1;
+
if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {
if (!(dev->info.dev_capab &
P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
@@ -1340,8 +1436,18 @@
dev->flags &= ~P2P_DEV_WAIT_GO_NEG_CONFIRM;
if (pd_before_go_neg)
dev->flags |= P2P_DEV_PD_BEFORE_GO_NEG;
- else
+ else {
dev->flags &= ~P2P_DEV_PD_BEFORE_GO_NEG;
+ /*
+ * Assign dialog token and tie breaker here to use the same
+ * values in each retry within the same GO Negotiation exchange.
+ */
+ dev->dialog_token++;
+ if (dev->dialog_token == 0)
+ dev->dialog_token = 1;
+ dev->tie_breaker = p2p->next_tie_breaker;
+ p2p->next_tie_breaker = !p2p->next_tie_breaker;
+ }
dev->connect_reqs = 0;
dev->go_neg_req_sent = 0;
dev->go_state = UNKNOWN_GO;
@@ -1368,11 +1474,6 @@
dev->wps_method = wps_method;
dev->status = P2P_SC_SUCCESS;
- if (force_freq)
- dev->flags |= P2P_DEV_FORCE_FREQ;
- else
- dev->flags &= ~P2P_DEV_FORCE_FREQ;
-
if (p2p->p2p_scan_running) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: p2p_scan running - delay connect send");
@@ -1390,7 +1491,8 @@
enum p2p_wps_method wps_method,
int go_intent, const u8 *own_interface_addr,
unsigned int force_freq, int persistent_group,
- const u8 *force_ssid, size_t force_ssid_len)
+ const u8 *force_ssid, size_t force_ssid_len,
+ unsigned int pref_freq)
{
struct p2p_device *dev;
@@ -1401,9 +1503,6 @@
MAC2STR(peer_addr), go_intent, MAC2STR(own_interface_addr),
wps_method, persistent_group);
- if (p2p_prepare_channel(p2p, force_freq) < 0)
- return -1;
-
dev = p2p_get_device(p2p, peer_addr);
if (dev == NULL) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
@@ -1412,6 +1511,9 @@
return -1;
}
+ if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq) < 0)
+ return -1;
+
p2p->ssid_set = 0;
if (force_ssid) {
wpa_hexdump_ascii(MSG_DEBUG, "P2P: Forced SSID",
@@ -1432,11 +1534,6 @@
dev->wps_method = wps_method;
dev->status = P2P_SC_SUCCESS;
- if (force_freq)
- dev->flags |= P2P_DEV_FORCE_FREQ;
- else
- dev->flags &= ~P2P_DEV_FORCE_FREQ;
-
return 0;
}
@@ -2140,11 +2237,13 @@
if ((p2p->state == P2P_CONNECT || p2p->state == P2P_CONNECT_LISTEN) &&
p2p->go_neg_peer &&
os_memcmp(addr, p2p->go_neg_peer->info.p2p_device_addr, ETH_ALEN)
- == 0) {
+ == 0 &&
+ !(p2p->go_neg_peer->flags & P2P_DEV_WAIT_GO_NEG_CONFIRM)) {
/* Received a Probe Request from GO Negotiation peer */
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Found GO Negotiation peer - try to start GO "
"negotiation from timeout");
+ eloop_cancel_timeout(p2p_go_neg_start, p2p, NULL);
eloop_register_timeout(0, 0, p2p_go_neg_start, p2p, NULL);
return P2P_PREQ_PROCESSED;
}
@@ -2416,6 +2515,7 @@
p2p->min_disc_int = 1;
#endif
p2p->max_disc_int = 3;
+ p2p->max_disc_tu = -1;
os_get_random(&p2p->next_tie_breaker, 1);
p2p->next_tie_breaker &= 0x01;
@@ -2457,6 +2557,7 @@
eloop_cancel_timeout(p2p_expiration_timeout, p2p, NULL);
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);
p2p_flush(p2p);
p2p_free_req_dev_types(p2p);
os_free(p2p->cfg->dev_name);
@@ -2712,7 +2813,7 @@
}
}
- p2p_listen_in_find(p2p);
+ p2p_listen_in_find(p2p, 1);
}
@@ -2758,8 +2859,7 @@
/*
* Retry the prov disc req attempt only for the peer that the user had
- * requested for and provided a join has not been initiated on it
- * in the meantime.
+ * requested.
*/
dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
@@ -2768,15 +2868,14 @@
continue;
if (!dev->req_config_methods)
continue;
- if (dev->flags & P2P_DEV_PD_FOR_JOIN)
- continue;
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send "
"pending Provision Discovery Request to "
MACSTR " (config methods 0x%x)",
MAC2STR(dev->info.p2p_device_addr),
dev->req_config_methods);
- p2p_send_prov_disc_req(p2p, dev, 0, 0);
+ p2p_send_prov_disc_req(p2p, dev,
+ dev->flags & P2P_DEV_PD_FOR_JOIN, 0);
return;
}
}
@@ -2841,9 +2940,25 @@
int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
- int level, const u8 *ies, size_t ies_len)
+ struct os_time *rx_time, int level, const u8 *ies,
+ size_t ies_len)
{
- p2p_add_device(p2p, bssid, freq, level, ies, ies_len, 1);
+ if (os_time_before(rx_time, &p2p->find_start)) {
+ /*
+ * The driver may have cached (e.g., in cfg80211 BSS table) the
+ * scan results for relatively long time. To avoid reporting
+ * stale information, update P2P peers only based on results
+ * that have based on frames received after the last p2p_find
+ * operation was started.
+ */
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Ignore old scan "
+ "result for " MACSTR " (rx_time=%u.%06u)",
+ MAC2STR(bssid), (unsigned int) rx_time->sec,
+ (unsigned int) rx_time->usec);
+ return 0;
+ }
+
+ p2p_add_device(p2p, bssid, freq, rx_time, level, ies, ies_len, 1);
return 0;
}
@@ -2913,6 +3028,7 @@
static void p2p_go_neg_req_cb(struct p2p_data *p2p, int success)
{
struct p2p_device *dev = p2p->go_neg_peer;
+ int timeout;
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: GO Negotiation Request TX callback: success=%d",
@@ -2951,11 +3067,20 @@
* channel.
*/
p2p_set_state(p2p, P2P_CONNECT);
-#ifdef ANDROID_P2P
- p2p_set_timeout(p2p, 0, 350000);
-#else
- p2p_set_timeout(p2p, 0, success ? 200000 : 100000);
-#endif
+ timeout = success ? 500000 : 100000;
+ if (!success && p2p->go_neg_peer &&
+ (p2p->go_neg_peer->flags & P2P_DEV_PEER_WAITING_RESPONSE)) {
+ unsigned int r;
+ /*
+ * Peer is expected to wait our response and we will skip the
+ * listen phase. Add some randomness to the wait time here to
+ * make it less likely to hit cases where we could end up in
+ * sync with peer not listening.
+ */
+ os_get_random((u8 *) &r, sizeof(r));
+ timeout += r % 100000;
+ }
+ p2p_set_timeout(p2p, 0, timeout);
}
@@ -2971,11 +3096,7 @@
return;
}
p2p_set_state(p2p, P2P_CONNECT);
-#ifdef ANDROID_P2P
- p2p_set_timeout(p2p, 0, 350000);
-#else
- p2p_set_timeout(p2p, 0, 250000);
-#endif
+ p2p_set_timeout(p2p, 0, 500000);
}
@@ -3197,8 +3318,17 @@
p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
return;
}
+ if (p2p->go_neg_peer &&
+ (p2p->go_neg_peer->flags & P2P_DEV_PEER_WAITING_RESPONSE) &&
+ p2p->go_neg_peer->connect_reqs < 120) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer expected to "
+ "wait our response - skip listen");
+ p2p_connect_send(p2p, p2p->go_neg_peer);
+ return;
+ }
+
p2p_set_state(p2p, P2P_CONNECT_LISTEN);
- p2p_listen_in_find(p2p);
+ p2p_listen_in_find(p2p, 0);
}
@@ -3262,7 +3392,7 @@
"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);
+ p2p_listen_in_find(p2p, 0);
}
@@ -3307,9 +3437,23 @@
p2p->pd_retries--;
p2p_retry_pd(p2p);
} else {
+ struct p2p_device *dev;
+ int for_join = 0;
+
+ dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
+ if (os_memcmp(p2p->pending_pd_devaddr,
+ dev->info.p2p_device_addr, ETH_ALEN) != 0)
+ continue;
+ if (dev->req_config_methods &&
+ (dev->flags & P2P_DEV_PD_FOR_JOIN))
+ for_join = 1;
+ }
+
if (p2p->cfg->prov_disc_fail)
p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx,
p2p->pending_pd_devaddr,
+ for_join ?
+ P2P_PROV_DISC_TIMEOUT_JOIN :
P2P_PROV_DISC_TIMEOUT);
p2p_reset_pending_pd(p2p);
}
@@ -3330,7 +3474,7 @@
p2p_set_timeout(p2p, 0, 100000);
return;
}
- p2p_listen_in_find(p2p);
+ p2p_listen_in_find(p2p, 0);
}
@@ -3346,7 +3490,8 @@
"P2P: Invitation Request retry limit reached");
if (p2p->cfg->invitation_result)
p2p->cfg->invitation_result(
- p2p->cfg->cb_ctx, -1, NULL);
+ p2p->cfg->cb_ctx, -1, NULL, NULL,
+ p2p->invite_peer->info.p2p_device_addr);
}
p2p_set_state(p2p, P2P_IDLE);
}
@@ -4175,6 +4320,14 @@
}
+void p2p_set_own_freq_preference(struct p2p_data *p2p, int freq)
+{
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Own frequency preference: "
+ "%d MHz", freq);
+ p2p->own_freq_preference = freq;
+}
+
+
const u8 * p2p_get_go_neg_peer(struct p2p_data *p2p)
{
if (p2p == NULL || p2p->go_neg_peer == NULL)
@@ -4384,3 +4537,20 @@
}
#endif /* CONFIG_WIFI_DISPLAY */
+
+
+int p2p_set_disc_int(struct p2p_data *p2p, int min_disc_int, int max_disc_int,
+ int max_disc_tu)
+{
+ if (min_disc_int > max_disc_int || min_disc_int < 0 || max_disc_int < 0)
+ return -1;
+
+ p2p->min_disc_int = min_disc_int;
+ p2p->max_disc_int = max_disc_int;
+ p2p->max_disc_tu = max_disc_tu;
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Set discoverable interval: "
+ "min=%d max=%d max_tu=%d", min_disc_int, max_disc_int,
+ max_disc_tu);
+
+ return 0;
+}
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index b80f898..28a0a1d 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -92,6 +92,16 @@
size_t ssid_len;
/**
+ * psk - WPA pre-shared key (256 bits) (GO only)
+ */
+ u8 psk[32];
+
+ /**
+ * psk_set - Whether PSK field is configured (GO only)
+ */
+ int psk_set;
+
+ /**
* passphrase - WPA2-Personal passphrase for the group (GO only)
*/
char passphrase[64];
@@ -227,6 +237,7 @@
P2P_PROV_DISC_SUCCESS,
P2P_PROV_DISC_TIMEOUT,
P2P_PROV_DISC_REJECTED,
+ P2P_PROV_DISC_TIMEOUT_JOIN,
};
struct p2p_channel {
@@ -359,6 +370,11 @@
*/
size_t ssid_postfix_len;
+ /**
+ * max_listen - Maximum listen duration in ms
+ */
+ unsigned int max_listen;
+
#ifdef ANDROID_P2P
enum p2p_concurrency_type {
P2P_NON_CONCURRENT,
@@ -726,6 +742,8 @@
* @ctx: Callback context from cb_ctx
* @status: Negotiation result (Status Code)
* @bssid: P2P Group BSSID or %NULL if not received
+ * @channels: Available operating channels for the group
+ * @addr: Peer address
*
* This callback is used to indicate result of an Invitation procedure
* started with a call to p2p_invite(). The indicated status code is
@@ -733,7 +751,9 @@
* (P2P_SC_SUCCESS) indicating success or -1 to indicate a timeout or a
* local failure in transmitting the Invitation Request.
*/
- void (*invitation_result)(void *ctx, int status, const u8 *bssid);
+ void (*invitation_result)(void *ctx, int status, const u8 *bssid,
+ const struct p2p_channels *channels,
+ const u8 *addr);
/**
* go_connected - Check whether we are connected to a GO
@@ -902,6 +922,8 @@
* @pd_before_go_neg: Whether to send Provision Discovery prior to GO
* Negotiation as an interoperability workaround when initiating group
* formation
+ * @pref_freq: Preferred operating frequency in MHz or 0 (this is only used if
+ * force_freq == 0)
* Returns: 0 on success, -1 on failure
*/
int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
@@ -909,7 +931,7 @@
int go_intent, const u8 *own_interface_addr,
unsigned int force_freq, int persistent_group,
const u8 *force_ssid, size_t force_ssid_len,
- int pd_before_go_neg);
+ int pd_before_go_neg, unsigned int pref_freq);
/**
* p2p_authorize - Authorize P2P group formation (GO negotiation)
@@ -925,6 +947,8 @@
* @force_ssid: Forced SSID for the group if we become GO or %NULL to generate
* a new SSID
* @force_ssid_len: Length of $force_ssid buffer
+ * @pref_freq: Preferred operating frequency in MHz or 0 (this is only used if
+ * force_freq == 0)
* Returns: 0 on success, -1 on failure
*
* This is like p2p_connect(), but the actual group negotiation is not
@@ -934,7 +958,8 @@
enum p2p_wps_method wps_method,
int go_intent, const u8 *own_interface_addr,
unsigned int force_freq, int persistent_group,
- const u8 *force_ssid, size_t force_ssid_len);
+ const u8 *force_ssid, size_t force_ssid_len,
+ unsigned int pref_freq);
/**
* p2p_reject - Reject peer device (explicitly block connection attempts)
@@ -951,6 +976,7 @@
* @config_methods: WPS Config Methods value (only one bit set)
* @join: Whether this is used by a client joining an active group
* @force_freq: Forced TX frequency for the frame (mainly for the join case)
+ * @user_initiated_pd: Flag to indicate if initiated by user or not
* Returns: 0 on success, -1 on failure
*
* This function can be used to request a discovered P2P peer to display a PIN
@@ -962,7 +988,8 @@
* indicated with the p2p_config::prov_disc_resp() callback.
*/
int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
- u16 config_methods, int join, int force_freq);
+ u16 config_methods, int join, int force_freq,
+ int user_initiated_pd);
/**
* p2p_sd_request - Schedule a service discovery query
@@ -1036,12 +1063,14 @@
* @force_freq: The only allowed channel frequency in MHz or 0
* @go_dev_addr: Forced GO Device Address or %NULL if none
* @persistent_group: Whether this is to reinvoke a persistent group
+ * @pref_freq: Preferred operating frequency in MHz or 0 (this is only used if
+ * force_freq == 0)
* Returns: 0 on success, -1 on failure
*/
int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role,
const u8 *bssid, const u8 *ssid, size_t ssid_len,
unsigned int force_freq, const u8 *go_dev_addr,
- int persistent_group);
+ int persistent_group, unsigned int pref_freq);
/**
* p2p_presence_req - Request GO presence
@@ -1177,6 +1206,7 @@
* @p2p: P2P module context from p2p_init()
* @bssid: BSSID of the scan result
* @freq: Frequency of the channel on which the device was found in MHz
+ * @rx_time: Time when the result was received
* @level: Signal level (signal strength of the received Beacon/Probe Response
* frame)
* @ies: Pointer to IEs from the scan result
@@ -1198,7 +1228,8 @@
* start of a pending operation, e.g., to start a pending GO negotiation.
*/
int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
- int level, const u8 *ies, size_t ies_len);
+ struct os_time *rx_time, int level, const u8 *ies,
+ size_t ies_len);
/**
* p2p_scan_res_handled - Indicate end of scan results
@@ -1606,6 +1637,9 @@
*/
void p2p_set_intra_bss_dist(struct p2p_data *p2p, int enabled);
+int p2p_channels_includes_freq(const struct p2p_channels *channels,
+ unsigned int freq);
+
/**
* p2p_supported_freq - Check whether channel is supported for P2P
* @p2p: P2P module context from p2p_init()
@@ -1626,6 +1660,17 @@
void p2p_set_best_channels(struct p2p_data *p2p, int freq_24, int freq_5,
int freq_overall);
+/**
+ * p2p_set_own_freq_preference - Set own preference for channel
+ * @p2p: P2P module context from p2p_init()
+ * @freq: Frequency (MHz) of the preferred channel or 0 if no preference
+ *
+ * This function can be used to set a preference on the operating channel based
+ * on frequencies used on the other virtual interfaces that share the same
+ * radio. If non-zero, this is used to try to avoid multi-channel concurrency.
+ */
+void p2p_set_own_freq_preference(struct p2p_data *p2p, int freq);
+
const u8 * p2p_get_go_neg_peer(struct p2p_data *p2p);
/**
@@ -1767,4 +1812,25 @@
const struct wpabuf *elem);
struct wpabuf * wifi_display_encaps(struct wpabuf *subelems);
+/**
+ * p2p_set_disc_int - Set min/max discoverable interval for p2p_find
+ * @p2p: P2P module context from p2p_init()
+ * @min_disc_int: minDiscoverableInterval (in units of 100 TU); default 1
+ * @max_disc_int: maxDiscoverableInterval (in units of 100 TU); default 3
+ * @max_disc_tu: Maximum number of TUs (1.024 ms) for discoverable interval; or
+ * -1 not to limit
+ * Returns: 0 on success, or -1 on failure
+ *
+ * This function can be used to configure minDiscoverableInterval and
+ * maxDiscoverableInterval parameters for the Listen state during device
+ * discovery (p2p_find). A random number of 100 TU units is picked for each
+ * Listen state iteration from [min_disc_int,max_disc_int] range.
+ *
+ * max_disc_tu can be used to futher limit the discoverable duration. However,
+ * it should be noted that use of this parameter is not recommended since it
+ * would not be compliant with the P2P specification.
+ */
+int p2p_set_disc_int(struct p2p_data *p2p, int min_disc_int, int max_disc_int,
+ int max_disc_tu);
+
#endif /* P2P_H */
diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c
index be069a5..5838d35 100644
--- a/src/p2p/p2p_build.c
+++ b/src/p2p/p2p_build.c
@@ -136,6 +136,7 @@
len + 2, (u8 *) wpabuf_put(buf, 0) - len - 2);
}
+
void p2p_buf_add_status(struct wpabuf *buf, u8 status)
{
/* Status */
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index b21d97c..c143ef4 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -145,9 +145,6 @@
if (buf == NULL)
return NULL;
- peer->dialog_token++;
- if (peer->dialog_token == 0)
- peer->dialog_token = 1;
p2p_buf_add_public_action_hdr(buf, P2P_GO_NEG_REQ, peer->dialog_token);
len = p2p_buf_add_ie_hdr(buf);
@@ -164,9 +161,7 @@
p2p_buf_add_capability(buf, p2p->dev_capab &
~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
group_capab);
- p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) |
- p2p->next_tie_breaker);
- p2p->next_tie_breaker = !p2p->next_tie_breaker;
+ p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) | peer->tie_breaker);
p2p_buf_add_config_timeout(buf, p2p->go_timeout, p2p->client_timeout);
p2p_buf_add_listen_channel(buf, p2p->cfg->country, p2p->cfg->reg_class,
p2p->cfg->channel);
@@ -211,7 +206,7 @@
else
return -1;
return p2p_prov_disc_req(p2p, dev->info.p2p_device_addr,
- config_method, 0, 0);
+ config_method, 0, 0, 1);
}
freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
@@ -235,7 +230,7 @@
dev->connect_reqs++;
if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
p2p->cfg->dev_addr, dev->info.p2p_device_addr,
- wpabuf_head(req), wpabuf_len(req), 200) < 0) {
+ wpabuf_head(req), wpabuf_len(req), 500) < 0) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Failed to send Action frame");
/* Use P2P find to recover and retry */
@@ -302,7 +297,6 @@
p2p->op_channel);
}
p2p_buf_add_intended_addr(buf, p2p->intended_addr);
-
if (status || peer == NULL) {
p2p_buf_add_channel_list(buf, p2p->cfg->country,
&p2p->channels);
@@ -315,7 +309,6 @@
&res);
p2p_buf_add_channel_list(buf, p2p->cfg->country, &res);
}
-
p2p_buf_add_device_info(buf, p2p, peer);
if (peer && peer->go_state == LOCAL_GO) {
p2p_buf_add_group_id(buf, p2p->cfg->dev_addr, p2p->ssid,
@@ -338,6 +331,17 @@
}
+/**
+ * p2p_reselect_channel - Re-select operating channel based on peer information
+ * @p2p: P2P module context from p2p_init()
+ * @intersection: Support channel list intersection from local and peer
+ *
+ * This function is used to re-select the best channel after having received
+ * information from the peer to allow supported channel lists to be intersected.
+ * This can be used to improve initial channel selection done in
+ * p2p_prepare_channel() prior to the start of GO Negotiation. In addition, this
+ * can be used for Invitation case.
+ */
void p2p_reselect_channel(struct p2p_data *p2p,
struct p2p_channels *intersection)
{
@@ -346,14 +350,36 @@
u8 op_reg_class, op_channel;
unsigned int i;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Selected operating "
- "channel (reg_class %u channel %u) not acceptable to the "
- "peer", p2p->op_reg_class, p2p->op_channel);
+ if (p2p->own_freq_preference > 0 &&
+ p2p_freq_to_channel(p2p->cfg->country, p2p->own_freq_preference,
+ &op_reg_class, &op_channel) == 0 &&
+ p2p_channels_includes(intersection, op_reg_class, op_channel)) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Pick own channel "
+ "preference (reg_class %u channel %u) from "
+ "intersection", op_reg_class, op_channel);
+ p2p->op_reg_class = op_reg_class;
+ p2p->op_channel = op_channel;
+ return;
+ }
+
+ if (p2p->best_freq_overall > 0 &&
+ p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_overall,
+ &op_reg_class, &op_channel) == 0 &&
+ p2p_channels_includes(intersection, op_reg_class, op_channel)) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Pick best overall "
+ "channel (reg_class %u channel %u) from intersection",
+ op_reg_class, op_channel);
+ p2p->op_reg_class = op_reg_class;
+ p2p->op_channel = op_channel;
+ return;
+ }
/* First, try to pick the best channel from another band */
freq = p2p_channel_to_freq(p2p->cfg->country, p2p->op_reg_class,
p2p->op_channel);
if (freq >= 2400 && freq < 2500 && p2p->best_freq_5 > 0 &&
+ !p2p_channels_includes(intersection, p2p->op_reg_class,
+ p2p->op_channel) &&
p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_5,
&op_reg_class, &op_channel) == 0 &&
p2p_channels_includes(intersection, op_reg_class, op_channel)) {
@@ -366,6 +392,8 @@
}
if (freq >= 4900 && freq < 6000 && p2p->best_freq_24 > 0 &&
+ !p2p_channels_includes(intersection, p2p->op_reg_class,
+ p2p->op_channel) &&
p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_24,
&op_reg_class, &op_channel) == 0 &&
p2p_channels_includes(intersection, op_reg_class, op_channel)) {
@@ -392,6 +420,35 @@
}
}
+ /* Try a channel where we might be able to use HT40 */
+ for (i = 0; i < intersection->reg_classes; i++) {
+ struct p2p_reg_class *c = &intersection->reg_class[i];
+ if (c->reg_class == 116 || c->reg_class == 117 ||
+ c->reg_class == 126 || c->reg_class == 127) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+ "P2P: Pick possible HT40 channel (reg_class "
+ "%u channel %u) from intersection",
+ c->reg_class, c->channel[0]);
+ p2p->op_reg_class = c->reg_class;
+ p2p->op_channel = c->channel[0];
+ return;
+ }
+ }
+
+ /*
+ * Try to see if the original channel is in the intersection. If
+ * so, no need to change anything, as it already contains some
+ * randomness.
+ */
+ if (p2p_channels_includes(intersection, p2p->op_reg_class,
+ p2p->op_channel)) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+ "P2P: Using original operating class and channel "
+ "(op_class %u channel %u) from intersection",
+ p2p->op_reg_class, p2p->op_channel);
+ return;
+ }
+
/*
* Fall back to whatever is included in the channel intersection since
* no better options seems to be available.
@@ -405,6 +462,60 @@
}
+static int p2p_go_select_channel(struct p2p_data *p2p, struct p2p_device *dev,
+ u8 *status)
+{
+ struct p2p_channels intersection;
+ size_t i;
+
+ p2p_channels_intersect(&p2p->channels, &dev->channels, &intersection);
+ if (intersection.reg_classes == 0 ||
+ intersection.reg_class[0].channels == 0) {
+ *status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+ "P2P: No common channels found");
+ return -1;
+ }
+
+ for (i = 0; i < intersection.reg_classes; i++) {
+ struct p2p_reg_class *c;
+ c = &intersection.reg_class[i];
+ wpa_printf(MSG_DEBUG, "P2P: reg_class %u", c->reg_class);
+ wpa_hexdump(MSG_DEBUG, "P2P: channels",
+ c->channel, c->channels);
+ }
+
+ if (!p2p_channels_includes(&intersection, p2p->op_reg_class,
+ p2p->op_channel)) {
+ if (dev->flags & P2P_DEV_FORCE_FREQ) {
+ *status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer does "
+ "not support the forced channel");
+ return -1;
+ }
+
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Selected operating "
+ "channel (op_class %u channel %u) not acceptable to "
+ "the peer", p2p->op_reg_class, p2p->op_channel);
+ p2p_reselect_channel(p2p, &intersection);
+ } else if (!(dev->flags & P2P_DEV_FORCE_FREQ) &&
+ !p2p->cfg->cfg_op_channel) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Try to optimize "
+ "channel selection with peer information received; "
+ "previously selected op_class %u channel %u",
+ p2p->op_reg_class, p2p->op_channel);
+ p2p_reselect_channel(p2p, &intersection);
+ }
+
+ if (!p2p->ssid_set) {
+ p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len);
+ p2p->ssid_set = 1;
+ }
+
+ return 0;
+}
+
+
void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
const u8 *data, size_t len, int rx_freq)
{
@@ -621,36 +732,8 @@
goto fail;
}
- if (go) {
- struct p2p_channels intersection;
- size_t i;
- p2p_channels_intersect(&p2p->channels, &dev->channels,
- &intersection);
- if (intersection.reg_classes == 0 ||
- intersection.reg_class[0].channels == 0) {
- status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No common channels found");
- goto fail;
- }
- for (i = 0; i < intersection.reg_classes; i++) {
- struct p2p_reg_class *c;
- c = &intersection.reg_class[i];
- wpa_printf(MSG_DEBUG, "P2P: reg_class %u",
- c->reg_class);
- wpa_hexdump(MSG_DEBUG, "P2P: channels",
- c->channel, c->channels);
- }
- if (!p2p_channels_includes(&intersection,
- p2p->op_reg_class,
- p2p->op_channel))
- p2p_reselect_channel(p2p, &intersection);
-
- if (!p2p->ssid_set) {
- p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len);
- p2p->ssid_set = 1;
- }
- }
+ if (go && p2p_go_select_channel(p2p, dev, &status) < 0)
+ goto fail;
dev->go_state = go ? LOCAL_GO : REMOTE_GO;
dev->oper_freq = p2p_channel_to_freq((const char *)
@@ -718,7 +801,7 @@
P2P_PENDING_GO_NEG_RESPONSE_FAILURE;
if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
p2p->cfg->dev_addr,
- wpabuf_head(resp), wpabuf_len(resp), 250) < 0) {
+ wpabuf_head(resp), wpabuf_len(resp), 500) < 0) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Failed to send Action frame");
}
@@ -924,10 +1007,8 @@
"P2P: Mandatory P2P Group ID attribute missing from "
"GO Negotiation Response");
p2p->ssid_len = 0;
-#ifdef CONFIG_P2P_STRICT
status = P2P_SC_FAIL_INVALID_PARAMS;
goto fail;
-#endif /* CONFIG_P2P_STRICT */
}
if (!msg.config_timeout) {
@@ -1023,35 +1104,8 @@
goto fail;
}
- if (go) {
- struct p2p_channels intersection;
- size_t i;
- p2p_channels_intersect(&p2p->channels, &dev->channels,
- &intersection);
- if (intersection.reg_classes == 0 ||
- intersection.reg_class[0].channels == 0) {
- status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: No common channels found");
- goto fail;
- }
- for (i = 0; i < intersection.reg_classes; i++) {
- struct p2p_reg_class *c;
- c = &intersection.reg_class[i];
- wpa_printf(MSG_DEBUG, "P2P: reg_class %u",
- c->reg_class);
- wpa_hexdump(MSG_DEBUG, "P2P: channels",
- c->channel, c->channels);
- }
- if (!p2p_channels_includes(&intersection, p2p->op_reg_class,
- p2p->op_channel))
- p2p_reselect_channel(p2p, &intersection);
-
- if (!p2p->ssid_set) {
- p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len);
- p2p->ssid_set = 1;
- }
- }
+ if (go && p2p_go_select_channel(p2p, dev, &status) < 0)
+ goto fail;
p2p_set_state(p2p, P2P_GO_NEG);
p2p_clear_timeout(p2p);
@@ -1084,6 +1138,11 @@
p2p_go_neg_failed(p2p, dev, -1);
}
wpabuf_free(conf);
+ if (status != P2P_SC_SUCCESS) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+ "P2P: GO Negotiation failed");
+ p2p_go_neg_failed(p2p, dev, status);
+ }
}
@@ -1141,6 +1200,7 @@
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: GO Negotiation rejected: status %d",
*msg.status);
+ p2p_go_neg_failed(p2p, dev, *msg.status);
p2p_parse_free(&msg);
return;
}
@@ -1154,10 +1214,9 @@
"P2P: Mandatory P2P Group ID attribute missing from "
"GO Negotiation Confirmation");
p2p->ssid_len = 0;
-#ifdef CONFIG_P2P_STRICT
+ p2p_go_neg_failed(p2p, dev, P2P_SC_FAIL_INVALID_PARAMS);
p2p_parse_free(&msg);
return;
-#endif /* CONFIG_P2P_STRICT */
}
if (!msg.operating_channel) {
diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c
index 8687320..852ddf5 100644
--- a/src/p2p/p2p_group.c
+++ b/src/p2p/p2p_group.c
@@ -169,6 +169,39 @@
}
+static struct wpabuf * p2p_group_encaps_probe_resp(struct wpabuf *subelems)
+{
+ struct wpabuf *ie;
+ const u8 *pos, *end;
+ size_t len;
+
+ if (subelems == NULL)
+ return NULL;
+
+ len = wpabuf_len(subelems) + 100;
+
+ ie = wpabuf_alloc(len);
+ if (ie == NULL)
+ return NULL;
+
+ pos = wpabuf_head(subelems);
+ end = pos + wpabuf_len(subelems);
+
+ while (end > pos) {
+ size_t frag_len = end - pos;
+ if (frag_len > 251)
+ frag_len = 251;
+ wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
+ wpabuf_put_u8(ie, 4 + frag_len);
+ wpabuf_put_be32(ie, P2P_IE_VENDOR_TYPE);
+ wpabuf_put_data(ie, pos, frag_len);
+ pos += frag_len;
+ }
+
+ return ie;
+}
+
+
static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group)
{
struct wpabuf *ie;
@@ -366,44 +399,41 @@
static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group)
{
- u8 *group_info;
- struct wpabuf *ie;
+ struct wpabuf *p2p_subelems, *ie;
struct p2p_group_member *m;
- u8 *len;
- size_t extra = 0;
-#ifdef CONFIG_WIFI_DISPLAY
- if (group->wfd_ie)
- extra += wpabuf_len(group->wfd_ie);
-#endif /* CONFIG_WIFI_DISPLAY */
-
- ie = wpabuf_alloc(257 + extra);
- if (ie == NULL)
+ p2p_subelems = wpabuf_alloc(500);
+ if (p2p_subelems == NULL)
return NULL;
-#ifdef CONFIG_WIFI_DISPLAY
- if (group->wfd_ie)
- wpabuf_put_buf(ie, group->wfd_ie);
-#endif /* CONFIG_WIFI_DISPLAY */
-
- len = p2p_buf_add_ie_hdr(ie);
-
- p2p_group_add_common_ies(group, ie);
- p2p_group_add_noa(ie, group->noa);
+ p2p_group_add_common_ies(group, p2p_subelems);
+ p2p_group_add_noa(p2p_subelems, group->noa);
/* P2P Device Info */
- p2p_buf_add_device_info(ie, group->p2p, NULL);
+ p2p_buf_add_device_info(p2p_subelems, group->p2p, NULL);
- /* P2P Group Info */
- group_info = wpabuf_put(ie, 0);
- wpabuf_put_u8(ie, P2P_ATTR_GROUP_INFO);
- wpabuf_put_le16(ie, 0); /* Length to be filled */
- for (m = group->members; m; m = m->next)
- p2p_client_info(ie, m);
- WPA_PUT_LE16(group_info + 1,
- (u8 *) wpabuf_put(ie, 0) - group_info - 3);
+ /* P2P Group Info: Only when at least one P2P Client is connected */
+ if (group->members) {
+ u8 *group_info;
+ group_info = wpabuf_put(p2p_subelems, 0);
+ wpabuf_put_u8(p2p_subelems, P2P_ATTR_GROUP_INFO);
+ wpabuf_put_le16(p2p_subelems, 0); /* Length to be filled */
+ for (m = group->members; m; m = m->next)
+ p2p_client_info(p2p_subelems, m);
+ WPA_PUT_LE16(group_info + 1,
+ (u8 *) wpabuf_put(p2p_subelems, 0) - group_info -
+ 3);
+ }
- p2p_buf_update_ie_hdr(ie, len);
+ ie = p2p_group_encaps_probe_resp(p2p_subelems);
+ wpabuf_free(p2p_subelems);
+
+#ifdef CONFIG_WIFI_DISPLAY
+ if (group->wfd_ie) {
+ struct wpabuf *wfd = wpabuf_dup(group->wfd_ie);
+ ie = wpabuf_concat(wfd, ie);
+ }
+#endif /* CONFIG_WIFI_DISPLAY */
return ie;
}
@@ -537,6 +567,8 @@
if (group == NULL)
return -1;
+ p2p_add_device(group->p2p, addr, 0, NULL, 0, ie, len, 0);
+
m = os_zalloc(sizeof(*m));
if (m == NULL)
return -1;
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 673c4c1..d5ce52f 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -52,6 +52,7 @@
int go_neg_req_sent;
enum p2p_go_state go_state;
u8 dialog_token;
+ u8 tie_breaker;
u8 intended_addr[ETH_ALEN];
char country[3];
@@ -91,6 +92,7 @@
#define P2P_DEV_REPORTED_ONCE BIT(15)
#define P2P_DEV_PREFER_PERSISTENT_RECONN BIT(16)
#define P2P_DEV_PD_BEFORE_GO_NEG BIT(17)
+#define P2P_DEV_NO_PREF_CHAN BIT(18)
unsigned int flags;
int status; /* enum p2p_status_code */
@@ -226,6 +228,11 @@
int max_disc_int;
/**
+ * max_disc_tu - Maximum number of TUs for discoverable interval
+ */
+ int max_disc_tu;
+
+ /**
* devices - List of known P2P Device peers
*/
struct dl_list devices;
@@ -398,6 +405,8 @@
u8 *find_dev_id;
u8 find_dev_id_buf[ETH_ALEN];
+ struct os_time find_start; /* time of last p2p_find start */
+
struct p2p_group **groups;
size_t num_groups;
@@ -421,6 +430,7 @@
int best_freq_24;
int best_freq_5;
int best_freq_overall;
+ int own_freq_preference;
/**
* wps_vendor_ext - WPS Vendor Extensions to add
@@ -700,8 +710,9 @@
struct p2p_message *msg);
void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr,
struct p2p_device *dev, struct p2p_message *msg);
-int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, int level,
- const u8 *ies, size_t ies_len, int scan_res);
+int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
+ struct os_time *rx_time, int level, const u8 *ies,
+ size_t ies_len, int scan_res);
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);
@@ -717,5 +728,7 @@
const u8 *src, const u8 *bssid, const u8 *buf,
size_t len, unsigned int wait_time);
void p2p_stop_listen_for_freq(struct p2p_data *p2p, int freq);
+int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
+ unsigned int force_freq, unsigned int pref_freq);
#endif /* P2P_I_H */
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index 7bf6600..3beefd2 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -62,8 +62,11 @@
p2p->client_timeout);
p2p_buf_add_invitation_flags(buf, p2p->inv_persistent ?
P2P_INVITATION_FLAGS_TYPE : 0);
- p2p_buf_add_operating_channel(buf, p2p->cfg->country,
- p2p->op_reg_class, p2p->op_channel);
+ if (p2p->inv_role != P2P_INVITE_ROLE_CLIENT ||
+ !(peer->flags & P2P_DEV_NO_PREF_CHAN))
+ p2p_buf_add_operating_channel(buf, p2p->cfg->country,
+ p2p->op_reg_class,
+ p2p->op_channel);
if (p2p->inv_bssid_set)
p2p_buf_add_group_bssid(buf, p2p->inv_bssid);
p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->channels);
@@ -176,8 +179,8 @@
"P2P: Invitation Request from unknown peer "
MACSTR, MAC2STR(sa));
- if (p2p_add_device(p2p, sa, rx_freq, 0, data + 1, len - 1, 0))
- {
+ if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data + 1, len - 1,
+ 0)) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Invitation Request add device failed "
MACSTR, MAC2STR(sa));
@@ -406,6 +409,7 @@
{
struct p2p_device *dev;
struct p2p_message msg;
+ struct p2p_channels intersection, *channels = NULL;
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Received Invitation Response from " MACSTR,
@@ -437,9 +441,32 @@
return;
}
+ if (!msg.channel_list) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+ "P2P: Mandatory Channel List attribute missing in "
+ "Invitation Response from " MACSTR, MAC2STR(sa));
+#ifdef CONFIG_P2P_STRICT
+ p2p_parse_free(&msg);
+ return;
+#endif /* CONFIG_P2P_STRICT */
+ /* Try to survive without peer channel list */
+ channels = &p2p->channels;
+ } else if (p2p_peer_channels_check(p2p, &p2p->channels, dev,
+ msg.channel_list,
+ msg.channel_list_len) < 0) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+ "P2P: No common channels found");
+ p2p_parse_free(&msg);
+ return;
+ } else {
+ p2p_channels_intersect(&p2p->channels, &dev->channels,
+ &intersection);
+ channels = &intersection;
+ }
+
if (p2p->cfg->invitation_result)
p2p->cfg->invitation_result(p2p->cfg->cb_ctx, *msg.status,
- msg.group_bssid);
+ msg.group_bssid, channels, sa);
p2p_parse_free(&msg);
@@ -520,7 +547,13 @@
"P2P: Invitation Response TX callback: success=%d", success);
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
- if (success && p2p->cfg->invitation_received) {
+ if (!success)
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+ "P2P: Assume Invitation Response was actually "
+ "received by the peer even though Ack was not "
+ "reported");
+
+ if (p2p->cfg->invitation_received) {
p2p->cfg->invitation_received(p2p->cfg->cb_ctx,
p2p->inv_sa,
p2p->inv_group_bssid_ptr,
@@ -535,7 +568,7 @@
int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role,
const u8 *bssid, const u8 *ssid, size_t ssid_len,
unsigned int force_freq, const u8 *go_dev_addr,
- int persistent_group)
+ int persistent_group, unsigned int pref_freq)
{
struct p2p_device *dev;
@@ -565,6 +598,15 @@
return -1;
}
+ if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq) < 0)
+ return -1;
+
+ if (persistent_group && role == P2P_INVITE_ROLE_CLIENT && !force_freq &&
+ !pref_freq)
+ dev->flags |= P2P_DEV_NO_PREF_CHAN;
+ else
+ dev->flags &= ~P2P_DEV_NO_PREF_CHAN;
+
if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {
if (!(dev->info.dev_capab &
P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
@@ -578,32 +620,6 @@
dev->invitation_reqs = 0;
- if (force_freq) {
- if (p2p_freq_to_channel(p2p->cfg->country, force_freq,
- &p2p->op_reg_class, &p2p->op_channel) <
- 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
- "P2P: Unsupported frequency %u MHz",
- force_freq);
- return -1;
- }
-#ifdef ANDROID_P2P
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "Single channel list %d", p2p->op_channel);
-#endif
- p2p->channels.reg_classes = 1;
- p2p->channels.reg_class[0].channels = 1;
- p2p->channels.reg_class[0].reg_class = p2p->op_reg_class;
- p2p->channels.reg_class[0].channel[0] = p2p->op_channel;
- } else {
-#ifdef ANDROID_P2P
- wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "Full channel list");
-#endif
- p2p->op_reg_class = p2p->cfg->op_reg_class;
- p2p->op_channel = p2p->cfg->op_channel;
- os_memcpy(&p2p->channels, &p2p->cfg->channels,
- sizeof(struct p2p_channels));
- }
-
if (p2p->state != P2P_IDLE)
p2p_stop_find(p2p);
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index 42447e5..a1268e4 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -19,7 +19,7 @@
* Number of retries to attempt for provision discovery requests
* in case the peer is not listening.
*/
-#define MAX_PROV_DISC_REQ_RETRIES 10
+#define MAX_PROV_DISC_REQ_RETRIES 120
static void p2p_build_wps_ie_config_methods(struct wpabuf *buf,
@@ -151,8 +151,9 @@
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Provision Discovery Request from "
"unknown peer " MACSTR, MAC2STR(sa));
- if (p2p_add_device(p2p, sa, rx_freq, 0, data + 1, len - 1, 0))
- {
+
+ if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data + 1, len - 1,
+ 0)) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Provision Discovery Request add device "
"failed " MACSTR, MAC2STR(sa));
@@ -258,7 +259,7 @@
{
struct p2p_message msg;
struct p2p_device *dev;
- u16 report_config_methods = 0;
+ u16 report_config_methods = 0, req_config_methods;
int success = 0;
if (p2p_parse(data, len, &msg))
@@ -293,6 +294,12 @@
}
/*
+ * Use a local copy of the requested config methods since
+ * p2p_reset_pending_pd() can clear this in the peer entry.
+ */
+ req_config_methods = dev->req_config_methods;
+
+ /*
* If the response is from the peer to whom a user initiated request
* was sent earlier, we reset that state info here.
*/
@@ -300,9 +307,11 @@
os_memcmp(p2p->pending_pd_devaddr, sa, ETH_ALEN) == 0)
p2p_reset_pending_pd(p2p);
- if (msg.wps_config_methods != dev->req_config_methods) {
+ if (msg.wps_config_methods != req_config_methods) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer rejected "
- "our Provision Discovery Request");
+ "our Provision Discovery Request (received "
+ "config_methods 0x%x expected 0x%x",
+ msg.wps_config_methods, req_config_methods);
if (p2p->cfg->prov_disc_fail)
p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
P2P_PROV_DISC_REJECTED);
@@ -310,10 +319,10 @@
goto out;
}
- report_config_methods = dev->req_config_methods;
+ report_config_methods = req_config_methods;
dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
P2P_DEV_PD_PEER_KEYPAD);
- if (dev->req_config_methods & WPS_CONFIG_DISPLAY) {
+ if (req_config_methods & WPS_CONFIG_DISPLAY) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
" accepted to show a PIN on display", MAC2STR(sa));
dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
@@ -345,6 +354,11 @@
if (success && p2p->cfg->prov_disc_resp)
p2p->cfg->prov_disc_resp(p2p->cfg->cb_ctx, sa,
report_config_methods);
+
+ if (p2p->state == P2P_PD_DURING_FIND) {
+ p2p_clear_timeout(p2p);
+ p2p_continue_find(p2p);
+ }
}
@@ -379,9 +393,6 @@
/* TODO: use device discoverability request through GO */
}
- dev->dialog_token++;
- if (dev->dialog_token == 0)
- dev->dialog_token = 1;
req = p2p_build_prov_disc_req(p2p, dev->dialog_token,
dev->req_config_methods,
join ? dev : NULL);
@@ -408,7 +419,8 @@
int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
- u16 config_methods, int join, int force_freq)
+ u16 config_methods, int join, int force_freq,
+ int user_initiated_pd)
{
struct p2p_device *dev;
@@ -446,15 +458,19 @@
return 0;
}
- /*
- * We use the join param as a cue to differentiate between user
- * initiated PD request and one issued during finds (internal).
- */
- p2p->user_initiated_pd = !join;
+ p2p->user_initiated_pd = user_initiated_pd;
if (p2p->user_initiated_pd)
p2p->pd_retries = MAX_PROV_DISC_REQ_RETRIES;
+ /*
+ * Assign dialog token here to use the same value in each retry within
+ * the same PD exchange.
+ */
+ dev->dialog_token++;
+ if (dev->dialog_token == 0)
+ dev->dialog_token = 1;
+
return p2p_send_prov_disc_req(p2p, dev, join, force_freq);
}
diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c
index bcc690d..37b9361 100644
--- a/src/p2p/p2p_utils.c
+++ b/src/p2p/p2p_utils.c
@@ -254,6 +254,23 @@
}
+int p2p_channels_includes_freq(const struct p2p_channels *channels,
+ unsigned int freq)
+{
+ size_t i, j;
+ for (i = 0; i < channels->reg_classes; i++) {
+ const struct p2p_reg_class *reg = &channels->reg_class[i];
+ for (j = 0; j < reg->channels; j++) {
+ if (p2p_channel_to_freq_j4(reg->reg_class,
+ reg->channel[j]) ==
+ (int) freq)
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq)
{
u8 op_reg_class, op_channel;
diff --git a/src/radius/radius.c b/src/radius/radius.c
index d5edfd8..d1feec9 100644
--- a/src/radius/radius.c
+++ b/src/radius/radius.c
@@ -1406,11 +1406,12 @@
* @secret: RADIUS shared secret
* @secret_len: Length of secret
* @sent_msg: Sent RADIUS message
- * Returns: pointer to password (free with os_free) or %NULL
+ * @n: Number of password attribute to return (starting with 0)
+ * Returns: Pointer to n-th password (free with os_free) or %NULL
*/
char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen,
const u8 *secret, size_t secret_len,
- struct radius_msg *sent_msg)
+ struct radius_msg *sent_msg, size_t n)
{
u8 *buf = NULL;
size_t buflen;
@@ -1420,7 +1421,7 @@
size_t len[3];
u8 hash[16];
u8 *pos;
- size_t i;
+ size_t i, j = 0;
struct radius_attr_hdr *attr;
const u8 *data;
size_t dlen;
@@ -1428,7 +1429,7 @@
size_t fdlen = -1;
char *ret = NULL;
- /* find attribute with lowest tag and check it */
+ /* find n-th valid Tunnel-Password attribute */
for (i = 0; i < msg->attr_used; i++) {
attr = radius_get_attr_hdr(msg, i);
if (attr == NULL ||
@@ -1441,11 +1442,13 @@
dlen = attr->length - sizeof(*attr);
if (dlen <= 3 || dlen % 16 != 3)
continue;
- if (fdata != NULL && fdata[0] <= data[0])
+ j++;
+ if (j <= n)
continue;
fdata = data;
fdlen = dlen;
+ break;
}
if (fdata == NULL)
goto out;
diff --git a/src/radius/radius.h b/src/radius/radius.h
index 727640b..2031054 100644
--- a/src/radius/radius.h
+++ b/src/radius/radius.h
@@ -242,7 +242,7 @@
int radius_msg_get_vlanid(struct radius_msg *msg);
char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen,
const u8 *secret, size_t secret_len,
- struct radius_msg *sent_msg);
+ struct radius_msg *sent_msg, size_t n);
static inline int radius_msg_add_attr_int32(struct radius_msg *msg, u8 type,
u32 value)
diff --git a/src/rsn_supp/peerkey.c b/src/rsn_supp/peerkey.c
index f2bac34..789ac25 100644
--- a/src/rsn_supp/peerkey.c
+++ b/src/rsn_supp/peerkey.c
@@ -217,23 +217,17 @@
return -1;
}
- cipher = ie.pairwise_cipher & sm->allowed_pairwise_cipher;
- if (cipher & WPA_CIPHER_CCMP) {
- wpa_printf(MSG_DEBUG, "RSN: Using CCMP for PeerKey");
- cipher = WPA_CIPHER_CCMP;
- } else if (cipher & WPA_CIPHER_GCMP) {
- wpa_printf(MSG_DEBUG, "RSN: Using GCMP for PeerKey");
- cipher = WPA_CIPHER_GCMP;
- } else if (cipher & WPA_CIPHER_TKIP) {
- wpa_printf(MSG_DEBUG, "RSN: Using TKIP for PeerKey");
- cipher = WPA_CIPHER_TKIP;
- } else {
+ cipher = wpa_pick_pairwise_cipher(ie.pairwise_cipher &
+ sm->allowed_pairwise_cipher, 0);
+ if (cipher < 0) {
wpa_printf(MSG_INFO, "RSN: No acceptable cipher in SMK M2");
wpa_supplicant_send_smk_error(sm, src_addr, kde.mac_addr,
STK_MUI_SMK, STK_ERR_CPHR_NS,
ver);
return -1;
}
+ wpa_printf(MSG_DEBUG, "RSN: Using %s for PeerKey",
+ wpa_cipher_txt(cipher));
/* TODO: find existing entry and if found, use that instead of adding
* a new one; how to handle the case where both ends initiate at the
@@ -496,17 +490,9 @@
peerkey->rsnie_p_len = kde->rsn_ie_len;
os_memcpy(peerkey->pnonce, kde->nonce, WPA_NONCE_LEN);
- cipher = ie.pairwise_cipher & sm->allowed_pairwise_cipher;
- if (cipher & WPA_CIPHER_CCMP) {
- wpa_printf(MSG_DEBUG, "RSN: Using CCMP for PeerKey");
- peerkey->cipher = WPA_CIPHER_CCMP;
- } else if (cipher & WPA_CIPHER_GCMP) {
- wpa_printf(MSG_DEBUG, "RSN: Using GCMP for PeerKey");
- peerkey->cipher = WPA_CIPHER_GCMP;
- } else if (cipher & WPA_CIPHER_TKIP) {
- wpa_printf(MSG_DEBUG, "RSN: Using TKIP for PeerKey");
- peerkey->cipher = WPA_CIPHER_TKIP;
- } else {
+ cipher = wpa_pick_pairwise_cipher(ie.pairwise_cipher &
+ sm->allowed_pairwise_cipher, 0);
+ if (cipher < 0) {
wpa_printf(MSG_INFO, "RSN: SMK Peer STA " MACSTR " selected "
"unacceptable cipher", MAC2STR(kde->mac_addr));
wpa_supplicant_send_smk_error(sm, src_addr, kde->mac_addr,
@@ -515,6 +501,9 @@
/* TODO: abort negotiation */
return -1;
}
+ wpa_printf(MSG_DEBUG, "RSN: Using %s for PeerKey",
+ wpa_cipher_txt(cipher));
+ peerkey->cipher = cipher;
return 0;
}
diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c
index 9783e7c..df67583 100644
--- a/src/rsn_supp/pmksa_cache.c
+++ b/src/rsn_supp/pmksa_cache.c
@@ -25,7 +25,7 @@
struct wpa_sm *sm; /* TODO: get rid of this reference(?) */
void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx,
- int replace);
+ enum pmksa_free_reason reason);
void *ctx;
};
@@ -41,11 +41,11 @@
static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
struct rsn_pmksa_cache_entry *entry,
- int replace)
+ enum pmksa_free_reason reason)
{
wpa_sm_remove_pmkid(pmksa->sm, entry->aa, entry->pmkid);
pmksa->pmksa_count--;
- pmksa->free_cb(entry, pmksa->ctx, replace);
+ pmksa->free_cb(entry, pmksa->ctx, reason);
_pmksa_cache_free_entry(entry);
}
@@ -61,7 +61,7 @@
pmksa->pmksa = entry->next;
wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
MACSTR, MAC2STR(entry->aa));
- pmksa_cache_free_entry(pmksa, entry, 0);
+ pmksa_cache_free_entry(pmksa, entry, PMKSA_EXPIRE);
}
pmksa_cache_set_expiration(pmksa);
@@ -164,22 +164,9 @@
pmksa->pmksa = pos->next;
else
prev->next = pos->next;
- if (pos == pmksa->sm->cur_pmksa) {
- /* We are about to replace the current PMKSA
- * cache entry. This happens when the PMKSA
- * caching attempt fails, so we don't want to
- * force pmksa_cache_free_entry() to disconnect
- * at this point. Let's just make sure the old
- * PMKSA cache entry will not be used in the
- * future.
- */
- wpa_printf(MSG_DEBUG, "RSN: replacing current "
- "PMKSA entry");
- pmksa->sm->cur_pmksa = NULL;
- }
wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for "
"the current AP");
- pmksa_cache_free_entry(pmksa, pos, 1);
+ pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE);
/*
* If OKC is used, there may be other PMKSA cache
@@ -214,7 +201,7 @@
"PMKSA cache entry (for " MACSTR ") to "
"make room for new one",
MAC2STR(pos->aa));
- pmksa_cache_free_entry(pmksa, pos, 0);
+ pmksa_cache_free_entry(pmksa, pos, PMKSA_FREE);
}
}
@@ -265,7 +252,7 @@
pmksa->pmksa = entry->next;
tmp = entry;
entry = entry->next;
- pmksa_cache_free_entry(pmksa, tmp, 0);
+ pmksa_cache_free_entry(pmksa, tmp, PMKSA_FREE);
removed++;
} else {
prev = entry;
@@ -507,7 +494,7 @@
*/
struct rsn_pmksa_cache *
pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
- void *ctx, int replace),
+ void *ctx, enum pmksa_free_reason reason),
void *ctx, struct wpa_sm *sm)
{
struct rsn_pmksa_cache *pmksa;
diff --git a/src/rsn_supp/pmksa_cache.h b/src/rsn_supp/pmksa_cache.h
index 9245aab..6f3dfb3 100644
--- a/src/rsn_supp/pmksa_cache.h
+++ b/src/rsn_supp/pmksa_cache.h
@@ -38,11 +38,17 @@
struct rsn_pmksa_cache;
+enum pmksa_free_reason {
+ PMKSA_FREE,
+ PMKSA_REPLACE,
+ PMKSA_EXPIRE,
+};
+
#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
struct rsn_pmksa_cache *
pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
- void *ctx, int replace),
+ void *ctx, enum pmksa_free_reason reason),
void *ctx, struct wpa_sm *sm);
void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa);
struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
@@ -66,7 +72,7 @@
static inline struct rsn_pmksa_cache *
pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
- void *ctx, int replace),
+ void *ctx, enum pmksa_free_reason reason),
void *ctx, struct wpa_sm *sm)
{
return (void *) -1;
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index 7646ca8..8ceaf6c 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -120,6 +120,14 @@
u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
size_t supp_rates_len;
+
+ struct ieee80211_ht_capabilities *ht_capabilities;
+ struct ieee80211_vht_capabilities *vht_capabilities;
+
+ u8 qos_info;
+
+ u8 *ext_capab;
+ size_t ext_capab_len;
};
@@ -611,6 +619,12 @@
peer->initiator = 0;
os_free(peer->sm_tmr.buf);
peer->sm_tmr.buf = NULL;
+ os_free(peer->ht_capabilities);
+ peer->ht_capabilities = NULL;
+ os_free(peer->vht_capabilities);
+ peer->vht_capabilities = NULL;
+ os_free(peer->ext_capab);
+ peer->ext_capab = NULL;
peer->rsnie_i_len = peer->rsnie_p_len = 0;
peer->cipher = 0;
peer->tpk_set = peer->tpk_success = 0;
@@ -680,8 +694,13 @@
return -1;
pos = rbuf;
- if (!wpa_tdls_get_privacy(sm) || !peer->tpk_set || !peer->tpk_success)
+ if (!wpa_tdls_get_privacy(sm) || !peer->tpk_set || !peer->tpk_success) {
+ if (reason_code != WLAN_REASON_DEAUTH_LEAVING) {
+ /* Overwrite the reason code */
+ reason_code = WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED;
+ }
goto skip_ies;
+ }
ftie = (struct wpa_tdls_ftie *) pos;
ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION;
@@ -715,8 +734,7 @@
/* request driver to send Teardown using this FTIE */
wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_TEARDOWN, 0,
- WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, rbuf,
- pos - rbuf);
+ reason_code, rbuf, pos - rbuf);
os_free(rbuf);
/* clear the Peerkey statemachine */
@@ -868,10 +886,20 @@
static struct wpa_tdls_peer *
-wpa_tdls_add_peer(struct wpa_sm *sm, const u8 *addr)
+wpa_tdls_add_peer(struct wpa_sm *sm, const u8 *addr, int *existing)
{
struct wpa_tdls_peer *peer;
+ if (existing)
+ *existing = 0;
+ for (peer = sm->tdls; peer; peer = peer->next) {
+ if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) {
+ if (existing)
+ *existing = 1;
+ return peer; /* re-use existing entry */
+ }
+ }
+
wpa_printf(MSG_INFO, "TDLS: Creating peer entry for " MACSTR,
MAC2STR(addr));
@@ -1282,7 +1310,7 @@
return -1;
}
- peer = wpa_tdls_add_peer(sm, addr);
+ peer = wpa_tdls_add_peer(sm, addr, NULL);
if (peer == NULL)
return -1;
@@ -1309,21 +1337,90 @@
wpa_printf(MSG_DEBUG, "TDLS: No supported rates received");
return -1;
}
+ peer->supp_rates_len = merge_byte_arrays(
+ peer->supp_rates, sizeof(peer->supp_rates),
+ kde->supp_rates + 2, kde->supp_rates_len - 2,
+ kde->ext_supp_rates + 2, kde->ext_supp_rates_len - 2);
+ return 0;
+}
- peer->supp_rates_len = kde->supp_rates_len - 2;
- if (peer->supp_rates_len > IEEE80211_MAX_SUPP_RATES)
- peer->supp_rates_len = IEEE80211_MAX_SUPP_RATES;
- os_memcpy(peer->supp_rates, kde->supp_rates + 2, peer->supp_rates_len);
- if (kde->ext_supp_rates) {
- int clen = kde->ext_supp_rates_len - 2;
- if (peer->supp_rates_len + clen > IEEE80211_MAX_SUPP_RATES)
- clen = IEEE80211_MAX_SUPP_RATES - peer->supp_rates_len;
- os_memcpy(peer->supp_rates + peer->supp_rates_len,
- kde->ext_supp_rates + 2, clen);
- peer->supp_rates_len += clen;
+static int copy_peer_ht_capab(const struct wpa_eapol_ie_parse *kde,
+ struct wpa_tdls_peer *peer)
+{
+ if (!kde->ht_capabilities ||
+ kde->ht_capabilities_len <
+ sizeof(struct ieee80211_ht_capabilities) ) {
+ wpa_printf(MSG_DEBUG, "TDLS: No supported ht capabilities "
+ "received");
+ return 0;
}
+ if (!peer->ht_capabilities) {
+ peer->ht_capabilities =
+ os_zalloc(sizeof(struct ieee80211_ht_capabilities));
+ if (peer->ht_capabilities == NULL)
+ return -1;
+ }
+
+ os_memcpy(peer->ht_capabilities, kde->ht_capabilities,
+ sizeof(struct ieee80211_ht_capabilities));
+ wpa_hexdump(MSG_DEBUG, "TDLS: Peer HT capabilities",
+ (u8 *) peer->ht_capabilities,
+ sizeof(struct ieee80211_ht_capabilities));
+
+ return 0;
+}
+
+
+static int copy_peer_vht_capab(const struct wpa_eapol_ie_parse *kde,
+ struct wpa_tdls_peer *peer)
+{
+ if (!kde->vht_capabilities ||
+ kde->vht_capabilities_len <
+ sizeof(struct ieee80211_vht_capabilities) ) {
+ wpa_printf(MSG_DEBUG, "TDLS: No supported vht capabilities "
+ "received");
+ return 0;
+ }
+
+ if (!peer->vht_capabilities) {
+ peer->vht_capabilities =
+ os_zalloc(sizeof(struct ieee80211_vht_capabilities));
+ if (peer->vht_capabilities == NULL)
+ return -1;
+ }
+
+ os_memcpy(peer->vht_capabilities, kde->vht_capabilities,
+ sizeof(struct ieee80211_vht_capabilities));
+ wpa_hexdump(MSG_DEBUG, "TDLS: Peer VHT capabilities",
+ (u8 *) peer->vht_capabilities,
+ sizeof(struct ieee80211_vht_capabilities));
+
+ return 0;
+}
+
+
+static int copy_peer_ext_capab(const struct wpa_eapol_ie_parse *kde,
+ struct wpa_tdls_peer *peer)
+{
+ if (!kde->ext_capab) {
+ wpa_printf(MSG_DEBUG, "TDLS: No extended capabilities "
+ "received");
+ return 0;
+ }
+
+ if (!peer->ext_capab || peer->ext_capab_len < kde->ext_capab_len - 2) {
+ /* Need to allocate buffer to fit the new information */
+ os_free(peer->ext_capab);
+ peer->ext_capab = os_zalloc(kde->ext_capab_len - 2);
+ if (peer->ext_capab == NULL)
+ return -1;
+ }
+
+ peer->ext_capab_len = kde->ext_capab_len - 2;
+ os_memcpy(peer->ext_capab, kde->ext_capab + 2, peer->ext_capab_len);
+
return 0;
}
@@ -1363,17 +1460,59 @@
wpa_printf(MSG_INFO, "TDLS: Dialog Token in TPK M1 %d", dtoken);
- for (peer = sm->tdls; peer; peer = peer->next) {
- if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0) {
- existing_peer = 1;
- break;
- }
- }
+ peer = wpa_tdls_add_peer(sm, src_addr, &existing_peer);
+ if (peer == NULL)
+ goto error;
- if (peer == NULL) {
- peer = wpa_tdls_add_peer(sm, src_addr);
- if (peer == NULL)
- goto error;
+ /* If found, use existing entry instead of adding a new one;
+ * how to handle the case where both ends initiate at the
+ * same time? */
+ if (existing_peer) {
+ if (peer->tpk_success) {
+ wpa_printf(MSG_DEBUG, "TDLS: TDLS Setup Request while "
+ "direct link is enabled - tear down the "
+ "old link first");
+#if 0
+ /* TODO: Disabling the link would be more proper
+ * operation here, but it seems to trigger a race with
+ * some drivers handling the new request frame. */
+ wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
+#else
+ if (sm->tdls_external_setup)
+ wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK,
+ src_addr);
+ else
+ wpa_tdls_del_key(sm, peer);
+#endif
+ wpa_tdls_peer_free(sm, peer);
+ }
+
+ /*
+ * An entry is already present, so check if we already sent a
+ * TDLS Setup Request. If so, compare MAC addresses and let the
+ * STA with the lower MAC address continue as the initiator.
+ * The other negotiation is terminated.
+ */
+ if (peer->initiator) {
+ if (os_memcmp(sm->own_addr, src_addr, ETH_ALEN) < 0) {
+ wpa_printf(MSG_DEBUG, "TDLS: Discard request "
+ "from peer with higher address "
+ MACSTR, MAC2STR(src_addr));
+ return -1;
+ } else {
+ wpa_printf(MSG_DEBUG, "TDLS: Accept request "
+ "from peer with lower address "
+ MACSTR " (terminate previously "
+ "initiated negotiation",
+ MAC2STR(src_addr));
+ if (sm->tdls_external_setup)
+ wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK,
+ src_addr);
+ else
+ wpa_tdls_del_key(sm, peer);
+ wpa_tdls_peer_free(sm, peer);
+ }
+ }
}
/* capability information */
@@ -1406,17 +1545,22 @@
if (copy_supp_rates(&kde, peer) < 0)
goto error;
+ if (copy_peer_ht_capab(&kde, peer) < 0)
+ goto error;
+
+ if (copy_peer_vht_capab(&kde, peer) < 0)
+ goto error;
+
+ if (copy_peer_ext_capab(&kde, peer) < 0)
+ goto error;
+
+ peer->qos_info = kde.qosinfo;
+
#ifdef CONFIG_TDLS_TESTING
if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) {
- for (peer = sm->tdls; peer; peer = peer->next) {
- if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0)
- break;
- }
- if (peer == NULL) {
- peer = wpa_tdls_add_peer(sm, src_addr);
- if (peer == NULL)
- goto error;
- }
+ peer = wpa_tdls_add_peer(sm, src_addr, NULL);
+ if (peer == NULL)
+ goto error;
wpa_printf(MSG_DEBUG, "TDLS: Testing concurrent initiation of "
"TDLS setup - send own request");
peer->initiator = 1;
@@ -1502,52 +1646,6 @@
}
skip_rsn:
- /* If found, use existing entry instead of adding a new one;
- * how to handle the case where both ends initiate at the
- * same time? */
- if (existing_peer) {
- if (peer->tpk_success) {
- wpa_printf(MSG_DEBUG, "TDLS: TDLS Setup Request while "
- "direct link is enabled - tear down the "
- "old link first");
-#if 0
- /* TODO: Disabling the link would be more proper
- * operation here, but it seems to trigger a race with
- * some drivers handling the new request frame. */
- wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
-#else
- if (sm->tdls_external_setup)
- wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK,
- src_addr);
- else
- wpa_tdls_del_key(sm, peer);
-#endif
- wpa_tdls_peer_free(sm, peer);
- }
-
- /*
- * An entry is already present, so check if we already sent a
- * TDLS Setup Request. If so, compare MAC addresses and let the
- * STA with the lower MAC address continue as the initiator.
- * The other negotiation is terminated.
- */
- if (peer->initiator) {
- if (os_memcmp(sm->own_addr, src_addr, ETH_ALEN) < 0) {
- wpa_printf(MSG_DEBUG, "TDLS: Discard request "
- "from peer with higher address "
- MACSTR, MAC2STR(src_addr));
- return -1;
- } else {
- wpa_printf(MSG_DEBUG, "TDLS: Accept request "
- "from peer with lower address "
- MACSTR " (terminate previously "
- "initiated negotiation",
- MAC2STR(src_addr));
- wpa_tdls_peer_free(sm, peer);
- }
- }
- }
-
#ifdef CONFIG_TDLS_TESTING
if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) {
if (os_memcmp(sm->own_addr, peer->addr, ETH_ALEN) < 0) {
@@ -1635,7 +1733,8 @@
skip_rsn_check:
/* add the peer to the driver as a "setup in progress" peer */
- wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, NULL, 0);
+ wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, NULL, 0, NULL, NULL, 0,
+ NULL, 0);
wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Response / TPK M2");
if (wpa_tdls_send_tpk_m2(sm, src_addr, dtoken, lnkid, peer) < 0) {
@@ -1675,9 +1774,12 @@
#endif /* CONFIG_TDLS_TESTING */
}
- /* add supported rates and capabilities to the TDLS peer */
+ /* add supported rates, capabilities, and qos_info to the TDLS peer */
wpa_sm_tdls_peer_addset(sm, peer->addr, 0, peer->capability,
- peer->supp_rates, peer->supp_rates_len);
+ peer->supp_rates, peer->supp_rates_len,
+ peer->ht_capabilities, peer->vht_capabilities,
+ peer->qos_info, peer->ext_capab,
+ peer->ext_capab_len);
wpa_sm_tdls_oper(sm, TDLS_ENABLE_LINK, peer->addr);
}
@@ -1710,6 +1812,16 @@
"TPK M2: " MACSTR, MAC2STR(src_addr));
return -1;
}
+ if (!peer->initiator) {
+ /*
+ * This may happen if both devices try to initiate TDLS at the
+ * same time and we accept the TPK M1 from the peer in
+ * wpa_tdls_process_tpk_m1() and clear our previous state.
+ */
+ wpa_printf(MSG_INFO, "TDLS: We were not the initiator, so "
+ "ignore TPK M2 from " MACSTR, MAC2STR(src_addr));
+ return -1;
+ }
wpa_tdls_tpk_retry_timeout_cancel(sm, peer, WLAN_TDLS_SETUP_REQUEST);
if (len < 3 + 2 + 1)
@@ -1773,6 +1885,17 @@
if (copy_supp_rates(&kde, peer) < 0)
goto error;
+ if (copy_peer_ht_capab(&kde, peer) < 0)
+ goto error;
+
+ if (copy_peer_vht_capab(&kde, peer) < 0)
+ goto error;
+
+ if (copy_peer_ext_capab(&kde, peer) < 0)
+ goto error;
+
+ peer->qos_info = kde.qosinfo;
+
if (!wpa_tdls_get_privacy(sm)) {
peer->rsnie_p_len = 0;
peer->cipher = WPA_CIPHER_NONE;
@@ -2069,23 +2192,15 @@
return -1;
}
- /* Find existing entry and if found, use that instead of adding
- * a new one */
- for (peer = sm->tdls; peer; peer = peer->next) {
- if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
- break;
- }
-
- if (peer == NULL) {
- peer = wpa_tdls_add_peer(sm, addr);
- if (peer == NULL)
- return -1;
- }
+ peer = wpa_tdls_add_peer(sm, addr, NULL);
+ if (peer == NULL)
+ return -1;
peer->initiator = 1;
/* add the peer to the driver as a "setup in progress" peer */
- wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, NULL, 0);
+ wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, NULL, 0, NULL, NULL, 0,
+ NULL, 0);
if (wpa_tdls_send_tpk_m1(sm, peer) < 0) {
wpa_tdls_disable_link(sm, peer->addr);
@@ -2096,12 +2211,12 @@
}
-int wpa_tdls_reneg(struct wpa_sm *sm, const u8 *addr)
+void wpa_tdls_remove(struct wpa_sm *sm, const u8 *addr)
{
struct wpa_tdls_peer *peer;
if (sm->tdls_disabled || !sm->tdls_supported)
- return -1;
+ return;
for (peer = sm->tdls; peer; peer = peer->next) {
if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
@@ -2109,7 +2224,7 @@
}
if (peer == NULL || !peer->tpk_success)
- return -1;
+ return;
if (sm->tdls_external_setup) {
/*
@@ -2118,8 +2233,6 @@
*/
wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
}
-
- return wpa_tdls_start(sm, addr);
}
@@ -2232,6 +2345,28 @@
}
+void wpa_tdls_teardown_peers(struct wpa_sm *sm)
+{
+ struct wpa_tdls_peer *peer;
+
+ peer = sm->tdls;
+
+ wpa_printf(MSG_DEBUG, "TDLS: Tear down peers");
+
+ while (peer) {
+ wpa_printf(MSG_DEBUG, "TDLS: Tear down peer " MACSTR,
+ MAC2STR(peer->addr));
+ if (sm->tdls_external_setup)
+ wpa_tdls_send_teardown(sm, peer->addr,
+ WLAN_REASON_DEAUTH_LEAVING);
+ else
+ wpa_sm_tdls_oper(sm, TDLS_TEARDOWN, peer->addr);
+
+ peer = peer->next;
+ }
+}
+
+
static void wpa_tdls_remove_peers(struct wpa_sm *sm)
{
struct wpa_tdls_peer *peer, *tmp;
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 5cf32df..e50404c 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -783,7 +783,7 @@
rsn_ie, rsn_ie_len);
}
- wpa_sm_disassociate(sm, WLAN_REASON_IE_IN_4WAY_DIFFERS);
+ wpa_sm_deauthenticate(sm, WLAN_REASON_IE_IN_4WAY_DIFFERS);
}
@@ -1836,6 +1836,10 @@
case WPA_KEY_MGMT_PSK_SHA256:
return RSN_AUTH_KEY_MGMT_PSK_SHA256;
#endif /* CONFIG_IEEE80211W */
+ case WPA_KEY_MGMT_CCKM:
+ return (sm->proto == WPA_PROTO_RSN ?
+ RSN_AUTH_KEY_MGMT_CCKM:
+ WPA_AUTH_KEY_MGMT_CCKM);
case WPA_KEY_MGMT_WPA_NONE:
return WPA_AUTH_KEY_MGMT_NONE;
default:
@@ -1931,25 +1935,40 @@
static void wpa_sm_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry,
- void *ctx, int replace)
+ void *ctx, enum pmksa_free_reason reason)
{
struct wpa_sm *sm = ctx;
+ int deauth = 0;
- if (sm->cur_pmksa == entry ||
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA cache entry free_cb: "
+ MACSTR " reason=%d", MAC2STR(entry->aa), reason);
+
+ if (sm->cur_pmksa == entry) {
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "RSN: %s current PMKSA entry",
+ reason == PMKSA_REPLACE ? "replaced" : "removed");
+ pmksa_cache_clear_current(sm);
+
+ /*
+ * If an entry is simply being replaced, there's no need to
+ * deauthenticate because it will be immediately re-added.
+ * This happens when EAP authentication is completed again
+ * (reauth or failed PMKSA caching attempt).
+ */
+ if (reason != PMKSA_REPLACE)
+ deauth = 1;
+ }
+
+ if (reason == PMKSA_EXPIRE &&
(sm->pmk_len == entry->pmk_len &&
os_memcmp(sm->pmk, entry->pmk, sm->pmk_len) == 0)) {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
- "RSN: removed current PMKSA entry");
- sm->cur_pmksa = NULL;
+ "RSN: deauthenticating due to expired PMK");
+ pmksa_cache_clear_current(sm);
+ deauth = 1;
+ }
- if (replace) {
- /* A new entry is being added, so no need to
- * deauthenticate in this case. This happens when EAP
- * authentication is completed again (reauth or failed
- * PMKSA caching attempt). */
- return;
- }
-
+ if (deauth) {
os_memset(sm->pmk, 0, sizeof(sm->pmk));
wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
}
@@ -2080,6 +2099,7 @@
void wpa_sm_notify_disassoc(struct wpa_sm *sm)
{
rsn_preauth_deinit(sm);
+ pmksa_cache_clear_current(sm);
if (wpa_sm_get_state(sm) == WPA_4WAY_HANDSHAKE)
sm->dot11RSNA4WayHandshakeFailures++;
#ifdef CONFIG_TDLS
@@ -2372,6 +2392,22 @@
if (ret < 0 || ret >= end - pos)
return pos - buf;
pos += ret;
+
+ if (sm->mfp != NO_MGMT_FRAME_PROTECTION && sm->ap_rsn_ie) {
+ struct wpa_ie_data rsn;
+ if (wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &rsn)
+ >= 0 &&
+ rsn.capabilities & (WPA_CAPABILITY_MFPR |
+ WPA_CAPABILITY_MFPC)) {
+ ret = os_snprintf(pos, end - pos, "pmf=%d\n",
+ (rsn.capabilities &
+ WPA_CAPABILITY_MFPR) ? 2 : 1);
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
+ }
+
return pos - buf;
}
@@ -2591,7 +2627,7 @@
}
-#ifdef CONFIG_IEEE80211V
+#ifdef CONFIG_WNM
int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
{
struct wpa_gtk_data gd;
@@ -2601,7 +2637,6 @@
#endif /* CONFIG_IEEE80211W */
u16 keyinfo;
u8 keylen; /* plaintext key len */
- u8 keydatalen;
u8 *key_rsc;
os_memset(&gd, 0, sizeof(gd));
@@ -2619,8 +2654,7 @@
if (subelem_id == WNM_SLEEP_SUBELEM_GTK) {
key_rsc = buf + 5;
- keyinfo = WPA_GET_LE16(buf+2);
- keydatalen = buf[1] - 11 - 8;
+ keyinfo = WPA_GET_LE16(buf + 2);
gd.gtk_len = keylen;
if (gd.gtk_len != buf[4]) {
wpa_printf(MSG_DEBUG, "GTK len mismatch len %d vs %d",
@@ -2631,18 +2665,7 @@
gd.tx = wpa_supplicant_gtk_tx_bit_workaround(
sm, !!(keyinfo & WPA_KEY_INFO_TXRX));
- if (keydatalen % 8) {
- wpa_printf(MSG_DEBUG, "WPA: Unsupported AES-WRAP len "
- "%d", keydatalen);
- return -1;
- }
-
- if (aes_unwrap(sm->ptk.kek, keydatalen / 8, buf + 13, gd.gtk))
- {
- wpa_printf(MSG_WARNING, "WNM: AES unwrap failed - "
- "could not decrypt GTK");
- return -1;
- }
+ os_memcpy(gd.gtk, buf + 13, gd.gtk_len);
wpa_hexdump_key(MSG_DEBUG, "Install GTK (WNM SLEEP)",
gd.gtk, gd.gtk_len);
@@ -2653,22 +2676,11 @@
}
#ifdef CONFIG_IEEE80211W
} else if (subelem_id == WNM_SLEEP_SUBELEM_IGTK) {
- if (buf[1] != 2 + 6 + WPA_IGTK_LEN + 8) {
- wpa_printf(MSG_DEBUG, "WPA: Unsupported AES-WRAP len "
- "%d", buf[1] - 2 - 6 - 8);
- return -1;
- }
os_memcpy(igd.keyid, buf + 2, 2);
os_memcpy(igd.pn, buf + 4, 6);
keyidx = WPA_GET_LE16(igd.keyid);
-
- if (aes_unwrap(sm->ptk.kek, WPA_IGTK_LEN / 8, buf + 10,
- igd.igtk)) {
- wpa_printf(MSG_WARNING, "WNM: AES unwrap failed - "
- "could not decrypr IGTK");
- return -1;
- }
+ os_memcpy(igd.igtk, buf + 10, WPA_IGTK_LEN);
wpa_hexdump_key(MSG_DEBUG, "Install IGTK (WNM SLEEP)",
igd.igtk, WPA_IGTK_LEN);
@@ -2687,4 +2699,4 @@
return 0;
}
-#endif /* CONFIG_IEEE80211V */
+#endif /* CONFIG_WNM */
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 1077b5a..dbb493e 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -12,6 +12,7 @@
#include "common/defs.h"
#include "common/eapol_common.h"
#include "common/wpa_common.h"
+#include "common/ieee802_11_defs.h"
struct wpa_sm;
struct eapol_sm;
@@ -24,7 +25,6 @@
void (*set_state)(void *ctx, enum wpa_states state);
enum wpa_states (*get_state)(void *ctx);
void (*deauthenticate)(void * ctx, int reason_code);
- void (*disassociate)(void *ctx, int reason_code);
int (*set_key)(void *ctx, enum wpa_alg alg,
const u8 *addr, int key_idx, int set_tx,
const u8 *seq, size_t seq_len,
@@ -58,7 +58,11 @@
int (*tdls_oper)(void *ctx, int oper, const u8 *peer);
int (*tdls_peer_addset)(void *ctx, const u8 *addr, int add,
u16 capability, const u8 *supp_rates,
- size_t supp_rates_len);
+ size_t supp_rates_len,
+ const struct ieee80211_ht_capabilities *ht_capab,
+ const struct ieee80211_vht_capabilities *vht_capab,
+ u8 qosinfo, const u8 *ext_capab,
+ size_t ext_capab_len);
#endif /* CONFIG_TDLS */
void (*set_rekey_offload)(void *ctx, const u8 *kek, const u8 *kck,
const u8 *replay_ctr);
@@ -356,18 +360,17 @@
void wpa_tdls_ap_ies(struct wpa_sm *sm, const u8 *ies, size_t len);
void wpa_tdls_assoc_resp_ies(struct wpa_sm *sm, const u8 *ies, size_t len);
int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr);
-int wpa_tdls_reneg(struct wpa_sm *sm, const u8 *addr);
+void wpa_tdls_remove(struct wpa_sm *sm, const u8 *addr);
int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr, u16 reason_code);
int wpa_tdls_teardown_link(struct wpa_sm *sm, const u8 *addr, u16 reason_code);
int wpa_tdls_send_discovery_request(struct wpa_sm *sm, const u8 *addr);
int wpa_tdls_init(struct wpa_sm *sm);
+void wpa_tdls_teardown_peers(struct wpa_sm *sm);
void wpa_tdls_deinit(struct wpa_sm *sm);
void wpa_tdls_enable(struct wpa_sm *sm, int enabled);
void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr);
int wpa_tdls_is_external_setup(struct wpa_sm *sm);
-#ifdef CONFIG_IEEE80211V
int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf);
-#endif /* CONFIG_IEEE80211V */
#endif /* WPA_H */
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index 2df060c..4b08a62 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -788,9 +788,12 @@
if (parse.ric) {
wpa_hexdump(MSG_MSGDUMP, "FT: RIC Response",
parse.ric, parse.ric_len);
- /* TODO: parse response and inform driver about results */
+ /* TODO: parse response and inform driver about results when
+ * using wpa_supplicant SME */
}
+ wpa_printf(MSG_DEBUG, "FT: Completed successfully");
+
return 0;
}
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index c30d09e..877e6de 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -143,12 +143,6 @@
sm->ctx->deauthenticate(sm->ctx->ctx, reason_code);
}
-static inline void wpa_sm_disassociate(struct wpa_sm *sm, int reason_code)
-{
- WPA_ASSERT(sm->ctx->disassociate);
- sm->ctx->disassociate(sm->ctx->ctx, reason_code);
-}
-
static inline int wpa_sm_set_key(struct wpa_sm *sm, enum wpa_alg alg,
const u8 *addr, int key_idx, int set_tx,
const u8 *seq, size_t seq_len,
@@ -289,12 +283,17 @@
static inline int
wpa_sm_tdls_peer_addset(struct wpa_sm *sm, const u8 *addr, int add,
u16 capability, const u8 *supp_rates,
- size_t supp_rates_len)
+ size_t supp_rates_len,
+ const struct ieee80211_ht_capabilities *ht_capab,
+ const struct ieee80211_vht_capabilities *vht_capab,
+ u8 qosinfo, const u8 *ext_capab, size_t ext_capab_len)
{
if (sm->ctx->tdls_peer_addset)
return sm->ctx->tdls_peer_addset(sm->ctx->ctx, addr, add,
capability, supp_rates,
- supp_rates_len);
+ supp_rates_len, ht_capab,
+ vht_capab, qosinfo,
+ ext_capab, ext_capab_len);
return -1;
}
#endif /* CONFIG_TDLS */
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index 6a8f9f1..652197f 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -83,6 +83,8 @@
RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X);
} else if (key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_NONE);
+ } else if (key_mgmt == WPA_KEY_MGMT_CCKM) {
+ RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_CCKM);
} else {
wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
key_mgmt);
@@ -152,6 +154,8 @@
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X);
} else if (key_mgmt == WPA_KEY_MGMT_PSK) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X);
+ } else if (key_mgmt == WPA_KEY_MGMT_CCKM) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_CCKM);
#ifdef CONFIG_IEEE80211R
} else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
@@ -164,6 +168,12 @@
} else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+ } else if (key_mgmt == WPA_KEY_MGMT_SAE) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
+ } else if (key_mgmt == WPA_KEY_MGMT_FT_SAE) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
+#endif /* CONFIG_SAE */
} else {
wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
key_mgmt);
@@ -417,6 +427,14 @@
} else if (*pos == WLAN_EID_EXT_SUPP_RATES) {
ie->ext_supp_rates = pos;
ie->ext_supp_rates_len = pos[1] + 2;
+ } else if (*pos == WLAN_EID_HT_CAP) {
+ ie->ht_capabilities = pos + 2;
+ ie->ht_capabilities_len = pos[1];
+ } else if (*pos == WLAN_EID_VHT_CAP) {
+ ie->vht_capabilities = pos + 2;
+ ie->vht_capabilities_len = pos[1];
+ } else if (*pos == WLAN_EID_QOS && pos[1] >= 1) {
+ ie->qosinfo = pos[2];
} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
ret = wpa_parse_generic(pos, end, ie);
if (ret < 0)
diff --git a/src/rsn_supp/wpa_ie.h b/src/rsn_supp/wpa_ie.h
index 5afdfe9..82a5c08 100644
--- a/src/rsn_supp/wpa_ie.h
+++ b/src/rsn_supp/wpa_ie.h
@@ -49,6 +49,11 @@
size_t supp_rates_len;
const u8 *ext_supp_rates;
size_t ext_supp_rates_len;
+ const u8 *ht_capabilities;
+ size_t ht_capabilities_len;
+ const u8 *vht_capabilities;
+ size_t vht_capabilities_len;
+ u8 qosinfo;
};
int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
diff --git a/src/tls/libtommath.c b/src/tls/libtommath.c
index 741b442..3fb8fbe 100644
--- a/src/tls/libtommath.c
+++ b/src/tls/libtommath.c
@@ -42,6 +42,9 @@
/* Include faster sqr at the cost of about 0.5 kB in code */
#define BN_FAST_S_MP_SQR_C
+/* About 0.25 kB of code, but ~1.7kB of stack space! */
+#define BN_FAST_S_MP_MUL_DIGS_C
+
#else /* LTM_FAST */
#define BN_MP_DIV_SMALL
@@ -139,7 +142,9 @@
static int s_mp_sqr(mp_int * a, mp_int * b);
static int s_mp_mul_high_digs(mp_int * a, mp_int * b, mp_int * c, int digs);
+#ifdef BN_FAST_S_MP_MUL_DIGS_C
static int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
+#endif
#ifdef BN_MP_INIT_MULTI_C
static int mp_init_multi(mp_int *mp, ...);
@@ -671,6 +676,9 @@
#ifdef BN_MP_EXPTMOD_FAST_C
}
#endif
+ if (dr == 0) {
+ /* avoid compiler warnings about possibly unused variable */
+ }
}
@@ -2339,12 +2347,14 @@
mp_word r;
mp_digit tmpx, *tmpt, *tmpy;
+#ifdef BN_FAST_S_MP_MUL_DIGS_C
/* can we use the fast multiplier? */
if (((digs) < MP_WARRAY) &&
MIN (a->used, b->used) <
(1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
return fast_s_mp_mul_digs (a, b, c, digs);
}
+#endif
if ((res = mp_init_size (&t, digs)) != MP_OKAY) {
return res;
@@ -2397,6 +2407,7 @@
}
+#ifdef BN_FAST_S_MP_MUL_DIGS_C
/* Fast (comba) multiplier
*
* This is the fast column-array [comba] multiplier. It is
@@ -2482,6 +2493,7 @@
mp_clamp (c);
return MP_OKAY;
}
+#endif /* BN_FAST_S_MP_MUL_DIGS_C */
/* init an mp_init for a given size */
diff --git a/src/utils/common.h b/src/utils/common.h
index 5fc916c..a859042 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -224,69 +224,105 @@
/* Macros for handling unaligned memory accesses */
-#define WPA_GET_BE16(a) ((u16) (((a)[0] << 8) | (a)[1]))
-#define WPA_PUT_BE16(a, val) \
- do { \
- (a)[0] = ((u16) (val)) >> 8; \
- (a)[1] = ((u16) (val)) & 0xff; \
- } while (0)
+static inline u16 WPA_GET_BE16(const u8 *a)
+{
+ return (a[0] << 8) | a[1];
+}
-#define WPA_GET_LE16(a) ((u16) (((a)[1] << 8) | (a)[0]))
-#define WPA_PUT_LE16(a, val) \
- do { \
- (a)[1] = ((u16) (val)) >> 8; \
- (a)[0] = ((u16) (val)) & 0xff; \
- } while (0)
+static inline void WPA_PUT_BE16(u8 *a, u16 val)
+{
+ a[0] = val >> 8;
+ a[1] = val & 0xff;
+}
-#define WPA_GET_BE24(a) ((((u32) (a)[0]) << 16) | (((u32) (a)[1]) << 8) | \
- ((u32) (a)[2]))
-#define WPA_PUT_BE24(a, val) \
- do { \
- (a)[0] = (u8) ((((u32) (val)) >> 16) & 0xff); \
- (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \
- (a)[2] = (u8) (((u32) (val)) & 0xff); \
- } while (0)
+static inline u16 WPA_GET_LE16(const u8 *a)
+{
+ return (a[1] << 8) | a[0];
+}
-#define WPA_GET_BE32(a) ((((u32) (a)[0]) << 24) | (((u32) (a)[1]) << 16) | \
- (((u32) (a)[2]) << 8) | ((u32) (a)[3]))
-#define WPA_PUT_BE32(a, val) \
- do { \
- (a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff); \
- (a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff); \
- (a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff); \
- (a)[3] = (u8) (((u32) (val)) & 0xff); \
- } while (0)
+static inline void WPA_PUT_LE16(u8 *a, u16 val)
+{
+ a[1] = val >> 8;
+ a[0] = val & 0xff;
+}
-#define WPA_GET_LE32(a) ((((u32) (a)[3]) << 24) | (((u32) (a)[2]) << 16) | \
- (((u32) (a)[1]) << 8) | ((u32) (a)[0]))
-#define WPA_PUT_LE32(a, val) \
- do { \
- (a)[3] = (u8) ((((u32) (val)) >> 24) & 0xff); \
- (a)[2] = (u8) ((((u32) (val)) >> 16) & 0xff); \
- (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \
- (a)[0] = (u8) (((u32) (val)) & 0xff); \
- } while (0)
+static inline u32 WPA_GET_BE24(const u8 *a)
+{
+ return (a[0] << 16) | (a[1] << 8) | a[2];
+}
-#define WPA_GET_BE64(a) ((((u64) (a)[0]) << 56) | (((u64) (a)[1]) << 48) | \
- (((u64) (a)[2]) << 40) | (((u64) (a)[3]) << 32) | \
- (((u64) (a)[4]) << 24) | (((u64) (a)[5]) << 16) | \
- (((u64) (a)[6]) << 8) | ((u64) (a)[7]))
-#define WPA_PUT_BE64(a, val) \
- do { \
- (a)[0] = (u8) (((u64) (val)) >> 56); \
- (a)[1] = (u8) (((u64) (val)) >> 48); \
- (a)[2] = (u8) (((u64) (val)) >> 40); \
- (a)[3] = (u8) (((u64) (val)) >> 32); \
- (a)[4] = (u8) (((u64) (val)) >> 24); \
- (a)[5] = (u8) (((u64) (val)) >> 16); \
- (a)[6] = (u8) (((u64) (val)) >> 8); \
- (a)[7] = (u8) (((u64) (val)) & 0xff); \
- } while (0)
+static inline void WPA_PUT_BE24(u8 *a, u32 val)
+{
+ a[0] = (val >> 16) & 0xff;
+ a[1] = (val >> 8) & 0xff;
+ a[2] = val & 0xff;
+}
-#define WPA_GET_LE64(a) ((((u64) (a)[7]) << 56) | (((u64) (a)[6]) << 48) | \
- (((u64) (a)[5]) << 40) | (((u64) (a)[4]) << 32) | \
- (((u64) (a)[3]) << 24) | (((u64) (a)[2]) << 16) | \
- (((u64) (a)[1]) << 8) | ((u64) (a)[0]))
+static inline u32 WPA_GET_BE32(const u8 *a)
+{
+ return (a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3];
+}
+
+static inline void WPA_PUT_BE32(u8 *a, u32 val)
+{
+ a[0] = (val >> 24) & 0xff;
+ a[1] = (val >> 16) & 0xff;
+ a[2] = (val >> 8) & 0xff;
+ a[3] = val & 0xff;
+}
+
+static inline u32 WPA_GET_LE32(const u8 *a)
+{
+ return (a[3] << 24) | (a[2] << 16) | (a[1] << 8) | a[0];
+}
+
+static inline void WPA_PUT_LE32(u8 *a, u32 val)
+{
+ a[3] = (val >> 24) & 0xff;
+ a[2] = (val >> 16) & 0xff;
+ a[1] = (val >> 8) & 0xff;
+ a[0] = val & 0xff;
+}
+
+static inline u64 WPA_GET_BE64(const u8 *a)
+{
+ return (((u64) a[0]) << 56) | (((u64) a[1]) << 48) |
+ (((u64) a[2]) << 40) | (((u64) a[3]) << 32) |
+ (((u64) a[4]) << 24) | (((u64) a[5]) << 16) |
+ (((u64) a[6]) << 8) | ((u64) a[7]);
+}
+
+static inline void WPA_PUT_BE64(u8 *a, u64 val)
+{
+ a[0] = val >> 56;
+ a[1] = val >> 48;
+ a[2] = val >> 40;
+ a[3] = val >> 32;
+ a[4] = val >> 24;
+ a[5] = val >> 16;
+ a[6] = val >> 8;
+ a[7] = val & 0xff;
+}
+
+static inline u64 WPA_GET_LE64(const u8 *a)
+{
+ return (((u64) a[7]) << 56) | (((u64) a[6]) << 48) |
+ (((u64) a[5]) << 40) | (((u64) a[4]) << 32) |
+ (((u64) a[3]) << 24) | (((u64) a[2]) << 16) |
+ (((u64) a[1]) << 8) | ((u64) a[0]);
+}
+
+static inline void WPA_PUT_LE64(u8 *a, u64 val)
+{
+ a[7] = val >> 56;
+ a[6] = val >> 48;
+ a[5] = val >> 40;
+ a[4] = val >> 32;
+ a[3] = val >> 24;
+ a[2] = val >> 16;
+ a[1] = val >> 8;
+ a[0] = val & 0xff;
+}
#ifndef ETH_ALEN
diff --git a/src/utils/eloop.c b/src/utils/eloop.c
index d01ae64..2de3e01 100644
--- a/src/utils/eloop.c
+++ b/src/utils/eloop.c
@@ -556,6 +556,33 @@
}
+int eloop_cancel_timeout_one(eloop_timeout_handler handler,
+ void *eloop_data, void *user_data,
+ struct os_time *remaining)
+{
+ struct eloop_timeout *timeout, *prev;
+ int removed = 0;
+ struct os_time now;
+
+ os_get_time(&now);
+ remaining->sec = remaining->usec = 0;
+
+ dl_list_for_each_safe(timeout, prev, &eloop.timeout,
+ struct eloop_timeout, list) {
+ if (timeout->handler == handler &&
+ (timeout->eloop_data == eloop_data) &&
+ (timeout->user_data == user_data)) {
+ removed = 1;
+ if (os_time_before(&now, &timeout->time))
+ os_time_sub(&timeout->time, &now, remaining);
+ eloop_remove_timeout(timeout);
+ break;
+ }
+ }
+ return removed;
+}
+
+
int eloop_is_timeout_registered(eloop_timeout_handler handler,
void *eloop_data, void *user_data)
{
diff --git a/src/utils/eloop.h b/src/utils/eloop.h
index db03a73..0037c63 100644
--- a/src/utils/eloop.h
+++ b/src/utils/eloop.h
@@ -195,6 +195,21 @@
void *eloop_data, void *user_data);
/**
+ * eloop_cancel_timeout_one - Cancel a single timeout
+ * @handler: Matching callback function
+ * @eloop_data: Matching eloop_data
+ * @user_data: Matching user_data
+ * @remaining: Time left on the cancelled timer
+ * Returns: Number of cancelled timeouts
+ *
+ * Cancel matching <handler,eloop_data,user_data> timeout registered with
+ * eloop_register_timeout() and return the remaining time left.
+ */
+int eloop_cancel_timeout_one(eloop_timeout_handler handler,
+ void *eloop_data, void *user_data,
+ struct os_time *remaining);
+
+/**
* eloop_is_timeout_registered - Check if a timeout is already registered
* @handler: Matching callback function
* @eloop_data: Matching eloop_data
diff --git a/src/utils/eloop_none.c b/src/utils/eloop_none.c
index c67ece4..cb5e922 100644
--- a/src/utils/eloop_none.c
+++ b/src/utils/eloop_none.c
@@ -1,6 +1,6 @@
/*
* Event loop - empty template (basic structure, but no OS specific operations)
- * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -9,6 +9,7 @@
#include "includes.h"
#include "common.h"
+#include "list.h"
#include "eloop.h"
@@ -16,21 +17,21 @@
int sock;
void *eloop_data;
void *user_data;
- void (*handler)(int sock, void *eloop_ctx, void *sock_ctx);
+ eloop_sock_handler handler;
};
struct eloop_timeout {
+ struct dl_list list;
struct os_time time;
void *eloop_data;
void *user_data;
- void (*handler)(void *eloop_ctx, void *sock_ctx);
- struct eloop_timeout *next;
+ eloop_timeout_handler handler;
};
struct eloop_signal {
int sig;
void *user_data;
- void (*handler)(int sig, void *eloop_ctx, void *signal_ctx);
+ eloop_signal_handler handler;
int signaled;
};
@@ -38,7 +39,7 @@
int max_sock, reader_count;
struct eloop_sock *readers;
- struct eloop_timeout *timeout;
+ struct dl_list timeout;
int signal_count;
struct eloop_signal *signals;
@@ -54,21 +55,19 @@
int eloop_init(void)
{
- memset(&eloop, 0, sizeof(eloop));
+ os_memset(&eloop, 0, sizeof(eloop));
+ dl_list_init(&eloop.timeout);
return 0;
}
-int eloop_register_read_sock(int sock,
- void (*handler)(int sock, void *eloop_ctx,
- void *sock_ctx),
+int eloop_register_read_sock(int sock, eloop_sock_handler handler,
void *eloop_data, void *user_data)
{
struct eloop_sock *tmp;
- tmp = (struct eloop_sock *)
- realloc(eloop.readers,
- (eloop.reader_count + 1) * sizeof(struct eloop_sock));
+ tmp = os_realloc_array(eloop.readers, eloop.reader_count + 1,
+ sizeof(struct eloop_sock));
if (tmp == NULL)
return -1;
@@ -100,9 +99,9 @@
if (i == eloop.reader_count)
return;
if (i != eloop.reader_count - 1) {
- memmove(&eloop.readers[i], &eloop.readers[i + 1],
- (eloop.reader_count - i - 1) *
- sizeof(struct eloop_sock));
+ os_memmove(&eloop.readers[i], &eloop.readers[i + 1],
+ (eloop.reader_count - i - 1) *
+ sizeof(struct eloop_sock));
}
eloop.reader_count--;
eloop.reader_table_changed = 1;
@@ -110,16 +109,31 @@
int eloop_register_timeout(unsigned int secs, unsigned int usecs,
- void (*handler)(void *eloop_ctx, void *timeout_ctx),
+ eloop_timeout_handler handler,
void *eloop_data, void *user_data)
{
- struct eloop_timeout *timeout, *tmp, *prev;
+ struct eloop_timeout *timeout, *tmp;
+ os_time_t now_sec;
- timeout = (struct eloop_timeout *) malloc(sizeof(*timeout));
+ timeout = os_zalloc(sizeof(*timeout));
if (timeout == NULL)
return -1;
- os_get_time(&timeout->time);
+ if (os_get_time(&timeout->time) < 0) {
+ os_free(timeout);
+ return -1;
+ }
+ now_sec = timeout->time.sec;
timeout->time.sec += secs;
+ if (timeout->time.sec < now_sec) {
+ /*
+ * Integer overflow - assume long enough timeout to be assumed
+ * to be infinite, i.e., the timeout would never happen.
+ */
+ wpa_printf(MSG_DEBUG, "ELOOP: Too long timeout (secs=%u) to "
+ "ever happen - ignore it", secs);
+ os_free(timeout);
+ return 0;
+ }
timeout->time.usec += usecs;
while (timeout->time.usec >= 1000000) {
timeout->time.sec++;
@@ -128,80 +142,86 @@
timeout->eloop_data = eloop_data;
timeout->user_data = user_data;
timeout->handler = handler;
- timeout->next = NULL;
- if (eloop.timeout == NULL) {
- eloop.timeout = timeout;
- return 0;
+ /* Maintain timeouts in order of increasing time */
+ dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
+ if (os_time_before(&timeout->time, &tmp->time)) {
+ dl_list_add(tmp->list.prev, &timeout->list);
+ return 0;
+ }
}
-
- prev = NULL;
- tmp = eloop.timeout;
- while (tmp != NULL) {
- if (os_time_before(&timeout->time, &tmp->time))
- break;
- prev = tmp;
- tmp = tmp->next;
- }
-
- if (prev == NULL) {
- timeout->next = eloop.timeout;
- eloop.timeout = timeout;
- } else {
- timeout->next = prev->next;
- prev->next = timeout;
- }
+ dl_list_add_tail(&eloop.timeout, &timeout->list);
return 0;
}
-int eloop_cancel_timeout(void (*handler)(void *eloop_ctx, void *sock_ctx),
+static void eloop_remove_timeout(struct eloop_timeout *timeout)
+{
+ dl_list_del(&timeout->list);
+ os_free(timeout);
+}
+
+
+int eloop_cancel_timeout(eloop_timeout_handler handler,
void *eloop_data, void *user_data)
{
- struct eloop_timeout *timeout, *prev, *next;
+ struct eloop_timeout *timeout, *prev;
int removed = 0;
- prev = NULL;
- timeout = eloop.timeout;
- while (timeout != NULL) {
- next = timeout->next;
-
+ dl_list_for_each_safe(timeout, prev, &eloop.timeout,
+ struct eloop_timeout, list) {
if (timeout->handler == handler &&
(timeout->eloop_data == eloop_data ||
eloop_data == ELOOP_ALL_CTX) &&
(timeout->user_data == user_data ||
user_data == ELOOP_ALL_CTX)) {
- if (prev == NULL)
- eloop.timeout = next;
- else
- prev->next = next;
- free(timeout);
+ eloop_remove_timeout(timeout);
removed++;
- } else
- prev = timeout;
-
- timeout = next;
+ }
}
return removed;
}
-int eloop_is_timeout_registered(void (*handler)(void *eloop_ctx,
- void *timeout_ctx),
+int eloop_cancel_timeout_one(eloop_timeout_handler handler,
+ void *eloop_data, void *user_data,
+ struct os_time *remaining)
+{
+ struct eloop_timeout *timeout, *prev;
+ int removed = 0;
+ struct os_time now;
+
+ os_get_time(&now);
+ remaining->sec = remaining->usec = 0;
+
+ dl_list_for_each_safe(timeout, prev, &eloop.timeout,
+ struct eloop_timeout, list) {
+ if (timeout->handler == handler &&
+ (timeout->eloop_data == eloop_data) &&
+ (timeout->user_data == user_data)) {
+ removed = 1;
+ if (os_time_before(&now, &timeout->time))
+ os_time_sub(&timeout->time, &now, remaining);
+ eloop_remove_timeout(timeout);
+ break;
+ }
+ }
+ return removed;
+}
+
+
+int eloop_is_timeout_registered(eloop_timeout_handler handler,
void *eloop_data, void *user_data)
{
struct eloop_timeout *tmp;
- tmp = eloop.timeout;
- while (tmp != NULL) {
+ dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
if (tmp->handler == handler &&
tmp->eloop_data == eloop_data &&
tmp->user_data == user_data)
return 1;
-
- tmp = tmp->next;
}
return 0;
@@ -241,24 +261,19 @@
if (eloop.signals[i].signaled) {
eloop.signals[i].signaled = 0;
eloop.signals[i].handler(eloop.signals[i].sig,
- eloop.user_data,
eloop.signals[i].user_data);
}
}
}
-int eloop_register_signal(int sig,
- void (*handler)(int sig, void *eloop_ctx,
- void *signal_ctx),
+int eloop_register_signal(int sig, eloop_signal_handler handler,
void *user_data)
{
struct eloop_signal *tmp;
- tmp = (struct eloop_signal *)
- realloc(eloop.signals,
- (eloop.signal_count + 1) *
- sizeof(struct eloop_signal));
+ tmp = os_realloc_array(eloop.signals, eloop.signal_count + 1,
+ sizeof(struct eloop_signal));
if (tmp == NULL)
return -1;
@@ -275,8 +290,7 @@
}
-int eloop_register_signal_terminate(void (*handler)(int sig, void *eloop_ctx,
- void *signal_ctx),
+int eloop_register_signal_terminate(eloop_signal_handler handler,
void *user_data)
{
#if 0
@@ -290,8 +304,7 @@
}
-int eloop_register_signal_reconfig(void (*handler)(int sig, void *eloop_ctx,
- void *signal_ctx),
+int eloop_register_signal_reconfig(eloop_signal_handler handler,
void *user_data)
{
#if 0
@@ -308,11 +321,14 @@
struct os_time tv, now;
while (!eloop.terminate &&
- (eloop.timeout || eloop.reader_count > 0)) {
- if (eloop.timeout) {
+ (!dl_list_empty(&eloop.timeout) || eloop.reader_count > 0)) {
+ struct eloop_timeout *timeout;
+ timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
+ list);
+ if (timeout) {
os_get_time(&now);
- if (os_time_before(&now, &eloop.timeout->time))
- os_time_sub(&eloop.timeout->time, &now, &tv);
+ if (os_time_before(&now, &timeout->time))
+ os_time_sub(&timeout->time, &now, &tv);
else
tv.sec = tv.usec = 0;
}
@@ -326,16 +342,17 @@
eloop_process_pending_signals();
/* check if some registered timeouts have occurred */
- if (eloop.timeout) {
- struct eloop_timeout *tmp;
-
+ timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
+ list);
+ if (timeout) {
os_get_time(&now);
- if (!os_time_before(&now, &eloop.timeout->time)) {
- tmp = eloop.timeout;
- eloop.timeout = eloop.timeout->next;
- tmp->handler(tmp->eloop_data,
- tmp->user_data);
- free(tmp);
+ if (!os_time_before(&now, &timeout->time)) {
+ void *eloop_data = timeout->eloop_data;
+ void *user_data = timeout->user_data;
+ eloop_timeout_handler handler =
+ timeout->handler;
+ eloop_remove_timeout(timeout);
+ handler(eloop_data, user_data);
}
}
@@ -369,14 +386,12 @@
{
struct eloop_timeout *timeout, *prev;
- timeout = eloop.timeout;
- while (timeout != NULL) {
- prev = timeout;
- timeout = timeout->next;
- free(prev);
+ dl_list_for_each_safe(timeout, prev, &eloop.timeout,
+ struct eloop_timeout, list) {
+ eloop_remove_timeout(timeout);
}
- free(eloop.readers);
- free(eloop.signals);
+ os_free(eloop.readers);
+ os_free(eloop.signals);
}
diff --git a/src/utils/eloop_win.c b/src/utils/eloop_win.c
index 1fafeb2..eda412f 100644
--- a/src/utils/eloop_win.c
+++ b/src/utils/eloop_win.c
@@ -1,6 +1,6 @@
/*
* Event loop based on Windows events and WaitForMultipleObjects
- * Copyright (c) 2002-2006, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, 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 <winsock2.h>
#include "common.h"
+#include "list.h"
#include "eloop.h"
@@ -29,11 +30,11 @@
};
struct eloop_timeout {
+ struct dl_list list;
struct os_time time;
void *eloop_data;
void *user_data;
eloop_timeout_handler handler;
- struct eloop_timeout *next;
};
struct eloop_signal {
@@ -51,7 +52,7 @@
size_t event_count;
struct eloop_event *events;
- struct eloop_timeout *timeout;
+ struct dl_list timeout;
int signal_count;
struct eloop_signal *signals;
@@ -74,6 +75,7 @@
int eloop_init(void)
{
os_memset(&eloop, 0, sizeof(eloop));
+ dl_list_init(&eloop.timeout);
eloop.num_handles = 1;
eloop.handles = os_malloc(eloop.num_handles *
sizeof(eloop.handles[0]));
@@ -236,13 +238,16 @@
eloop_timeout_handler handler,
void *eloop_data, void *user_data)
{
- struct eloop_timeout *timeout, *tmp, *prev;
+ struct eloop_timeout *timeout, *tmp;
os_time_t now_sec;
- timeout = os_malloc(sizeof(*timeout));
+ timeout = os_zalloc(sizeof(*timeout));
if (timeout == NULL)
return -1;
- os_get_time(&timeout->time);
+ if (os_get_time(&timeout->time) < 0) {
+ os_free(timeout);
+ return -1;
+ }
now_sec = timeout->time.sec;
timeout->time.sec += secs;
if (timeout->time.sec < now_sec) {
@@ -263,79 +268,86 @@
timeout->eloop_data = eloop_data;
timeout->user_data = user_data;
timeout->handler = handler;
- timeout->next = NULL;
- if (eloop.timeout == NULL) {
- eloop.timeout = timeout;
- return 0;
+ /* Maintain timeouts in order of increasing time */
+ dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
+ if (os_time_before(&timeout->time, &tmp->time)) {
+ dl_list_add(tmp->list.prev, &timeout->list);
+ return 0;
+ }
}
-
- prev = NULL;
- tmp = eloop.timeout;
- while (tmp != NULL) {
- if (os_time_before(&timeout->time, &tmp->time))
- break;
- prev = tmp;
- tmp = tmp->next;
- }
-
- if (prev == NULL) {
- timeout->next = eloop.timeout;
- eloop.timeout = timeout;
- } else {
- timeout->next = prev->next;
- prev->next = timeout;
- }
+ dl_list_add_tail(&eloop.timeout, &timeout->list);
return 0;
}
+static void eloop_remove_timeout(struct eloop_timeout *timeout)
+{
+ dl_list_del(&timeout->list);
+ os_free(timeout);
+}
+
+
int eloop_cancel_timeout(eloop_timeout_handler handler,
void *eloop_data, void *user_data)
{
- struct eloop_timeout *timeout, *prev, *next;
+ struct eloop_timeout *timeout, *prev;
int removed = 0;
- prev = NULL;
- timeout = eloop.timeout;
- while (timeout != NULL) {
- next = timeout->next;
-
+ dl_list_for_each_safe(timeout, prev, &eloop.timeout,
+ struct eloop_timeout, list) {
if (timeout->handler == handler &&
(timeout->eloop_data == eloop_data ||
eloop_data == ELOOP_ALL_CTX) &&
(timeout->user_data == user_data ||
user_data == ELOOP_ALL_CTX)) {
- if (prev == NULL)
- eloop.timeout = next;
- else
- prev->next = next;
- os_free(timeout);
+ eloop_remove_timeout(timeout);
removed++;
- } else
- prev = timeout;
-
- timeout = next;
+ }
}
return removed;
}
+int eloop_cancel_timeout_one(eloop_timeout_handler handler,
+ void *eloop_data, void *user_data,
+ struct os_time *remaining)
+{
+ struct eloop_timeout *timeout, *prev;
+ int removed = 0;
+ struct os_time now;
+
+ os_get_time(&now);
+ remaining->sec = remaining->usec = 0;
+
+ dl_list_for_each_safe(timeout, prev, &eloop.timeout,
+ struct eloop_timeout, list) {
+ if (timeout->handler == handler &&
+ (timeout->eloop_data == eloop_data) &&
+ (timeout->user_data == user_data)) {
+ removed = 1;
+ if (os_time_before(&now, &timeout->time))
+ os_time_sub(&timeout->time, &now, remaining);
+ eloop_remove_timeout(timeout);
+ break;
+ }
+ }
+ return removed;
+}
+
+
int eloop_is_timeout_registered(eloop_timeout_handler handler,
void *eloop_data, void *user_data)
{
struct eloop_timeout *tmp;
- tmp = eloop.timeout;
- while (tmp != NULL) {
+ dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
if (tmp->handler == handler &&
tmp->eloop_data == eloop_data &&
tmp->user_data == user_data)
return 1;
-
- tmp = tmp->next;
}
return 0;
@@ -457,17 +469,20 @@
void eloop_run(void)
{
struct os_time tv, now;
- DWORD count, ret, timeout, err;
+ DWORD count, ret, timeout_val, err;
size_t i;
while (!eloop.terminate &&
- (eloop.timeout || eloop.reader_count > 0 ||
+ (!dl_list_empty(&eloop.timeout) || eloop.reader_count > 0 ||
eloop.event_count > 0)) {
+ struct eloop_timeout *timeout;
tv.sec = tv.usec = 0;
- if (eloop.timeout) {
+ timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
+ list);
+ if (timeout) {
os_get_time(&now);
- if (os_time_before(&now, &eloop.timeout->time))
- os_time_sub(&eloop.timeout->time, &now, &tv);
+ if (os_time_before(&now, &timeout->time))
+ os_time_sub(&timeout->time, &now, &tv);
}
count = 0;
@@ -480,10 +495,10 @@
if (eloop.term_event)
eloop.handles[count++] = eloop.term_event;
- if (eloop.timeout)
- timeout = tv.sec * 1000 + tv.usec / 1000;
+ if (timeout)
+ timeout_val = tv.sec * 1000 + tv.usec / 1000;
else
- timeout = INFINITE;
+ timeout_val = INFINITE;
if (count > MAXIMUM_WAIT_OBJECTS) {
printf("WaitForMultipleObjects: Too many events: "
@@ -493,26 +508,27 @@
}
#ifdef _WIN32_WCE
ret = WaitForMultipleObjects(count, eloop.handles, FALSE,
- timeout);
+ timeout_val);
#else /* _WIN32_WCE */
ret = WaitForMultipleObjectsEx(count, eloop.handles, FALSE,
- timeout, TRUE);
+ timeout_val, TRUE);
#endif /* _WIN32_WCE */
err = GetLastError();
eloop_process_pending_signals();
/* check if some registered timeouts have occurred */
- if (eloop.timeout) {
- struct eloop_timeout *tmp;
-
+ timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
+ list);
+ if (timeout) {
os_get_time(&now);
- if (!os_time_before(&now, &eloop.timeout->time)) {
- tmp = eloop.timeout;
- eloop.timeout = eloop.timeout->next;
- tmp->handler(tmp->eloop_data,
- tmp->user_data);
- os_free(tmp);
+ if (!os_time_before(&now, &timeout->time)) {
+ void *eloop_data = timeout->eloop_data;
+ void *user_data = timeout->user_data;
+ eloop_timeout_handler handler =
+ timeout->handler;
+ eloop_remove_timeout(timeout);
+ handler(eloop_data, user_data);
}
}
@@ -571,11 +587,9 @@
{
struct eloop_timeout *timeout, *prev;
- timeout = eloop.timeout;
- while (timeout != NULL) {
- prev = timeout;
- timeout = timeout->next;
- os_free(prev);
+ dl_list_for_each_safe(timeout, prev, &eloop.timeout,
+ struct eloop_timeout, list) {
+ eloop_remove_timeout(timeout);
}
os_free(eloop.readers);
os_free(eloop.signals);
diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c
index 1e21fb7..10b9e0d 100644
--- a/src/utils/os_unix.c
+++ b/src/utils/os_unix.c
@@ -213,6 +213,9 @@
size_t len = 128, cwd_len, rel_len, ret_len;
int last_errno;
+ if (!rel_path)
+ return NULL;
+
if (rel_path[0] == '/')
return os_strdup(rel_path);
@@ -257,7 +260,11 @@
* We ignore errors here since errors are normal if we
* are already running as non-root.
*/
+#ifdef ANDROID_SETGROUPS_OVERRIDE
+ gid_t groups[] = { ANDROID_SETGROUPS_OVERRIDE };
+#else /* ANDROID_SETGROUPS_OVERRIDE */
gid_t groups[] = { AID_INET, AID_WIFI, AID_KEYSTORE };
+#endif /* ANDROID_SETGROUPS_OVERRIDE */
struct __user_cap_header_struct header;
struct __user_cap_data_struct cap;
diff --git a/src/wps/ndef.c b/src/wps/ndef.c
index 7630ecb..96685d2 100644
--- a/src/wps/ndef.c
+++ b/src/wps/ndef.c
@@ -10,13 +10,13 @@
#include "includes.h"
#include "common.h"
#include "wps/wps.h"
-#include "wps/wps_i.h"
#define FLAG_MESSAGE_BEGIN (1 << 7)
#define FLAG_MESSAGE_END (1 << 6)
#define FLAG_CHUNK (1 << 5)
#define FLAG_SHORT_RECORD (1 << 4)
#define FLAG_ID_LENGTH_PRESENT (1 << 3)
+#define FLAG_TNF_NFC_FORUM (0x01)
#define FLAG_TNF_RFC2046 (0x02)
struct ndef_record {
@@ -168,3 +168,87 @@
FLAG_TNF_RFC2046, wifi_handover_type,
os_strlen(wifi_handover_type), NULL, 0, buf);
}
+
+
+struct wpabuf * ndef_build_wifi_hc(int begin)
+{
+ struct wpabuf *hc, *carrier;
+
+ carrier = wpabuf_alloc(2 + os_strlen(wifi_handover_type));
+ if (carrier == NULL)
+ return NULL;
+ wpabuf_put_u8(carrier, 0x02); /* Carrier Type Format */
+ wpabuf_put_u8(carrier, os_strlen(wifi_handover_type));
+ wpabuf_put_str(carrier, wifi_handover_type);
+
+ hc = ndef_build_record((begin ? FLAG_MESSAGE_BEGIN : 0) |
+ FLAG_MESSAGE_END | FLAG_TNF_NFC_FORUM, "Hc", 2,
+ "0", 1, carrier);
+ wpabuf_free(carrier);
+
+ return hc;
+}
+
+
+struct wpabuf * ndef_build_wifi_hr(void)
+{
+ struct wpabuf *rn, *cr, *ac_payload, *ac, *hr_payload, *hr;
+ struct wpabuf *hc;
+
+ rn = wpabuf_alloc(2);
+ if (rn == NULL)
+ return NULL;
+ wpabuf_put_be16(rn, os_random() & 0xffff);
+
+ cr = ndef_build_record(FLAG_MESSAGE_BEGIN | FLAG_TNF_NFC_FORUM, "cr", 2,
+ NULL, 0, rn);
+ wpabuf_free(rn);
+
+ if (cr == NULL)
+ return NULL;
+
+ ac_payload = wpabuf_alloc(4);
+ if (ac_payload == NULL) {
+ wpabuf_free(cr);
+ return NULL;
+ }
+ wpabuf_put_u8(ac_payload, 0x01); /* Carrier Flags: CRS=1 "active" */
+ wpabuf_put_u8(ac_payload, 0x01); /* Carrier Data Reference Length */
+ wpabuf_put_u8(ac_payload, '0'); /* Carrier Data Reference: "0" */
+ wpabuf_put_u8(ac_payload, 0); /* Aux Data Reference Count */
+
+ ac = ndef_build_record(FLAG_MESSAGE_END | FLAG_TNF_NFC_FORUM, "ac", 2,
+ NULL, 0, ac_payload);
+ wpabuf_free(ac_payload);
+ if (ac == NULL) {
+ wpabuf_free(cr);
+ return NULL;
+ }
+
+ hr_payload = wpabuf_alloc(1 + wpabuf_len(cr) + wpabuf_len(ac));
+ if (hr_payload == NULL) {
+ wpabuf_free(cr);
+ wpabuf_free(ac);
+ return NULL;
+ }
+
+ wpabuf_put_u8(hr_payload, 0x12); /* Connection Handover Version 1.2 */
+ wpabuf_put_buf(hr_payload, cr);
+ wpabuf_put_buf(hr_payload, ac);
+ wpabuf_free(cr);
+ wpabuf_free(ac);
+
+ hr = ndef_build_record(FLAG_MESSAGE_BEGIN | FLAG_TNF_NFC_FORUM, "Hr", 2,
+ NULL, 0, hr_payload);
+ wpabuf_free(hr_payload);
+ if (hr == NULL)
+ return NULL;
+
+ hc = ndef_build_wifi_hc(0);
+ if (hc == NULL) {
+ wpabuf_free(hr);
+ return NULL;
+ }
+
+ return wpabuf_concat(hr, hc);
+}
diff --git a/src/wps/wps.c b/src/wps/wps.c
index 4c2322d..ff4b20d 100644
--- a/src/wps/wps.c
+++ b/src/wps/wps.c
@@ -45,8 +45,7 @@
os_memcpy(data->uuid_e, cfg->wps->uuid, WPS_UUID_LEN);
}
if (cfg->pin) {
- data->dev_pw_id = data->wps->oob_dev_pw_id == 0 ?
- cfg->dev_pw_id : data->wps->oob_dev_pw_id;
+ data->dev_pw_id = cfg->dev_pw_id;
data->dev_password = os_malloc(cfg->pin_len);
if (data->dev_password == NULL) {
os_free(data);
@@ -54,12 +53,18 @@
}
os_memcpy(data->dev_password, cfg->pin, cfg->pin_len);
data->dev_password_len = cfg->pin_len;
+ wpa_hexdump_key(MSG_DEBUG, "WPS: AP PIN dev_password",
+ data->dev_password, data->dev_password_len);
}
#ifdef CONFIG_WPS_NFC
if (cfg->wps->ap && !cfg->registrar && cfg->wps->ap_nfc_dev_pw_id) {
+ /* Keep AP PIN as alternative Device Password */
+ data->alt_dev_pw_id = data->dev_pw_id;
+ data->alt_dev_password = data->dev_password;
+ data->alt_dev_password_len = data->dev_password_len;
+
data->dev_pw_id = cfg->wps->ap_nfc_dev_pw_id;
- os_free(data->dev_password);
data->dev_password =
os_malloc(wpabuf_len(cfg->wps->ap_nfc_dev_pw));
if (data->dev_password == NULL) {
@@ -70,6 +75,8 @@
wpabuf_head(cfg->wps->ap_nfc_dev_pw),
wpabuf_len(cfg->wps->ap_nfc_dev_pw));
data->dev_password_len = wpabuf_len(cfg->wps->ap_nfc_dev_pw);
+ wpa_hexdump_key(MSG_DEBUG, "WPS: NFC dev_password",
+ data->dev_password, data->dev_password_len);
}
#endif /* CONFIG_WPS_NFC */
@@ -110,6 +117,7 @@
data->new_ap_settings =
os_malloc(sizeof(*data->new_ap_settings));
if (data->new_ap_settings == NULL) {
+ os_free(data->dev_password);
os_free(data);
return NULL;
}
@@ -155,6 +163,7 @@
wpabuf_free(data->dh_pubkey_r);
wpabuf_free(data->last_msg);
os_free(data->dev_password);
+ os_free(data->alt_dev_password);
os_free(data->new_psk);
wps_device_data_free(&data->peer_dev);
os_free(data->new_ap_settings);
diff --git a/src/wps/wps.h b/src/wps/wps.h
index c45b68c..cb03dbd 100644
--- a/src/wps/wps.h
+++ b/src/wps/wps.h
@@ -1,6 +1,6 @@
/*
* Wi-Fi Protected Setup
- * Copyright (c) 2007-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -42,6 +42,7 @@
* @cred_attr: Unparsed Credential attribute data (used only in cred_cb());
* this may be %NULL, if not used
* @cred_attr_len: Length of cred_attr in octets
+ * @ap_channel: AP channel
*/
struct wps_credential {
u8 ssid[32];
@@ -54,6 +55,7 @@
u8 mac_addr[ETH_ALEN];
const u8 *cred_attr;
size_t cred_attr_len;
+ u16 ap_channel;
};
#define WPS_DEV_TYPE_LEN 8
@@ -101,17 +103,6 @@
int p2p;
};
-struct oob_conf_data {
- enum {
- OOB_METHOD_UNKNOWN = 0,
- OOB_METHOD_DEV_PWD_E,
- OOB_METHOD_DEV_PWD_R,
- OOB_METHOD_CRED,
- } oob_method;
- struct wpabuf *dev_password;
- struct wpabuf *pubkey_hash;
-};
-
/**
* struct wps_config - WPS configuration for a single registration protocol run
*/
@@ -617,16 +608,6 @@
struct wps_device_data dev;
/**
- * oob_conf - OOB Config data
- */
- struct oob_conf_data oob_conf;
-
- /**
- * oob_dev_pw_id - OOB Device password id
- */
- u16 oob_dev_pw_id;
-
- /**
* dh_ctx - Context data for Diffie-Hellman operation
*/
void *dh_ctx;
@@ -764,23 +745,6 @@
struct wpabuf *ap_nfc_dev_pw;
};
-struct oob_device_data {
- char *device_name;
- char *device_path;
- void * (*init_func)(struct wps_context *, struct oob_device_data *,
- int);
- struct wpabuf * (*read_func)(void *);
- int (*write_func)(void *, struct wpabuf *);
- void (*deinit_func)(void *);
-};
-
-struct oob_nfc_device_data {
- int (*init_func)(char *);
- void * (*read_func)(size_t *);
- int (*write_func)(void *, size_t);
- void (*deinit_func)(void);
-};
-
struct wps_registrar *
wps_registrar_init(struct wps_context *wps,
const struct wps_registrar_config *cfg);
@@ -819,11 +783,6 @@
int wps_pin_str_valid(const char *pin);
void wps_free_pending_msgs(struct upnp_pending_message *msgs);
-struct oob_device_data * wps_get_oob_device(char *device_type);
-struct oob_nfc_device_data * wps_get_oob_nfc_device(char *device_name);
-int wps_get_oob_method(char *method);
-int wps_process_oob(struct wps_context *wps, struct oob_device_data *oob_dev,
- int registrar);
struct wpabuf * wps_get_oob_cred(struct wps_context *wps);
int wps_oob_use_cred(struct wps_context *wps, struct wps_parse_attr *attr);
int wps_attr_text(struct wpabuf *data, char *buf, char *end);
@@ -834,14 +793,19 @@
void wps_er_deinit(struct wps_er *er, void (*cb)(void *ctx), void *ctx);
void wps_er_set_sel_reg(struct wps_er *er, int sel_reg, u16 dev_passwd_id,
u16 sel_reg_config_methods);
-int wps_er_pbc(struct wps_er *er, const u8 *uuid);
-int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *pin,
- size_t pin_len);
-int wps_er_set_config(struct wps_er *er, const u8 *uuid,
+int wps_er_pbc(struct wps_er *er, const u8 *uuid, const u8 *addr);
+const u8 * wps_er_get_sta_uuid(struct wps_er *er, const u8 *addr);
+int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *addr,
+ const u8 *pin, size_t pin_len);
+int wps_er_set_config(struct wps_er *er, const u8 *uuid, const u8 *addr,
const struct wps_credential *cred);
-int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *pin,
- size_t pin_len, const struct wps_credential *cred);
-struct wpabuf * wps_er_nfc_config_token(struct wps_er *er, const u8 *uuid);
+int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *addr,
+ const u8 *pin, size_t pin_len,
+ const struct wps_credential *cred);
+struct wpabuf * wps_er_config_token_from_cred(struct wps_context *wps,
+ struct wps_credential *cred);
+struct wpabuf * wps_er_nfc_config_token(struct wps_er *er, const u8 *uuid,
+ const u8 *addr);
int wps_dev_type_str2bin(const char *str, u8 dev_type[WPS_DEV_TYPE_LEN]);
char * wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char *buf,
@@ -851,6 +815,8 @@
struct wpabuf * wps_build_nfc_pw_token(u16 dev_pw_id,
const struct wpabuf *pubkey,
const struct wpabuf *dev_pw);
+struct wpabuf * wps_nfc_token_build(int ndef, int id, struct wpabuf *pubkey,
+ struct wpabuf *dev_pw);
struct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey,
struct wpabuf **privkey,
struct wpabuf **dev_pw);
@@ -858,6 +824,8 @@
/* ndef.c */
struct wpabuf * ndef_parse_wifi(const struct wpabuf *buf);
struct wpabuf * ndef_build_wifi(const struct wpabuf *buf);
+struct wpabuf * ndef_build_wifi_hc(int begin);
+struct wpabuf * ndef_build_wifi_hr(void);
#ifdef CONFIG_WPS_STRICT
int wps_validate_beacon(const struct wpabuf *wps_ie);
diff --git a/src/wps/wps_attr_build.c b/src/wps/wps_attr_build.c
index 9be30b9..edcc18c 100644
--- a/src/wps/wps_attr_build.c
+++ b/src/wps/wps_attr_build.c
@@ -24,8 +24,15 @@
wpa_printf(MSG_DEBUG, "WPS: * Public Key");
wpabuf_free(wps->dh_privkey);
- if (wps->dev_pw_id != DEV_PW_DEFAULT && wps->wps->dh_privkey) {
+ wps->dh_privkey = NULL;
+ if (wps->dev_pw_id != DEV_PW_DEFAULT && wps->wps->dh_privkey &&
+ wps->wps->dh_ctx) {
wpa_printf(MSG_DEBUG, "WPS: Using pre-configured DH keys");
+ if (wps->wps->dh_pubkey == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "WPS: wps->wps->dh_pubkey == NULL");
+ return -1;
+ }
wps->dh_privkey = wpabuf_dup(wps->wps->dh_privkey);
wps->dh_ctx = wps->wps->dh_ctx;
wps->wps->dh_ctx = NULL;
@@ -34,13 +41,22 @@
} else if (wps->dev_pw_id >= 0x10 && wps->wps->ap &&
wps->dev_pw_id == wps->wps->ap_nfc_dev_pw_id) {
wpa_printf(MSG_DEBUG, "WPS: Using NFC password token DH keys");
+ if (wps->wps->ap_nfc_dh_privkey == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "WPS: wps->wps->ap_nfc_dh_privkey == NULL");
+ return -1;
+ }
+ if (wps->wps->ap_nfc_dh_pubkey == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "WPS: wps->wps->ap_nfc_dh_pubkey == NULL");
+ return -1;
+ }
wps->dh_privkey = wpabuf_dup(wps->wps->ap_nfc_dh_privkey);
pubkey = wpabuf_dup(wps->wps->ap_nfc_dh_pubkey);
wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, pubkey);
#endif /* CONFIG_WPS_NFC */
} else {
wpa_printf(MSG_DEBUG, "WPS: Generate new DH keys");
- wps->dh_privkey = NULL;
dh5_free(wps->dh_ctx);
wps->dh_ctx = dh5_init(&wps->dh_privkey, &pubkey);
pubkey = wpabuf_zeropad(pubkey, 192);
@@ -368,38 +384,6 @@
return 0;
}
-
-
-int wps_build_oob_dev_password(struct wpabuf *msg, struct wps_context *wps)
-{
- u8 dev_password_bin[WPS_OOB_DEVICE_PASSWORD_LEN];
-
- wpa_printf(MSG_DEBUG, "WPS: * OOB Device Password");
-
- if (os_get_random((u8 *) &wps->oob_dev_pw_id, sizeof(u16)) < 0) {
- wpa_printf(MSG_ERROR, "WPS: device password id "
- "generation error");
- return -1;
- }
- wps->oob_dev_pw_id |= 0x0010;
-
- if (random_get_bytes(dev_password_bin, WPS_OOB_DEVICE_PASSWORD_LEN) <
- 0) {
- wpa_printf(MSG_ERROR, "WPS: OOB device password "
- "generation error");
- return -1;
- }
-
- wpa_snprintf_hex_uppercase(
- wpabuf_put(wps->oob_conf.dev_password,
- wpabuf_size(wps->oob_conf.dev_password)),
- wpabuf_size(wps->oob_conf.dev_password),
- dev_password_bin, WPS_OOB_DEVICE_PASSWORD_LEN);
-
- return wps_build_oob_dev_pw(msg, wps->oob_dev_pw_id, wps->dh_pubkey,
- dev_password_bin,
- WPS_OOB_DEVICE_PASSWORD_LEN);
-}
#endif /* CONFIG_WPS_OOB */
diff --git a/src/wps/wps_attr_parse.c b/src/wps/wps_attr_parse.c
index 5aa9b00..3999b1b 100644
--- a/src/wps/wps_attr_parse.c
+++ b/src/wps/wps_attr_parse.c
@@ -542,6 +542,14 @@
if (wps_parse_vendor_ext(attr, pos, len) < 0)
return -1;
break;
+ case ATTR_AP_CHANNEL:
+ if (len != 2) {
+ wpa_printf(MSG_DEBUG, "WPS: Invalid AP Channel "
+ "length %u", len);
+ return -1;
+ }
+ attr->ap_channel = pos;
+ break;
default:
wpa_printf(MSG_DEBUG, "WPS: Unsupported attribute type 0x%x "
"len=%u", type, len);
diff --git a/src/wps/wps_attr_parse.h b/src/wps/wps_attr_parse.h
index 332e966..88e51a4 100644
--- a/src/wps/wps_attr_parse.h
+++ b/src/wps/wps_attr_parse.h
@@ -56,6 +56,7 @@
const u8 *settings_delay_time; /* 1 octet */
const u8 *network_key_shareable; /* 1 octet (Bool) */
const u8 *request_to_enroll; /* 1 octet (Bool) */
+ const u8 *ap_channel; /* 2 octets */
/* variable length fields */
const u8 *manufacturer;
diff --git a/src/wps/wps_attr_process.c b/src/wps/wps_attr_process.c
index d4c6e88..b81f106 100644
--- a/src/wps/wps_attr_process.c
+++ b/src/wps/wps_attr_process.c
@@ -258,6 +258,19 @@
}
+static int wps_process_cred_ap_channel(struct wps_credential *cred,
+ const u8 *ap_channel)
+{
+ if (ap_channel == NULL)
+ return 0; /* optional attribute */
+
+ cred->ap_channel = WPA_GET_BE16(ap_channel);
+ wpa_printf(MSG_DEBUG, "WPS: AP Channel: %u", cred->ap_channel);
+
+ return 0;
+}
+
+
static int wps_workaround_cred_key(struct wps_credential *cred)
{
if (cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK) &&
@@ -303,7 +316,8 @@
wps_process_cred_eap_identity(cred, attr->eap_identity,
attr->eap_identity_len) ||
wps_process_cred_key_prov_auto(cred, attr->key_prov_auto) ||
- wps_process_cred_802_1x_enabled(cred, attr->dot1x_enabled))
+ wps_process_cred_802_1x_enabled(cred, attr->dot1x_enabled) ||
+ wps_process_cred_ap_channel(cred, attr->ap_channel))
return -1;
return wps_workaround_cred_key(cred);
diff --git a/src/wps/wps_common.c b/src/wps/wps_common.c
index 5a8817f..0897b7b 100644
--- a/src/wps/wps_common.c
+++ b/src/wps/wps_common.c
@@ -375,84 +375,6 @@
}
-static struct wpabuf * wps_get_oob_dev_pwd(struct wps_context *wps)
-{
- struct wpabuf *data;
-
- data = wpabuf_alloc(200);
- if (data == NULL) {
- wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
- "device password attribute");
- return NULL;
- }
-
- wpabuf_free(wps->oob_conf.dev_password);
- wps->oob_conf.dev_password =
- wpabuf_alloc(WPS_OOB_DEVICE_PASSWORD_LEN * 2 + 1);
- if (wps->oob_conf.dev_password == NULL) {
- wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
- "device password");
- wpabuf_free(data);
- return NULL;
- }
-
- if (wps_build_version(data) ||
- wps_build_oob_dev_password(data, wps) ||
- wps_build_wfa_ext(data, 0, NULL, 0)) {
- wpa_printf(MSG_ERROR, "WPS: Build OOB device password "
- "attribute error");
- wpabuf_free(data);
- return NULL;
- }
-
- return data;
-}
-
-
-static int wps_parse_oob_dev_pwd(struct wps_context *wps,
- struct wpabuf *data)
-{
- struct oob_conf_data *oob_conf = &wps->oob_conf;
- struct wps_parse_attr attr;
- const u8 *pos;
- size_t pw_len;
-
- if (wps_parse_msg(data, &attr) < 0 ||
- attr.oob_dev_password == NULL) {
- wpa_printf(MSG_ERROR, "WPS: OOB device password not found");
- return -1;
- }
-
- pos = attr.oob_dev_password;
-
- wpabuf_free(oob_conf->pubkey_hash);
- oob_conf->pubkey_hash =
- wpabuf_alloc_copy(pos, WPS_OOB_PUBKEY_HASH_LEN);
- if (oob_conf->pubkey_hash == NULL) {
- wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
- "public key hash");
- return -1;
- }
- pos += WPS_OOB_PUBKEY_HASH_LEN;
-
- wps->oob_dev_pw_id = WPA_GET_BE16(pos);
- pos += sizeof(wps->oob_dev_pw_id);
-
- pw_len = attr.oob_dev_password_len - WPS_OOB_PUBKEY_HASH_LEN - 2;
- oob_conf->dev_password = wpabuf_alloc(pw_len * 2 + 1);
- if (oob_conf->dev_password == NULL) {
- wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
- "device password");
- return -1;
- }
- wpa_snprintf_hex_uppercase(wpabuf_put(oob_conf->dev_password,
- pw_len * 2 + 1),
- pw_len * 2 + 1, pos, pw_len);
-
- return 0;
-}
-
-
int wps_oob_use_cred(struct wps_context *wps, struct wps_parse_attr *attr)
{
struct wpabuf msg;
@@ -477,107 +399,6 @@
}
-static int wps_parse_oob_cred(struct wps_context *wps, struct wpabuf *data)
-{
- struct wps_parse_attr attr;
-
- if (wps_parse_msg(data, &attr) < 0 || attr.num_cred <= 0) {
- wpa_printf(MSG_ERROR, "WPS: OOB credential not found");
- return -1;
- }
-
- return wps_oob_use_cred(wps, &attr);
-}
-
-
-int wps_process_oob(struct wps_context *wps, struct oob_device_data *oob_dev,
- int registrar)
-{
- struct wpabuf *data;
- int ret, write_f, oob_method = wps->oob_conf.oob_method;
- void *oob_priv;
-
- write_f = oob_method == OOB_METHOD_DEV_PWD_E ? !registrar : registrar;
-
- oob_priv = oob_dev->init_func(wps, oob_dev, registrar);
- if (oob_priv == NULL) {
- wpa_printf(MSG_ERROR, "WPS: Failed to initialize OOB device");
- return -1;
- }
-
- if (write_f) {
- if (oob_method == OOB_METHOD_CRED)
- data = wps_get_oob_cred(wps);
- else
- data = wps_get_oob_dev_pwd(wps);
-
- ret = 0;
- if (data == NULL || oob_dev->write_func(oob_priv, data) < 0)
- ret = -1;
- } else {
- data = oob_dev->read_func(oob_priv);
- if (data == NULL)
- ret = -1;
- else {
- if (oob_method == OOB_METHOD_CRED)
- ret = wps_parse_oob_cred(wps, data);
- else
- ret = wps_parse_oob_dev_pwd(wps, data);
- }
- }
- wpabuf_free(data);
- oob_dev->deinit_func(oob_priv);
-
- if (ret < 0) {
- wpa_printf(MSG_ERROR, "WPS: Failed to process OOB data");
- return -1;
- }
-
- return 0;
-}
-
-
-struct oob_device_data * wps_get_oob_device(char *device_type)
-{
-#ifdef CONFIG_WPS_UFD
- if (os_strstr(device_type, "ufd") != NULL)
- return &oob_ufd_device_data;
-#endif /* CONFIG_WPS_UFD */
-#ifdef CONFIG_WPS_NFC
- if (os_strstr(device_type, "nfc") != NULL)
- return &oob_nfc_device_data;
-#endif /* CONFIG_WPS_NFC */
-
- return NULL;
-}
-
-
-#ifdef CONFIG_WPS_NFC
-struct oob_nfc_device_data * wps_get_oob_nfc_device(char *device_name)
-{
- if (device_name == NULL)
- return NULL;
-#ifdef CONFIG_WPS_NFC_PN531
- if (os_strstr(device_name, "pn531") != NULL)
- return &oob_nfc_pn531_device_data;
-#endif /* CONFIG_WPS_NFC_PN531 */
-
- return NULL;
-}
-#endif /* CONFIG_WPS_NFC */
-
-
-int wps_get_oob_method(char *method)
-{
- if (os_strstr(method, "pin-e") != NULL)
- return OOB_METHOD_DEV_PWD_E;
- if (os_strstr(method, "pin-r") != NULL)
- return OOB_METHOD_DEV_PWD_R;
- if (os_strstr(method, "cred") != NULL)
- return OOB_METHOD_CRED;
- return OOB_METHOD_UNKNOWN;
-}
-
#endif /* CONFIG_WPS_OOB */
@@ -657,15 +478,10 @@
#ifdef CONFIG_WPS2
methods |= WPS_CONFIG_VIRT_DISPLAY;
#endif /* CONFIG_WPS2 */
-#ifdef CONFIG_WPS_UFD
- methods |= WPS_CONFIG_USBA;
-#endif /* CONFIG_WPS_UFD */
#ifdef CONFIG_WPS_NFC
methods |= WPS_CONFIG_NFC_INTERFACE;
#endif /* CONFIG_WPS_NFC */
} else {
- if (os_strstr(str, "usba"))
- methods |= WPS_CONFIG_USBA;
if (os_strstr(str, "ethernet"))
methods |= WPS_CONFIG_ETHERNET;
if (os_strstr(str, "label"))
@@ -746,11 +562,34 @@
#ifdef CONFIG_WPS_NFC
+
+struct wpabuf * wps_nfc_token_build(int ndef, int id, struct wpabuf *pubkey,
+ struct wpabuf *dev_pw)
+{
+ struct wpabuf *ret;
+
+ if (pubkey == NULL || dev_pw == NULL)
+ return NULL;
+
+ ret = wps_build_nfc_pw_token(id, pubkey, dev_pw);
+ if (ndef && ret) {
+ struct wpabuf *tmp;
+ tmp = ndef_build_wifi(ret);
+ wpabuf_free(ret);
+ if (tmp == NULL)
+ return NULL;
+ ret = tmp;
+ }
+
+ return ret;
+}
+
+
struct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey,
struct wpabuf **privkey,
struct wpabuf **dev_pw)
{
- struct wpabuf *priv = NULL, *pub = NULL, *pw, *ret;
+ struct wpabuf *priv = NULL, *pub = NULL, *pw;
void *dh_ctx;
u16 val;
@@ -780,16 +619,7 @@
wpabuf_free(*dev_pw);
*dev_pw = pw;
- ret = wps_build_nfc_pw_token(*id, *pubkey, *dev_pw);
- if (ndef && ret) {
- struct wpabuf *tmp;
- tmp = ndef_build_wifi(ret);
- wpabuf_free(ret);
- if (tmp == NULL)
- return NULL;
- ret = tmp;
- }
-
- return ret;
+ return wps_nfc_token_build(ndef, *id, *pubkey, *dev_pw);
}
+
#endif /* CONFIG_WPS_NFC */
diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c
index 389aa84..9c0cebb 100644
--- a/src/wps/wps_enrollee.c
+++ b/src/wps/wps_enrollee.c
@@ -523,23 +523,6 @@
return -1;
}
-#ifdef CONFIG_WPS_OOB
- if (wps->dev_pw_id != DEV_PW_DEFAULT &&
- wps->wps->oob_conf.pubkey_hash) {
- const u8 *addr[1];
- u8 hash[WPS_HASH_LEN];
-
- addr[0] = pk;
- sha256_vector(1, addr, &pk_len, hash);
- if (os_memcmp(hash,
- wpabuf_head(wps->wps->oob_conf.pubkey_hash),
- WPS_OOB_PUBKEY_HASH_LEN) != 0) {
- wpa_printf(MSG_ERROR, "WPS: Public Key hash error");
- return -1;
- }
- }
-#endif /* CONFIG_WPS_OOB */
-
wpabuf_free(wps->dh_pubkey_r);
wps->dh_pubkey_r = wpabuf_alloc_copy(pk, pk_len);
if (wps->dh_pubkey_r == NULL)
@@ -665,6 +648,7 @@
{
struct wps_parse_attr attr;
struct wpabuf msg;
+ int ret = 0;
wpa_printf(MSG_DEBUG, "WPS: Received Credential");
os_memset(&wps->cred, 0, sizeof(wps->cred));
@@ -714,12 +698,12 @@
if (wps->wps->cred_cb) {
wps->cred.cred_attr = cred - 4;
wps->cred.cred_attr_len = cred_len + 4;
- wps->wps->cred_cb(wps->wps->cb_ctx, &wps->cred);
+ ret = wps->wps->cred_cb(wps->wps->cb_ctx, &wps->cred);
wps->cred.cred_attr = NULL;
wps->cred.cred_attr_len = 0;
}
- return 0;
+ return ret;
}
@@ -853,6 +837,39 @@
}
+static int wps_process_dev_pw_id(struct wps_data *wps, const u8 *dev_pw_id)
+{
+ u16 id;
+
+ if (dev_pw_id == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS: Device Password ID");
+ return -1;
+ }
+
+ id = WPA_GET_BE16(dev_pw_id);
+ if (wps->dev_pw_id == id) {
+ wpa_printf(MSG_DEBUG, "WPS: Device Password ID %u", id);
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG, "WPS: Registrar trying to change Device Password "
+ "ID from %u to %u", wps->dev_pw_id, id);
+
+ if (wps->alt_dev_password && wps->alt_dev_pw_id == id) {
+ wpa_printf(MSG_DEBUG, "WPS: Found a matching Device Password");
+ os_free(wps->dev_password);
+ wps->dev_pw_id = wps->alt_dev_pw_id;
+ wps->dev_password = wps->alt_dev_password;
+ wps->dev_password_len = wps->alt_dev_password_len;
+ wps->alt_dev_password = NULL;
+ wps->alt_dev_password_len = 0;
+ return 0;
+ }
+
+ return -1;
+}
+
+
static enum wps_process_res wps_process_m2(struct wps_data *wps,
const struct wpabuf *msg,
struct wps_parse_attr *attr)
@@ -868,7 +885,8 @@
if (wps_process_registrar_nonce(wps, attr->registrar_nonce) ||
wps_process_enrollee_nonce(wps, attr->enrollee_nonce) ||
- wps_process_uuid_r(wps, attr->uuid_r)) {
+ wps_process_uuid_r(wps, attr->uuid_r) ||
+ wps_process_dev_pw_id(wps, attr->dev_password_id)) {
wps->state = SEND_WSC_NACK;
return WPS_CONTINUE;
}
diff --git a/src/wps/wps_er.c b/src/wps/wps_er.c
index 95a0dec..14c1b77 100644
--- a/src/wps/wps_er.c
+++ b/src/wps/wps_er.c
@@ -1,6 +1,6 @@
/*
* Wi-Fi Protected Setup - External Registrar
- * Copyright (c) 2009-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -97,13 +97,16 @@
static struct wps_er_ap * wps_er_ap_get(struct wps_er *er,
- struct in_addr *addr, const u8 *uuid)
+ struct in_addr *addr, const u8 *uuid,
+ const u8 *mac_addr)
{
struct wps_er_ap *ap;
dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
if ((addr == NULL || ap->addr.s_addr == addr->s_addr) &&
(uuid == NULL ||
- os_memcmp(uuid, ap->uuid, WPS_UUID_LEN) == 0))
+ os_memcmp(uuid, ap->uuid, WPS_UUID_LEN) == 0) &&
+ (mac_addr == NULL ||
+ os_memcmp(mac_addr, ap->mac_addr, ETH_ALEN) == 0))
return ap;
}
return NULL;
@@ -290,7 +293,7 @@
struct wps_er_ap *ap;
struct wps_er_ap_settings *settings;
- ap = wps_er_ap_get(er, addr, NULL);
+ ap = wps_er_ap_get(er, addr, NULL, NULL);
if (ap == NULL || ap->ap_settings == NULL)
return -1;
@@ -636,7 +639,7 @@
{
struct wps_er_ap *ap;
- ap = wps_er_ap_get(er, addr, uuid);
+ ap = wps_er_ap_get(er, addr, uuid, NULL);
if (ap) {
/* Update advertisement timeout */
eloop_cancel_timeout(wps_er_ap_timeout, er, ap);
@@ -1555,7 +1558,7 @@
}
-int wps_er_pbc(struct wps_er *er, const u8 *uuid)
+int wps_er_pbc(struct wps_er *er, const u8 *uuid, const u8 *addr)
{
int res;
struct wps_er_ap *ap;
@@ -1569,11 +1572,14 @@
return -2;
}
- ap = wps_er_ap_get(er, NULL, uuid);
+ if (uuid)
+ ap = wps_er_ap_get(er, NULL, uuid, NULL);
+ else
+ ap = NULL;
if (ap == NULL) {
struct wps_er_sta *sta = NULL;
dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
- sta = wps_er_sta_get(ap, NULL, uuid);
+ sta = wps_er_sta_get(ap, addr, uuid);
if (sta) {
uuid = ap->uuid;
break;
@@ -1619,6 +1625,19 @@
}
+const u8 * wps_er_get_sta_uuid(struct wps_er *er, const u8 *addr)
+{
+ struct wps_er_ap *ap;
+ dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
+ struct wps_er_sta *sta;
+ sta = wps_er_sta_get(ap, addr, NULL);
+ if (sta)
+ return sta->uuid;
+ }
+ return NULL;
+}
+
+
static void wps_er_http_put_message_cb(void *ctx, struct http_client *c,
enum http_client_event event)
{
@@ -1877,20 +1896,22 @@
}
-int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *pin,
- size_t pin_len)
+int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *addr,
+ const u8 *pin, size_t pin_len)
{
struct wps_er_ap *ap;
if (er == NULL)
return -1;
- ap = wps_er_ap_get(er, NULL, uuid);
+ ap = wps_er_ap_get(er, NULL, uuid, addr);
if (ap == NULL) {
wpa_printf(MSG_DEBUG, "WPS ER: AP not found for learn "
"request");
return -1;
}
+ if (uuid == NULL)
+ uuid = ap->uuid;
if (ap->wps) {
wpa_printf(MSG_DEBUG, "WPS ER: Pending operation ongoing "
"with the AP - cannot start learn");
@@ -1908,7 +1929,7 @@
}
-int wps_er_set_config(struct wps_er *er, const u8 *uuid,
+int wps_er_set_config(struct wps_er *er, const u8 *uuid, const u8 *addr,
const struct wps_credential *cred)
{
struct wps_er_ap *ap;
@@ -1916,7 +1937,7 @@
if (er == NULL)
return -1;
- ap = wps_er_ap_get(er, NULL, uuid);
+ ap = wps_er_ap_get(er, NULL, uuid, addr);
if (ap == NULL) {
wpa_printf(MSG_DEBUG, "WPS ER: AP not found for set config "
"request");
@@ -1960,20 +1981,23 @@
}
-int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *pin,
- size_t pin_len, const struct wps_credential *cred)
+int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *addr,
+ const u8 *pin, size_t pin_len,
+ const struct wps_credential *cred)
{
struct wps_er_ap *ap;
if (er == NULL)
return -1;
- ap = wps_er_ap_get(er, NULL, uuid);
+ ap = wps_er_ap_get(er, NULL, uuid, addr);
if (ap == NULL) {
wpa_printf(MSG_DEBUG, "WPS ER: AP not found for config "
"request");
return -1;
}
+ if (uuid == NULL)
+ uuid = ap->uuid;
if (ap->wps) {
wpa_printf(MSG_DEBUG, "WPS ER: Pending operation ongoing "
"with the AP - cannot start config");
@@ -1999,31 +2023,20 @@
#ifdef CONFIG_WPS_NFC
-struct wpabuf * wps_er_nfc_config_token(struct wps_er *er, const u8 *uuid)
+
+struct wpabuf * wps_er_config_token_from_cred(struct wps_context *wps,
+ struct wps_credential *cred)
{
- struct wps_er_ap *ap;
struct wpabuf *ret;
struct wps_data data;
- if (er == NULL)
- return NULL;
-
- ap = wps_er_ap_get(er, NULL, uuid);
- if (ap == NULL)
- return NULL;
- if (ap->ap_settings == NULL) {
- wpa_printf(MSG_DEBUG, "WPS ER: No settings known for the "
- "selected AP");
- return NULL;
- }
-
ret = wpabuf_alloc(500);
if (ret == NULL)
return NULL;
os_memset(&data, 0, sizeof(data));
- data.wps = er->wps;
- data.use_cred = ap->ap_settings;
+ data.wps = wps;
+ data.use_cred = cred;
if (wps_build_version(ret) ||
wps_build_cred(&data, ret) ||
wps_build_wfa_ext(ret, 0, NULL, 0)) {
@@ -2033,4 +2046,26 @@
return ret;
}
+
+
+struct wpabuf * wps_er_nfc_config_token(struct wps_er *er, const u8 *uuid,
+ const u8 *addr)
+{
+ struct wps_er_ap *ap;
+
+ if (er == NULL)
+ return NULL;
+
+ ap = wps_er_ap_get(er, NULL, uuid, addr);
+ if (ap == NULL)
+ return NULL;
+ if (ap->ap_settings == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS ER: No settings known for the "
+ "selected AP");
+ return NULL;
+ }
+
+ return wps_er_config_token_from_cred(er->wps, ap->ap_settings);
+}
+
#endif /* CONFIG_WPS_NFC */
diff --git a/src/wps/wps_i.h b/src/wps/wps_i.h
index 86ad248..6efc3bf 100644
--- a/src/wps/wps_i.h
+++ b/src/wps/wps_i.h
@@ -71,6 +71,9 @@
size_t dev_password_len;
u16 dev_pw_id;
int pbc;
+ u8 *alt_dev_password;
+ size_t alt_dev_password_len;
+ u16 alt_dev_pw_id;
/**
* request_type - Request Type attribute from (Re)AssocReq
@@ -137,10 +140,6 @@
void wps_pbc_overlap_event(struct wps_context *wps);
void wps_pbc_timeout_event(struct wps_context *wps);
-extern struct oob_device_data oob_ufd_device_data;
-extern struct oob_device_data oob_nfc_device_data;
-extern struct oob_nfc_device_data oob_nfc_pn531_device_data;
-
struct wpabuf * wps_build_wsc_ack(struct wps_data *wps);
struct wpabuf * wps_build_wsc_nack(struct wps_data *wps);
@@ -169,7 +168,6 @@
int wps_build_oob_dev_pw(struct wpabuf *msg, u16 dev_pw_id,
const struct wpabuf *pubkey, const u8 *dev_pw,
size_t dev_pw_len);
-int wps_build_oob_dev_password(struct wpabuf *msg, struct wps_context *wps);
struct wpabuf * wps_ie_encapsulate(struct wpabuf *data);
/* wps_attr_process.c */
diff --git a/src/wps/wps_nfc.c b/src/wps/wps_nfc.c
deleted file mode 100644
index 6804350..0000000
--- a/src/wps/wps_nfc.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * NFC routines for Wi-Fi Protected Setup
- * Copyright (c) 2009-2012, Masashi Honma <masashi.honma@gmail.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "includes.h"
-#include "common.h"
-
-#include "wps/wps.h"
-#include "wps_i.h"
-
-
-struct wps_nfc_data {
- struct oob_nfc_device_data *oob_nfc_dev;
-};
-
-
-static void * init_nfc(struct wps_context *wps,
- struct oob_device_data *oob_dev, int registrar)
-{
- struct oob_nfc_device_data *oob_nfc_dev;
- struct wps_nfc_data *data;
-
- oob_nfc_dev = wps_get_oob_nfc_device(oob_dev->device_name);
- if (oob_nfc_dev == NULL) {
- wpa_printf(MSG_ERROR, "WPS (NFC): Unknown NFC device (%s)",
- oob_dev->device_name);
- return NULL;
- }
-
- if (oob_nfc_dev->init_func(oob_dev->device_path) < 0)
- return NULL;
-
- data = os_zalloc(sizeof(*data));
- if (data == NULL) {
- wpa_printf(MSG_ERROR, "WPS (NFC): Failed to allocate "
- "nfc data area");
- return NULL;
- }
- data->oob_nfc_dev = oob_nfc_dev;
- return data;
-}
-
-
-static struct wpabuf * read_nfc(void *priv)
-{
- struct wps_nfc_data *data = priv;
- struct wpabuf *wifi, *buf;
- char *raw_data;
- size_t len;
-
- raw_data = data->oob_nfc_dev->read_func(&len);
- if (raw_data == NULL)
- return NULL;
-
- wifi = wpabuf_alloc_copy(raw_data, len);
- os_free(raw_data);
- if (wifi == NULL) {
- wpa_printf(MSG_ERROR, "WPS (NFC): Failed to allocate "
- "nfc read area");
- return NULL;
- }
-
- buf = ndef_parse_wifi(wifi);
- wpabuf_free(wifi);
- if (buf == NULL)
- wpa_printf(MSG_ERROR, "WPS (NFC): Failed to unwrap");
- return buf;
-}
-
-
-static int write_nfc(void *priv, struct wpabuf *buf)
-{
- struct wps_nfc_data *data = priv;
- struct wpabuf *wifi;
- int ret;
-
- wifi = ndef_build_wifi(buf);
- if (wifi == NULL) {
- wpa_printf(MSG_ERROR, "WPS (NFC): Failed to wrap");
- return -1;
- }
-
- ret = data->oob_nfc_dev->write_func(wpabuf_mhead(wifi),
- wpabuf_len(wifi));
- wpabuf_free(wifi);
- return ret;
-}
-
-
-static void deinit_nfc(void *priv)
-{
- struct wps_nfc_data *data = priv;
-
- data->oob_nfc_dev->deinit_func();
-
- os_free(data);
-}
-
-
-struct oob_device_data oob_nfc_device_data = {
- .device_name = NULL,
- .device_path = NULL,
- .init_func = init_nfc,
- .read_func = read_nfc,
- .write_func = write_nfc,
- .deinit_func = deinit_nfc,
-};
diff --git a/src/wps/wps_nfc_pn531.c b/src/wps/wps_nfc_pn531.c
deleted file mode 100644
index c2bf457..0000000
--- a/src/wps/wps_nfc_pn531.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * NFC PN531 routines for Wi-Fi Protected Setup
- * Copyright (c) 2009-2012, Masashi Honma <masashi.honma@gmail.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "includes.h"
-#include "common.h"
-
-#include "wps/wps.h"
-#include "wps_i.h"
-
-#include "WpsNfcType.h"
-#include "WpsNfc.h"
-
-
-static int init_nfc_pn531(char *path)
-{
- u32 ret;
-
- ret = WpsNfcInit();
- if (ret != WPS_NFCLIB_ERR_SUCCESS) {
- wpa_printf(MSG_ERROR, "WPS (PN531): Failed to initialize "
- "NFC Library: 0x%08x", ret);
- return -1;
- }
-
- ret = WpsNfcOpenDevice((int8 *) path);
- if (ret != WPS_NFCLIB_ERR_SUCCESS) {
- wpa_printf(MSG_ERROR, "WPS (PN531): Failed to open "
- "NFC Device(%s): 0x%08x", path, ret);
- goto fail;
- }
-
- ret = WpsNfcTokenDiscovery();
- if (ret != WPS_NFCLIB_ERR_SUCCESS) {
- wpa_printf(MSG_ERROR, "WPS (PN531): Failed to discover "
- "token: 0x%08x", ret);
- WpsNfcCloseDevice();
- goto fail;
- }
-
- return 0;
-
-fail:
- WpsNfcDeinit();
- return -1;
-}
-
-
-static void * read_nfc_pn531(size_t *size)
-{
- uint32 len;
- u32 ret;
- int8 *data;
-
- ret = WpsNfcRawReadToken(&data, &len);
- if (ret != WPS_NFCLIB_ERR_SUCCESS) {
- wpa_printf(MSG_ERROR, "WPS (PN531): Failed to read: 0x%08x",
- ret);
- return NULL;
- }
-
- *size = len;
- return data;
-}
-
-
-static int write_nfc_pn531(void *data, size_t len)
-{
- u32 ret;
-
- ret = WpsNfcRawWriteToken(data, len);
- if (ret != WPS_NFCLIB_ERR_SUCCESS) {
- wpa_printf(MSG_ERROR, "WPS (PN531): Failed to write: 0x%08x",
- ret);
- return -1;
- }
-
- return 0;
-}
-
-
-static void deinit_nfc_pn531(void)
-{
- u32 ret;
-
- ret = WpsNfcCloseDevice();
- if (ret != WPS_NFCLIB_ERR_SUCCESS)
- wpa_printf(MSG_ERROR, "WPS (PN531): Failed to close "
- "NFC Device: 0x%08x", ret);
-
- ret = WpsNfcDeinit();
- if (ret != WPS_NFCLIB_ERR_SUCCESS)
- wpa_printf(MSG_ERROR, "WPS (PN531): Failed to deinitialize "
- "NFC Library: 0x%08x", ret);
-}
-
-
-struct oob_nfc_device_data oob_nfc_pn531_device_data = {
- .init_func = init_nfc_pn531,
- .read_func = read_nfc_pn531,
- .write_func = write_nfc_pn531,
- .deinit_func = deinit_nfc_pn531,
-};
diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c
index 53684d6..86ef022 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -32,7 +32,7 @@
struct dl_list list;
u8 pubkey_hash[WPS_OOB_PUBKEY_HASH_LEN];
u16 pw_id;
- u8 dev_pw[WPS_OOB_DEVICE_PASSWORD_LEN];
+ u8 dev_pw[WPS_OOB_DEVICE_PASSWORD_LEN * 2 + 1];
size_t dev_pw_len;
};
@@ -180,6 +180,9 @@
u8 authorized_macs_union[WPS_MAX_AUTHORIZED_MACS][ETH_ALEN];
u8 p2p_dev_addr[ETH_ALEN];
+
+ u8 pbc_ignore_uuid[WPS_UUID_LEN];
+ struct os_time pbc_ignore_start;
};
@@ -187,6 +190,8 @@
static void wps_registrar_pbc_timeout(void *eloop_ctx, void *timeout_ctx);
static void wps_registrar_set_selected_timeout(void *eloop_ctx,
void *timeout_ctx);
+static void wps_registrar_remove_pin(struct wps_registrar *reg,
+ struct wps_uuid_pin *pin);
static void wps_registrar_add_authorized_mac(struct wps_registrar *reg,
@@ -696,6 +701,21 @@
}
+static void wps_registrar_invalidate_unused(struct wps_registrar *reg)
+{
+ struct wps_uuid_pin *pin;
+
+ dl_list_for_each(pin, ®->pins, struct wps_uuid_pin, list) {
+ if (pin->wildcard_uuid == 1 && !(pin->flags & PIN_LOCKED)) {
+ wpa_printf(MSG_DEBUG, "WPS: Invalidate previously "
+ "configured wildcard PIN");
+ wps_registrar_remove_pin(reg, pin);
+ break;
+ }
+ }
+}
+
+
/**
* wps_registrar_add_pin - Configure a new PIN for Registrar
* @reg: Registrar data from wps_registrar_init()
@@ -735,6 +755,9 @@
p->expiration.sec += timeout;
}
+ if (p->wildcard_uuid)
+ wps_registrar_invalidate_unused(reg);
+
dl_list_add(®->pins, &p->list);
wpa_printf(MSG_DEBUG, "WPS: A new PIN configured (timeout=%d)",
@@ -1015,6 +1038,8 @@
wps_registrar_remove_pbc_session(registrar,
uuid_e, NULL);
wps_registrar_pbc_completed(registrar);
+ os_get_time(®istrar->pbc_ignore_start);
+ os_memcpy(registrar->pbc_ignore_uuid, uuid_e, WPS_UUID_LEN);
} else {
wps_registrar_pin_completed(registrar);
}
@@ -1061,6 +1086,7 @@
int p2p_wildcard)
{
struct wps_parse_attr attr;
+ int skip_add = 0;
wpa_hexdump_buf(MSG_MSGDUMP,
"WPS: Probe Request with WPS data received",
@@ -1112,7 +1138,24 @@
wpa_hexdump(MSG_DEBUG, "WPS: UUID-E from Probe Request", attr.uuid_e,
WPS_UUID_LEN);
- wps_registrar_add_pbc_session(reg, addr, attr.uuid_e);
+#ifdef WPS_WORKAROUNDS
+ if (reg->pbc_ignore_start.sec &&
+ os_memcmp(attr.uuid_e, reg->pbc_ignore_uuid, WPS_UUID_LEN) == 0) {
+ struct os_time now, dur;
+ os_get_time(&now);
+ os_time_sub(&now, ®->pbc_ignore_start, &dur);
+ if (dur.sec >= 0 && dur.sec < 5) {
+ wpa_printf(MSG_DEBUG, "WPS: Ignore PBC activation "
+ "based on Probe Request from the Enrollee "
+ "that just completed PBC provisioning");
+ skip_add = 1;
+ } else
+ reg->pbc_ignore_start.sec = 0;
+ }
+#endif /* WPS_WORKAROUNDS */
+
+ if (!skip_add)
+ wps_registrar_add_pbc_session(reg, addr, attr.uuid_e);
if (wps_registrar_pbc_overlap(reg, addr, attr.uuid_e)) {
wpa_printf(MSG_DEBUG, "WPS: PBC session overlap detected");
reg->force_pbc_overlap = 1;
@@ -1255,7 +1298,7 @@
wps_build_uuid_e(probe, reg->wps->uuid) ||
wps_build_device_attrs(®->wps->dev, probe) ||
wps_build_probe_config_methods(reg, probe) ||
- wps_build_rf_bands(®->wps->dev, probe) ||
+ (reg->dualband && wps_build_rf_bands(®->wps->dev, probe)) ||
wps_build_wfa_ext(probe, 0, auth_macs, count) ||
wps_build_vendor_ext(®->wps->dev, probe)) {
wpabuf_free(beacon);
@@ -1320,6 +1363,14 @@
} else {
pin = wps_registrar_get_pin(wps->wps->registrar, wps->uuid_e,
&pin_len);
+ if (pin && wps->dev_pw_id >= 0x10) {
+ wpa_printf(MSG_DEBUG, "WPS: No match for OOB Device "
+ "Password ID, but PIN found");
+ /*
+ * See whether Enrollee is willing to use PIN instead.
+ */
+ wps->dev_pw_id = DEV_PW_DEFAULT;
+ }
}
if (pin == NULL) {
wpa_printf(MSG_DEBUG, "WPS: No Device Password available for "
@@ -2218,22 +2269,6 @@
return -1;
}
-#ifdef CONFIG_WPS_OOB
- if (wps->wps->oob_conf.pubkey_hash != NULL) {
- const u8 *addr[1];
- u8 hash[WPS_HASH_LEN];
-
- addr[0] = pk;
- sha256_vector(1, addr, &pk_len, hash);
- if (os_memcmp(hash,
- wpabuf_head(wps->wps->oob_conf.pubkey_hash),
- WPS_OOB_PUBKEY_HASH_LEN) != 0) {
- wpa_printf(MSG_ERROR, "WPS: Public Key hash error");
- return -1;
- }
- }
-#endif /* CONFIG_WPS_OOB */
-
wpabuf_free(wps->dh_pubkey_e);
wps->dh_pubkey_e = wpabuf_alloc_copy(pk, pk_len);
if (wps->dh_pubkey_e == NULL)
@@ -2529,16 +2564,6 @@
}
#endif /* CONFIG_WPS_NFC */
-#ifdef CONFIG_WPS_OOB
- if (wps->dev_pw_id >= 0x10 && wps->nfc_pw_token == NULL &&
- wps->dev_pw_id != wps->wps->oob_dev_pw_id) {
- wpa_printf(MSG_DEBUG, "WPS: OOB Device Password ID "
- "%d mismatch", wps->dev_pw_id);
- wps->state = SEND_M2D;
- return WPS_CONTINUE;
- }
-#endif /* CONFIG_WPS_OOB */
-
if (wps->dev_pw_id == DEV_PW_PUSHBUTTON) {
if ((wps->wps->registrar->force_pbc_overlap ||
wps_registrar_pbc_overlap(wps->wps->registrar,
@@ -3168,6 +3193,9 @@
wps->uuid_e,
wps->p2p_dev_addr);
wps_registrar_pbc_completed(wps->wps->registrar);
+ os_get_time(&wps->wps->registrar->pbc_ignore_start);
+ os_memcpy(wps->wps->registrar->pbc_ignore_uuid, wps->uuid_e,
+ WPS_UUID_LEN);
} else {
wps_registrar_pin_completed(wps->wps->registrar);
}
@@ -3475,8 +3503,10 @@
os_memcpy(token->pubkey_hash, pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
token->pw_id = pw_id;
- os_memcpy(token->dev_pw, dev_pw, dev_pw_len);
- token->dev_pw_len = dev_pw_len;
+ wpa_snprintf_hex_uppercase((char *) token->dev_pw,
+ sizeof(token->dev_pw),
+ dev_pw, dev_pw_len);
+ token->dev_pw_len = dev_pw_len * 2;
dl_list_add(®->nfc_pw_tokens, &token->list);
diff --git a/src/wps/wps_ufd.c b/src/wps/wps_ufd.c
deleted file mode 100644
index f83bdf4..0000000
--- a/src/wps/wps_ufd.c
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * UFD routines for Wi-Fi Protected Setup
- * Copyright (c) 2009-2012, Masashi Honma <masashi.honma@gmail.com>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "includes.h"
-#include "common.h"
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <dirent.h>
-
-#include "wps/wps.h"
-#include "wps/wps_i.h"
-
-#ifdef CONFIG_NATIVE_WINDOWS
-#define UFD_DIR1 "%s\\SMRTNTKY"
-#define UFD_DIR2 UFD_DIR1 "\\WFAWSC"
-#define UFD_FILE UFD_DIR2 "\\%s"
-#else /* CONFIG_NATIVE_WINDOWS */
-#define UFD_DIR1 "%s/SMRTNTKY"
-#define UFD_DIR2 UFD_DIR1 "/WFAWSC"
-#define UFD_FILE UFD_DIR2 "/%s"
-#endif /* CONFIG_NATIVE_WINDOWS */
-
-
-struct wps_ufd_data {
- int ufd_fd;
-};
-
-
-static int dev_pwd_e_file_filter(const struct dirent *entry)
-{
- unsigned int prefix;
- char ext[5];
-
- if (sscanf(entry->d_name, "%8x.%4s", &prefix, ext) != 2)
- return 0;
- if (prefix == 0)
- return 0;
- if (os_strcasecmp(ext, "WFA") != 0)
- return 0;
-
- return 1;
-}
-
-
-static int wps_get_dev_pwd_e_file_name(char *path, char *file_name)
-{
- struct dirent **namelist;
- int i, file_num;
-
- file_num = scandir(path, &namelist, &dev_pwd_e_file_filter,
- alphasort);
- if (file_num < 0) {
- wpa_printf(MSG_ERROR, "WPS: OOB file not found: %d (%s)",
- errno, strerror(errno));
- return -1;
- }
- if (file_num == 0) {
- wpa_printf(MSG_ERROR, "WPS: OOB file not found");
- os_free(namelist);
- return -1;
- }
- os_strlcpy(file_name, namelist[0]->d_name, 13);
- for (i = 0; i < file_num; i++)
- os_free(namelist[i]);
- os_free(namelist);
- return 0;
-}
-
-
-static int get_file_name(struct wps_context *wps, int registrar,
- const char *path, char *file_name)
-{
- switch (wps->oob_conf.oob_method) {
- case OOB_METHOD_CRED:
- os_snprintf(file_name, 13, "00000000.WSC");
- break;
- case OOB_METHOD_DEV_PWD_E:
- if (registrar) {
- char temp[128];
- os_snprintf(temp, sizeof(temp), UFD_DIR2, path);
- if (wps_get_dev_pwd_e_file_name(temp, file_name) < 0)
- return -1;
- } else {
- u8 *mac_addr = wps->dev.mac_addr;
-
- os_snprintf(file_name, 13, "%02X%02X%02X%02X.WFA",
- mac_addr[2], mac_addr[3], mac_addr[4],
- mac_addr[5]);
- }
- break;
- case OOB_METHOD_DEV_PWD_R:
- os_snprintf(file_name, 13, "00000000.WFA");
- break;
- default:
- wpa_printf(MSG_ERROR, "WPS: Invalid USBA OOB method");
- return -1;
- }
- return 0;
-}
-
-
-static int ufd_mkdir(const char *path)
-{
- if (mkdir(path, S_IRWXU) < 0 && errno != EEXIST) {
- wpa_printf(MSG_ERROR, "WPS (UFD): Failed to create directory "
- "'%s': %d (%s)", path, errno, strerror(errno));
- return -1;
- }
- return 0;
-}
-
-
-static void * init_ufd(struct wps_context *wps,
- struct oob_device_data *oob_dev, int registrar)
-{
- int write_f;
- char temp[128];
- char *path = oob_dev->device_path;
- char filename[13];
- struct wps_ufd_data *data;
- int ufd_fd;
-
- if (path == NULL)
- return NULL;
-
- write_f = wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_E ?
- !registrar : registrar;
-
- if (get_file_name(wps, registrar, path, filename) < 0) {
- wpa_printf(MSG_ERROR, "WPS (UFD): Failed to get file name");
- return NULL;
- }
-
- if (write_f) {
- os_snprintf(temp, sizeof(temp), UFD_DIR1, path);
- if (ufd_mkdir(temp))
- return NULL;
- os_snprintf(temp, sizeof(temp), UFD_DIR2, path);
- if (ufd_mkdir(temp))
- return NULL;
- }
-
- os_snprintf(temp, sizeof(temp), UFD_FILE, path, filename);
- if (write_f)
- ufd_fd = open(temp, O_WRONLY | O_CREAT | O_TRUNC,
- S_IRUSR | S_IWUSR);
- else
- ufd_fd = open(temp, O_RDONLY);
- if (ufd_fd < 0) {
- wpa_printf(MSG_ERROR, "WPS (UFD): Failed to open %s: %s",
- temp, strerror(errno));
- return NULL;
- }
-
- data = os_zalloc(sizeof(*data));
- if (data == NULL) {
- close(ufd_fd);
- return NULL;
- }
- data->ufd_fd = ufd_fd;
- return data;
-}
-
-
-static struct wpabuf * read_ufd(void *priv)
-{
- struct wps_ufd_data *data = priv;
- struct wpabuf *buf;
- struct stat s;
- size_t file_size;
-
- if (fstat(data->ufd_fd, &s) < 0) {
- wpa_printf(MSG_ERROR, "WPS (UFD): Failed to get file size");
- return NULL;
- }
-
- file_size = s.st_size;
- buf = wpabuf_alloc(file_size);
- if (buf == NULL) {
- wpa_printf(MSG_ERROR, "WPS (UFD): Failed to alloc read "
- "buffer");
- return NULL;
- }
-
- if (read(data->ufd_fd, wpabuf_mhead(buf), file_size) !=
- (int) file_size) {
- wpabuf_free(buf);
- wpa_printf(MSG_ERROR, "WPS (UFD): Failed to read");
- return NULL;
- }
- wpabuf_put(buf, file_size);
- return buf;
-}
-
-
-static int write_ufd(void *priv, struct wpabuf *buf)
-{
- struct wps_ufd_data *data = priv;
-
- if (write(data->ufd_fd, wpabuf_mhead(buf), wpabuf_len(buf)) !=
- (int) wpabuf_len(buf)) {
- wpa_printf(MSG_ERROR, "WPS (UFD): Failed to write");
- return -1;
- }
- return 0;
-}
-
-
-static void deinit_ufd(void *priv)
-{
- struct wps_ufd_data *data = priv;
- close(data->ufd_fd);
- os_free(data);
-}
-
-
-struct oob_device_data oob_ufd_device_data = {
- .device_name = NULL,
- .device_path = NULL,
- .init_func = init_ufd,
- .read_func = read_ufd,
- .write_func = write_ufd,
- .deinit_func = deinit_ufd,
-};
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 33e4579..a0c97f0 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -31,10 +31,10 @@
ifeq ($(BOARD_WLAN_DEVICE), bcmdhd)
L_CFLAGS += -DANDROID_P2P
+L_CFLAGS += -DP2P_CONCURRENT_SEARCH_DELAY=0
endif
ifeq ($(BOARD_WLAN_DEVICE), qcwcn)
-L_CFLAGS += -DANDROID_QCOM_WCN
L_CFLAGS += -DANDROID_P2P
endif
@@ -147,6 +147,10 @@
L_CFLAGS += -DCONFIG_HT_OVERRIDES
endif
+ifdef CONFIG_VHT_OVERRIDES
+L_CFLAGS += -DCONFIG_VHT_OVERRIDES
+endif
+
ifndef CONFIG_BACKEND
CONFIG_BACKEND=file
endif
@@ -193,8 +197,15 @@
NEED_AES_OMAC1=y
endif
-ifdef CONFIG_IEEE80211V
-L_CFLAGS += -DCONFIG_IEEE80211V
+ifdef CONFIG_SAE
+L_CFLAGS += -DCONFIG_SAE
+OBJS += src/common/sae.c
+NEED_ECC=y
+NEED_DH_GROUPS=y
+endif
+
+ifdef CONFIG_WNM
+L_CFLAGS += -DCONFIG_WNM
OBJS += wnm_sta.c
endif
@@ -333,6 +344,17 @@
CONFIG_IEEE8021X_EAPOL=y
endif
+ifdef CONFIG_EAP_UNAUTH_TLS
+# EAP-UNAUTH-TLS
+L_CFLAGS += -DEAP_UNAUTH_TLS
+ifndef CONFIG_EAP_UNAUTH_TLS
+OBJS += src/eap_peer/eap_tls.c
+OBJS_h += src/eap_server/eap_server_tls.c
+TLS_FUNCS=y
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
ifdef CONFIG_EAP_PEAP
# EAP-PEAP
ifeq ($(CONFIG_EAP_PEAP), dyn)
@@ -486,6 +508,13 @@
NEED_AES_CBC=y
endif
+ifdef CONFIG_EAP_PROXY
+L_CFLAGS += -DCONFIG_EAP_PROXY
+OBJS += src/eap_peer/eap_proxy_$(CONFIG_EAP_PROXY).c
+include eap_proxy_$(CONFIG_EAP_PROXY).mk
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
ifdef CONFIG_EAP_AKA_PRIME
# EAP-AKA'
ifeq ($(CONFIG_EAP_AKA_PRIME), dyn)
@@ -567,7 +596,7 @@
ifdef CONFIG_EAP_PWD
L_CFLAGS += -DEAP_PWD
OBJS += src/eap_peer/eap_pwd.c src/eap_common/eap_pwd_common.c
-OBJS_h += src/eap_server/eap_pwd.c
+OBJS_h += src/eap_server/eap_server_pwd.c
CONFIG_IEEE8021X_EAPOL=y
NEED_SHA256=y
endif
@@ -599,25 +628,10 @@
NEED_AES_CBC=y
NEED_MODEXP=y
-ifdef CONFIG_WPS_UFD
-L_CFLAGS += -DCONFIG_WPS_UFD
-OBJS += src/wps/wps_ufd.c
-NEED_WPS_OOB=y
-endif
-
ifdef CONFIG_WPS_NFC
L_CFLAGS += -DCONFIG_WPS_NFC
OBJS += src/wps/ndef.c
-OBJS += src/wps/wps_nfc.c
NEED_WPS_OOB=y
-ifdef CONFIG_WPS_NFC_PN531
-PN531_PATH ?= /usr/local/src/nfc
-L_CFLAGS += -DCONFIG_WPS_NFC_PN531
-L_CFLAGS += -I${PN531_PATH}/inc
-OBJS += src/wps/wps_nfc_pn531.c
-LIBS += ${PN531_PATH}/lib/wpsnfc.dll
-LIBS += ${PN531_PATH}/lib/libnfc_mapping_pn53x.dll
-endif
endif
ifdef NEED_WPS_OOB
@@ -743,9 +757,13 @@
OBJS += src/ap/drv_callbacks.c
OBJS += src/ap/ap_drv_ops.c
OBJS += src/ap/beacon.c
+OBJS += src/ap/eap_user_db.c
ifdef CONFIG_IEEE80211N
OBJS += src/ap/ieee802_11_ht.c
endif
+ifdef CONFIG_WNM
+OBJS += src/ap/wnm_ap.c
+endif
ifdef CONFIG_CTRL_IFACE
OBJS += src/ap/ctrl_iface_ap.c
endif
@@ -759,10 +777,6 @@
L_CFLAGS += -DCONFIG_IEEE80211N
endif
-ifdef CONFIG_WNM
-L_CFLAGS += -DCONFIG_WNM
-endif
-
ifdef NEED_AP_MLME
OBJS += src/ap/wmm.c
OBJS += src/ap/ap_list.c
@@ -881,6 +895,8 @@
OBJS_h += src/eap_server/eap_server_tls_common.c
ifndef CONFIG_FIPS
NEED_TLS_PRF=y
+NEED_SHA1=y
+NEED_MD5=y
endif
endif
@@ -910,6 +926,10 @@
endif
LIBS += -lcrypto
LIBS_p += -lcrypto
+ifdef CONFIG_TLS_ADD_DL
+LIBS += -ldl
+LIBS_p += -ldl
+endif
endif
ifeq ($(CONFIG_TLS), gnutls)
@@ -1139,10 +1159,7 @@
endif
endif
-MD5OBJS =
-ifndef CONFIG_FIPS
-MD5OBJS += src/crypto/md5.c
-endif
+MD5OBJS = src/crypto/md5.c
ifdef NEED_MD5
ifdef CONFIG_INTERNAL_MD5
MD5OBJS += src/crypto/md5-internal.c
@@ -1198,6 +1215,10 @@
endif
endif
+ifdef NEED_ECC
+L_CFLAGS += -DCONFIG_ECC
+endif
+
ifdef CONFIG_NO_RANDOM_POOL
L_CFLAGS += -DCONFIG_NO_RANDOM_POOL
else
@@ -1503,7 +1524,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE := wpa_cli
LOCAL_MODULE_TAGS := debug
-LOCAL_SHARED_LIBRARIES := libc libcutils
+LOCAL_SHARED_LIBRARIES := libc libcutils liblog
LOCAL_CFLAGS := $(L_CFLAGS)
LOCAL_SRC_FILES := $(OBJS_c)
LOCAL_C_INCLUDES := $(INCLUDES)
@@ -1518,7 +1539,7 @@
ifneq ($(BOARD_WPA_SUPPLICANT_PRIVATE_LIB),)
LOCAL_STATIC_LIBRARIES += $(BOARD_WPA_SUPPLICANT_PRIVATE_LIB)
endif
-LOCAL_SHARED_LIBRARIES := libc libcutils
+LOCAL_SHARED_LIBRARIES := libc libcutils liblog
ifeq ($(CONFIG_TLS), openssl)
LOCAL_SHARED_LIBRARIES += libcrypto libssl libkeystore_binder
endif
@@ -1561,7 +1582,7 @@
LOCAL_CFLAGS = $(L_CFLAGS)
LOCAL_SRC_FILES = src/common/wpa_ctrl.c src/utils/os_$(CONFIG_OS).c
LOCAL_C_INCLUDES = $(INCLUDES)
-LOCAL_SHARED_LIBRARIES := libcutils
+LOCAL_SHARED_LIBRARIES := libcutils liblog
LOCAL_COPY_HEADERS_TO := libwpa_client
LOCAL_COPY_HEADERS := src/common/wpa_ctrl.h
include $(BUILD_SHARED_LIBRARY)
diff --git a/wpa_supplicant/ChangeLog b/wpa_supplicant/ChangeLog
index 650b8a0..3f10e11 100644
--- a/wpa_supplicant/ChangeLog
+++ b/wpa_supplicant/ChangeLog
@@ -1,5 +1,239 @@
ChangeLog for wpa_supplicant
+????-??-?? - v2.1
+ * added support for simulataneous authentication of equals (SAE) for
+ stronger password-based authentication with WPA2-Personal
+
+2013-01-12 - v2.0
+ * removed Qt3-based wpa_gui (obsoleted by wpa_qui-qt4)
+ * removed unmaintained driver wrappers broadcom, iphone, osx, ralink,
+ hostap, madwifi (hostap and madwifi remain available for hostapd;
+ their wpa_supplicant functionality is obsoleted by wext)
+ * improved debug logging (human readable event names, interface name
+ included in more entries)
+ * changed AP mode behavior to enable WPS only for open and
+ WPA/WPA2-Personal configuration
+ * improved P2P concurrency operations
+ - better coordination of concurrent scan and P2P search operations
+ - avoid concurrent remain-on-channel operation requests by canceling
+ previous operations prior to starting a new one
+ - reject operations that would require multi-channel concurrency if
+ the driver does not support it
+ - add parameter to select whether STA or P2P connection is preferred
+ if the driver cannot support both at the same time
+ - allow driver to indicate channel changes
+ - added optional delay=<search delay in milliseconds> parameter for
+ p2p_find to avoid taking all radio resources
+ - use 500 ms p2p_find search delay by default during concurrent
+ operations
+ - allow all channels in GO Negotiation if the driver supports
+ multi-channel concurrency
+ * added number of small changes to make it easier for static analyzers
+ to understand the implementation
+ * fixed number of small bugs (see git logs for more details)
+ * nl80211: number of updates to use new cfg80211/nl80211 functionality
+ - replace monitor interface with nl80211 commands for AP mode
+ - additional information for driver-based AP SME
+ - STA entry authorization in RSN IBSS
+ * EAP-pwd:
+ - fixed KDF for group 21 and zero-padding
+ - added support for fragmentation
+ - increased maximum number of hunting-and-pecking iterations
+ * avoid excessive Probe Response retries for broadcast Probe Request
+ frames (only with drivers using wpa_supplicant AP mode SME/MLME)
+ * added "GET country" ctrl_iface command
+ * do not save an invalid network block in wpa_supplicant.conf to avoid
+ problems reading the file on next start
+ * send STA connected/disconnected ctrl_iface events to both the P2P
+ group and parent interfaces
+ * added preliminary support for using TLS v1.2 (CONFIG_TLSV12=y)
+ * added "SET pno <1/0>" ctrl_iface command to start/stop preferred
+ network offload with sched_scan driver command
+ * merged in number of changes from Android repository for P2P, nl80211,
+ and build parameters
+ * changed P2P GO mode configuration to use driver capabilities to
+ automatically enable HT operations when supported
+ * added "wpa_cli status wps" command to fetch WPA2-Personal passhrase
+ for WPS use cases in AP mode
+ * EAP-AKA: keep pseudonym identity across EAP exchanges to match EAP-SIM
+ behavior
+ * improved reassociation behavior in cases where association is rejected
+ or when an AP disconnects us to handle common load balancing
+ mechanisms
+ - try to avoid extra scans when the needed information is available
+ * added optional "join" argument for p2p_prov_disc ctrl_iface command
+ * added group ifname to P2P-PROV-DISC-* events
+ * added P2P Device Address to AP-STA-DISCONNECTED event and use
+ p2p_dev_addr parameter name with AP-STA-CONNECTED
+ * added workarounds for WPS PBC overlap detection for some P2P use cases
+ where deployed stations work incorrectly
+ * optimize WPS connection speed by disconnecting prior to WPS scan and
+ by using single channel scans when AP channel is known
+ * PCSC and SIM/USIM improvements:
+ - accept 0x67 (Wrong length) as a response to READ RECORD to fix
+ issues with some USIM cards
+ - try to read MNC length from SIM/USIM
+ - build realm according to 3GPP TS 23.003 with identity from the SIM
+ - allow T1 protocol to be enabled
+ * added more WPS and P2P information available through D-Bus
+ * improve P2P negotiation robustness
+ - extra waits to get ACK frames through
+ - longer timeouts for cases where deployed devices have been
+ identified have issues meeting the specification requirements
+ - more retries for some P2P frames
+ - handle race conditions in GO Negotiation start by both devices
+ - ignore unexpected GO Negotiation Response frame
+ * added support for libnl 3.2 and newer
+ * added P2P persistent group info to P2P_PEER data
+ * maintain a list of P2P Clients for persistent group on GO
+ * AP: increased initial group key handshake retransmit timeout to 500 ms
+ * added optional dev_id parameter for p2p_find
+ * added P2P-FIND-STOPPED ctrl_iface event
+ * fixed issues in WPA/RSN element validation when roaming with ap_scan=1
+ and driver-based BSS selection
+ * do not expire P2P peer entries while connected with the peer in a
+ group
+ * fixed WSC element inclusion in cases where P2P is disabled
+ * AP: added a WPS workaround for mixed mode AP Settings with Windows 7
+ * EAP-SIM: fixed AT_COUNTER_TOO_SMALL use
+ * EAP-SIM/AKA: append realm to pseudonym identity
+ * EAP-SIM/AKA: store pseudonym identity in network configuration to
+ allow it to persist over multiple EAP sessions and wpa_supplicant
+ restarts
+ * EAP-AKA': updated to RFC 5448 (username prefixes changed); note: this
+ breaks interoperability with older versions
+ * added support for WFA Hotspot 2.0
+ - GAS/ANQP to fetch network information
+ - credential configuration and automatic network selections based on
+ credential match with ANQP information
+ * limited PMKSA cache entries to be used only with the network context
+ that was used to create them
+ * improved PMKSA cache expiration to avoid unnecessary disconnections
+ * adjusted bgscan_simple fast-scan backoff to avoid too frequent
+ background scans
+ * removed ctrl_iface event on P2P PD Response in join-group case
+ * added option to fetch BSS table entry based on P2P Device Address
+ ("BSS p2p_dev_addr=<P2P Device Address>")
+ * added BSS entry age to ctrl_iface BSS command output
+ * added optional MASK=0xH option for ctrl_iface BSS command to select
+ which fields are included in the response
+ * added optional RANGE=ALL|N1-N2 option for ctrl_iface BSS command to
+ fetch information about several BSSes in one call
+ * simplified licensing terms by selecting the BSD license as the only
+ alternative
+ * added "P2P_SET disallow_freq <freq list>" ctrl_iface command to
+ disable channels from P2P use
+ * added p2p_pref_chan configuration parameter to allow preferred P2P
+ channels to be specified
+ * added support for advertising immediate availability of a WPS
+ credential for P2P use cases
+ * optimized scan operations for P2P use cases (use single channel scan
+ for a specific SSID when possible)
+ * EAP-TTLS: fixed peer challenge generation for MSCHAPv2
+ * SME: do not use reassociation after explicit disconnection request
+ (local or a notification from an AP)
+ * added support for sending debug info to Linux tracing (-T on command
+ line)
+ * added support for using Deauthentication reason code 3 as an
+ indication of P2P group termination
+ * added wps_vendor_ext_m1 configuration parameter to allow vendor
+ specific attributes to be added to WPS M1
+ * started using separate TLS library context for tunneled TLS
+ (EAP-PEAP/TLS, EAP-TTLS/TLS, EAP-FAST/TLS) to support different CA
+ certificate configuration between Phase 1 and Phase 2
+ * added optional "auto" parameter for p2p_connect to request automatic
+ GO Negotiation vs. join-a-group selection
+ * added disabled_scan_offload parameter to disable automatic scan
+ offloading (sched_scan)
+ * added optional persistent=<network id> parameter for p2p_connect to
+ allow forcing of a specific SSID/passphrase for GO Negotiation
+ * added support for OBSS scan requests and 20/40 BSS coexistence reports
+ * reject PD Request for unknown group
+ * removed scripts and notes related to Windows binary releases (which
+ have not been used starting from 1.x)
+ * added initial support for WNM operations
+ - Keep-alive based on BSS max idle period
+ - WNM-Sleep Mode
+ - minimal BSS Transition Management processing
+ * added autoscan module to control scanning behavior while not connected
+ - autoscan_periodic and autoscan_exponential modules
+ * added new WPS NFC ctrl_iface mechanism
+ - added initial support NFC connection handover
+ - removed obsoleted WPS_OOB command (including support for deprecated
+ UFD config_method)
+ * added optional framework for external password storage ("ext:<name>")
+ * wpa_cli: added optional support for controlling wpa_supplicant
+ remotely over UDP (CONFIG_CTRL_IFACE=udp-remote) for testing purposes
+ * wpa_cli: extended tab completion to more commands
+ * changed SSID output to use printf-escaped strings instead of masking
+ of non-ASCII characters
+ - SSID can now be configured in the same format: ssid=P"abc\x00test"
+ * removed default ACM=1 from AC_VO and AC_VI
+ * added optional "ht40" argument for P2P ctrl_iface commands to allow
+ 40 MHz channels to be requested on the 5 GHz band
+ * added optional parameters for p2p_invite command to specify channel
+ when reinvoking a persistent group as the GO
+ * improved FIPS mode builds with OpenSSL
+ - "make fips" with CONFIG_FIPS=y to build wpa_supplicant with the
+ OpenSSL FIPS object module
+ - replace low level OpenSSL AES API calls to use EVP
+ - use OpenSSL keying material exporter when possible
+ - do not export TLS keys in FIPS mode
+ - remove MD5 from CONFIG_FIPS=y builds
+ - use OpenSSL function for PKBDF2 passphrase-to-PSK
+ - use OpenSSL HMAC implementation
+ - mix RAND_bytes() output into random_get_bytes() to force OpenSSL
+ DRBG to be used in FIPS mode
+ - use OpenSSL CMAC implementation
+ * added mechanism to disable TLS Session Ticket extension
+ - a workaround for servers that do not support TLS extensions that
+ was enabled by default in recent OpenSSL versions
+ - tls_disable_session_ticket=1
+ - automatically disable TLS Session Ticket extension by default when
+ using EAP-TLS/PEAP/TTLS (i.e., only use it with EAP-FAST)
+ * changed VENDOR-TEST EAP method to use proper private enterprise number
+ (this will not interoperate with older versions)
+ * disable network block temporarily on authentication failures
+ * improved WPS AP selection during WPS PIN iteration
+ * added support for configuring GCMP cipher for IEEE 802.11ad
+ * added support for Wi-Fi Display extensions
+ - WFD_SUBELEMENT_SET ctrl_iface command to configure WFD subelements
+ - SET wifi_display <0/1> to disable/enable WFD support
+ - WFD service discovery
+ - an external program is needed to manage the audio/video streaming
+ and codecs
+ * optimized scan result use for network selection
+ - use the internal BSS table instead of raw scan results
+ - allow unnecessary scans to be skipped if fresh information is
+ available (e.g., after GAS/ANQP round for Interworking)
+ * added support for 256-bit AES with internal TLS implementation
+ * allow peer to propose channel in P2P invitation process for a
+ persistent group
+ * added disallow_aps parameter to allow BSSIDs/SSIDs to be disallowed
+ from network selection
+ * re-enable the networks disabled during WPS operations
+ * allow P2P functionality to be disabled per interface (p2p_disabled=1)
+ * added secondary device types into P2P_PEER output
+ * added an option to disable use of a separate P2P group interface
+ (p2p_no_group_iface=1)
+ * fixed P2P Bonjour SD to match entries with both compressed and not
+ compressed domain name format and support multiple Bonjour PTR matches
+ for the same key
+ * use deauthentication instead of disassociation for all disconnection
+ operations; this removes the now unused disassociate() wpa_driver_ops
+ callback
+ * optimized PSK generation on P2P GO by caching results to avoid
+ multiple PBKDF2 operations
+ * added okc=1 global configuration parameter to allow OKC to be enabled
+ by default for all network blocks
+ * added a workaround for WPS PBC session overlap detection to avoid
+ interop issues with deployed station implementations that do not
+ remove active PBC indication from Probe Request frames properly
+ * added basic support for 60 GHz band
+ * extend EAPOL frames processing workaround for roaming cases
+ (postpone processing of unexpected EAPOL frame until association
+ event to handle reordered events)
+
2012-05-10 - v1.0
* bsd: Add support for setting HT values in IFM_MMASK.
* Delay STA entry removal until Deauth/Disassoc TX status in AP mode.
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 227fb4f..0634219 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -126,6 +126,10 @@
CFLAGS += -DCONFIG_HT_OVERRIDES
endif
+ifdef CONFIG_VHT_OVERRIDES
+CFLAGS += -DCONFIG_VHT_OVERRIDES
+endif
+
ifndef CONFIG_BACKEND
CONFIG_BACKEND=file
endif
@@ -172,8 +176,15 @@
NEED_AES_OMAC1=y
endif
-ifdef CONFIG_IEEE80211V
-CFLAGS += -DCONFIG_IEEE80211V
+ifdef CONFIG_SAE
+CFLAGS += -DCONFIG_SAE
+OBJS += ../src/common/sae.o
+NEED_ECC=y
+NEED_DH_GROUPS=y
+endif
+
+ifdef CONFIG_WNM
+CFLAGS += -DCONFIG_WNM
OBJS += wnm_sta.o
endif
@@ -475,6 +486,13 @@
NEED_AES_CBC=y
endif
+ifdef CONFIG_EAP_PROXY
+CFLAGS += -DCONFIG_EAP_PROXY
+OBJS += ../src/eap_peer/eap_proxy_$(CONFIG_EAP_PROXY).o
+include eap_proxy_$(CONFIG_EAP_PROXY).mk
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
ifdef CONFIG_EAP_AKA_PRIME
# EAP-AKA'
ifeq ($(CONFIG_EAP_AKA_PRIME), dyn)
@@ -556,7 +574,7 @@
ifdef CONFIG_EAP_PWD
CFLAGS += -DEAP_PWD
OBJS += ../src/eap_peer/eap_pwd.o ../src/eap_common/eap_pwd_common.o
-OBJS_h += ../src/eap_server/eap_pwd.o
+OBJS_h += ../src/eap_server/eap_server_pwd.o
CONFIG_IEEE8021X_EAPOL=y
NEED_SHA256=y
endif
@@ -588,25 +606,10 @@
NEED_AES_CBC=y
NEED_MODEXP=y
-ifdef CONFIG_WPS_UFD
-CFLAGS += -DCONFIG_WPS_UFD
-OBJS += ../src/wps/wps_ufd.o
-NEED_WPS_OOB=y
-endif
-
ifdef CONFIG_WPS_NFC
CFLAGS += -DCONFIG_WPS_NFC
OBJS += ../src/wps/ndef.o
-OBJS += ../src/wps/wps_nfc.o
NEED_WPS_OOB=y
-ifdef CONFIG_WPS_NFC_PN531
-PN531_PATH ?= /usr/local/src/nfc
-CFLAGS += -DCONFIG_WPS_NFC_PN531
-CFLAGS += -I${PN531_PATH}/inc
-OBJS += ../src/wps/wps_nfc_pn531.o
-LIBS += ${PN531_PATH}/lib/wpsnfc.dll
-LIBS += ${PN531_PATH}/lib/libnfc_mapping_pn53x.dll
-endif
endif
ifdef NEED_WPS_OOB
@@ -732,9 +735,13 @@
OBJS += ../src/ap/drv_callbacks.o
OBJS += ../src/ap/ap_drv_ops.o
OBJS += ../src/ap/beacon.o
+OBJS += ../src/ap/eap_user_db.o
ifdef CONFIG_IEEE80211N
OBJS += ../src/ap/ieee802_11_ht.o
endif
+ifdef CONFIG_WNM
+OBJS += ../src/ap/wnm_ap.o
+endif
ifdef CONFIG_CTRL_IFACE
OBJS += ../src/ap/ctrl_iface_ap.o
endif
@@ -748,10 +755,6 @@
CFLAGS += -DCONFIG_IEEE80211N
endif
-ifdef CONFIG_WNM
-CFLAGS += -DCONFIG_WNM
-endif
-
ifdef NEED_AP_MLME
OBJS += ../src/ap/wmm.o
OBJS += ../src/ap/ap_list.o
@@ -870,6 +873,8 @@
OBJS_h += ../src/eap_server/eap_server_tls_common.o
ifndef CONFIG_FIPS
NEED_TLS_PRF=y
+NEED_SHA1=y
+NEED_MD5=y
endif
endif
@@ -1189,6 +1194,10 @@
endif
endif
+ifdef NEED_ECC
+CFLAGS += -DCONFIG_ECC
+endif
+
ifdef CONFIG_NO_RANDOM_POOL
CFLAGS += -DCONFIG_NO_RANDOM_POOL
else
@@ -1416,6 +1425,7 @@
endif
OBJS += ../src/drivers/driver_common.o
+OBJS_priv += ../src/drivers/driver_common.o
OBJS_wpa_rm := ctrl_iface.o ctrl_iface_unix.o
OBJS_wpa := $(filter-out $(OBJS_wpa_rm),$(OBJS)) $(OBJS_h) tests/test_wpa.o
diff --git a/wpa_supplicant/README b/wpa_supplicant/README
index a06e5c1..d84e61e 100644
--- a/wpa_supplicant/README
+++ b/wpa_supplicant/README
@@ -1,7 +1,7 @@
WPA Supplicant
==============
-Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
This program is licensed under the BSD license (the one with
diff --git a/wpa_supplicant/README-HS20 b/wpa_supplicant/README-HS20
index feb9049..5669c55 100644
--- a/wpa_supplicant/README-HS20
+++ b/wpa_supplicant/README-HS20
@@ -190,6 +190,11 @@
# phase2: Pre-configure Phase 2 (inner authentication) parameters
# This optional field is used with like the 'eap' parameter.
#
+# excluded_ssid: Excluded SSID
+# This optional field can be used to excluded specific SSID(s) from
+# matching with the network. Multiple entries can be used to specify more
+# than one SSID.
+#
# for example:
#
#cred={
diff --git a/wpa_supplicant/README-P2P b/wpa_supplicant/README-P2P
index 4abc2f2..8447a90 100644
--- a/wpa_supplicant/README-P2P
+++ b/wpa_supplicant/README-P2P
@@ -191,7 +191,13 @@
p2p_cancel
-Cancel an ongoing P2P group formation related operation.
+Cancel an ongoing P2P group formation and joining-a-group related
+operation. This operations unauthorizes the specific peer device (if any
+had been authorized to start group formation), stops P2P find (if in
+progress), stops pending operations for join-a-group, and removes the
+P2P group interface (if one was used) that is in the WPS provisioning
+step. If the WPS provisioning step has been completed, the group is not
+terminated.
Service Discovery
@@ -219,6 +225,19 @@
will be automatically removed when the specified peer has replied to
it.
+Service Query TLV has following format:
+Length (2 octets, little endian) - length of following data
+Service Protocol Type (1 octet) - see the table below
+Service Transaction ID (1 octet) - nonzero identifier for the TLV
+Query Data (Length - 2 octets of data) - service protocol specific data
+
+Service Protocol Types:
+0 = All service protocols
+1 = Bonjour
+2 = UPnP
+3 = WS-Discovery
+4 = Wi-Fi Display
+
For UPnP, an alternative command format can be used to specify a
single query TLV (i.e., a service discovery for a specific UPnP
service):
@@ -346,7 +365,7 @@
Invitation
p2p_invite [persistent=<network id>|group=<group ifname>] [peer=address]
- [go_dev_addr=address] [freq=<freq in MHz>] [ht40]
+ [go_dev_addr=address] [freq=<freq in MHz>] [ht40] [pref=<MHz>]
Invite a peer to join a group (e.g., group=wlan1) or to reinvoke a
persistent group (e.g., persistent=4). If the peer device is the GO of
@@ -355,7 +374,11 @@
used to override the GO device address for Invitation Request should
it be not known for some reason (this should not be needed in most
cases). When reinvoking a persistent group, the GO device can specify
-the frequency for the group with the freq parameter.
+the frequency for the group with the freq parameter. When reinvoking a
+persistent group, the P2P client device can use freq parameter to force
+a specific operating channel (or invitation failure if GO rejects that)
+or pref parameter to request a specific channel (while allowing GO to
+select to use another channel, if needed).
Group Operations
diff --git a/wpa_supplicant/README-WPS b/wpa_supplicant/README-WPS
index 692d5f5..3d07109 100644
--- a/wpa_supplicant/README-WPS
+++ b/wpa_supplicant/README-WPS
@@ -130,6 +130,12 @@
This starts the WPS negotiation in the same way as above with the
generated PIN.
+When the wps_pin command is issued for an AP (including P2P GO) mode
+interface, an optional timeout parameter can be used to specify
+expiration timeout for the PIN in seconds. For example:
+
+wpa_cli wps_pin any 12345670 300
+
If a random PIN is needed for a user interface, "wpa_cli wps_pin get"
can be used to generate a new PIN without starting WPS negotiation.
@@ -253,16 +259,16 @@
wps_er_stop
- stop WPS ER functionality
-wps_er_learn <UUID> <AP PIN>
+wps_er_learn <UUID|BSSID> <AP PIN>
- learn AP configuration
-wps_er_set_config <UUID> <network id>
+wps_er_set_config <UUID|BSSID> <network id>
- use AP configuration from a locally configured network (e.g., from
wps_reg command); this does not change the AP's configuration, but
only prepares a configuration to be used when enrolling a new device
to the AP
-wps_er_config <UUID> <AP PIN> <new SSID> <auth> <encr> <new key>
+wps_er_config <UUID|BSSID> <AP PIN> <new SSID> <auth> <encr> <new key>
- examples:
wps_er_config 87654321-9abc-def0-1234-56789abc0002 12345670 testing WPA2PSK CCMP 12345678
wpa_er_config 87654321-9abc-def0-1234-56789abc0002 12345670 clear OPEN NONE ""
@@ -271,10 +277,10 @@
<encr> must be one of the following: NONE WEP TKIP CCMP
-wps_er_pbc <Enrollee UUID>
+wps_er_pbc <Enrollee UUID|MAC address>
- accept an Enrollee PBC using External Registrar
-wps_er_pin <Enrollee UUID> <PIN> [Enrollee MAC address]
+wps_er_pin <Enrollee UUID|"any"|MAC address> <PIN> [Enrollee MAC address]
- add an Enrollee PIN to External Registrar
- if Enrollee UUID is not known, "any" can be used to add a wildcard PIN
- if the MAC address of the enrollee is known, it should be configured
@@ -330,6 +336,20 @@
tokens during manufacturing (each station needs to have its own random
keys).
+The "wps_nfc_config_token <WPS/NDEF>" command can be used to build an
+NFC configuration token when wpa_supplicant is controlling an AP
+interface (AP or P2P GO). The output value from this command is a
+hexdump of the current AP configuration (WPS parameter requests this to
+include only the WPS attributes; NDEF parameter requests additional NDEF
+encapsulation to be included). This data needs to be written to an NFC
+tag with an external program. Once written, the NFC configuration token
+can be used to touch an NFC interface on a station to provision the
+credentials needed to access the network.
+
+The "wps_nfc_config_token <WPS/NDEF> <network id>" command can be used
+to build an NFC configuration token based on a locally configured
+network.
+
If the station includes NFC interface and reads an NFC tag with a MIME
media type "application/vnd.wfa.wsc", the NDEF message payload (with or
without NDEF encapsulation) can be delivered to wpa_supplicant using the
@@ -345,3 +365,47 @@
the ER functionality has been started (wps_er_start), the NFC password
token is used to enable enrollment of a new station (that was the source
of the NFC password token).
+
+"nfc_get_handover_req <NDEF> <WPS>" command can be used to build the
+contents of a Handover Request Message for connection handover. The
+first argument selects the format of the output data and the second
+argument selects which type of connection handover is requested (WPS =
+Wi-Fi handover as specified in WSC 2.0).
+
+"nfc_get_handover_sel <NDEF> <WPS> [UUID|BSSID]" command can be used to
+build the contents of a Handover Select Message for connection handover
+when this does not depend on the contents of the Handover Request
+Message. The first argument selects the format of the output data and
+the second argument selects which type of connection handover is
+requested (WPS = Wi-Fi handover as specified in WSC 2.0). If the options
+UUID|BSSID argument is included, this is a request to build the handover
+message for the specified AP when wpa_supplicant is operating as a WPS
+ER.
+
+"nfc_rx_handover_req <hexdump of payload>" is used to indicate receipt
+of NFC connection handover request. The payload may include multiple
+carriers the the applicable ones are matched based on the media
+type. The reply data is contents for the Handover Select Message
+(hexdump).
+
+"nfc_rx_handover_sel <hexdump of payload>" is used to indicate receipt
+of NFC connection handover select. The payload may include multiple
+carriers the the applicable ones are matched based on the media
+type.
+
+"nfc_report_handover <INIT/RESP> WPS <carrier from handover request>
+<carrier from handover select>" can be used as an alternative way for
+reporting completed NFC connection handover. The first parameter
+indicates whether the local device initiated or responded to the
+connection handover and the carrier records are the selected carrier
+from the handover request and select messages as a hexdump.
+
+The "wps_er_nfc_config_token <WPS/NDEF> <UUID|BSSID>" command can be
+used to build an NFC configuration token for the specified AP when
+wpa_supplicant is operating as a WPS ER. The output value from this
+command is a hexdump of the selected AP configuration (WPS parameter
+requests this to include only the WPS attributes; NDEF parameter
+requests additional NDEF encapsulation to be included). This data needs
+to be written to an NFC tag with an external program. Once written, the
+NFC configuration token can be used to touch an NFC interface on a
+station to provision the credentials needed to access the network.
diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config
index 58d0c43..b86c4c7 100644
--- a/wpa_supplicant/android.config
+++ b/wpa_supplicant/android.config
@@ -224,6 +224,9 @@
# Support HT overrides (disable HT/HT40, mask MCS rates, etc.)
#CONFIG_HT_OVERRIDES=y
+# Support VHT overrides (disable VHT, mask MCS rates, etc.)
+#CONFIG_VHT_OVERRIDES=y
+
# Development testing
#CONFIG_EAPOL_TEST=y
@@ -495,6 +498,9 @@
# Disable roaming in wpa_supplicant
CONFIG_NO_ROAMING=y
+# Enable TDLS
+CONFIG_TDLS=y
+
# Enable P2P
CONFIG_P2P=y
CONFIG_AP=y
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 3798f5a..3ba4496 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -46,7 +46,6 @@
struct hostapd_config *conf)
{
struct hostapd_bss_config *bss = &conf->bss[0];
- int pairwise;
conf->driver = wpa_s->driver;
@@ -63,6 +62,10 @@
(ssid->frequency >= 5745 && ssid->frequency <= 5825)) {
conf->hw_mode = HOSTAPD_MODE_IEEE80211A;
conf->channel = (ssid->frequency - 5000) / 5;
+ } else if (ssid->frequency >= 56160 + 2160 * 1 &&
+ ssid->frequency <= 56160 + 2160 * 4) {
+ conf->hw_mode = HOSTAPD_MODE_IEEE80211AD;
+ conf->channel = (ssid->frequency - 56160) / 2160;
} else {
wpa_printf(MSG_ERROR, "Unsupported AP mode frequency: %d MHz",
ssid->frequency);
@@ -174,15 +177,15 @@
bss->wpa = ssid->proto;
bss->wpa_key_mgmt = ssid->key_mgmt;
bss->wpa_pairwise = ssid->pairwise_cipher;
- if (ssid->passphrase) {
- bss->ssid.wpa_passphrase = os_strdup(ssid->passphrase);
- } else if (ssid->psk_set) {
+ if (ssid->psk_set) {
os_free(bss->ssid.wpa_psk);
bss->ssid.wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk));
if (bss->ssid.wpa_psk == NULL)
return -1;
os_memcpy(bss->ssid.wpa_psk->psk, ssid->psk, PMK_LEN);
bss->ssid.wpa_psk->group = 1;
+ } else if (ssid->passphrase) {
+ bss->ssid.wpa_passphrase = os_strdup(ssid->passphrase);
} else if (ssid->wep_key_len[0] || ssid->wep_key_len[1] ||
ssid->wep_key_len[2] || ssid->wep_key_len[3]) {
struct hostapd_wep_keys *wep = &bss->ssid.wep;
@@ -206,23 +209,18 @@
if (ssid->dtim_period)
bss->dtim_period = ssid->dtim_period;
+ else if (wpa_s->conf->dtim_period)
+ bss->dtim_period = wpa_s->conf->dtim_period;
- /* Select group cipher based on the enabled pairwise cipher suites */
- pairwise = 0;
- if (bss->wpa & 1)
- pairwise |= bss->wpa_pairwise;
- if (bss->wpa & 2) {
- if (bss->rsn_pairwise == 0)
- bss->rsn_pairwise = bss->wpa_pairwise;
- pairwise |= bss->rsn_pairwise;
- }
- if (pairwise & WPA_CIPHER_TKIP)
- bss->wpa_group = WPA_CIPHER_TKIP;
- else if ((pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) ==
- WPA_CIPHER_GCMP)
- bss->wpa_group = WPA_CIPHER_GCMP;
- else
- bss->wpa_group = WPA_CIPHER_CCMP;
+ if (ssid->beacon_int)
+ conf->beacon_int = ssid->beacon_int;
+ else if (wpa_s->conf->beacon_int)
+ conf->beacon_int = wpa_s->conf->beacon_int;
+
+ if ((bss->wpa & 2) && bss->rsn_pairwise == 0)
+ bss->rsn_pairwise = bss->wpa_pairwise;
+ bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa, bss->wpa_pairwise,
+ bss->rsn_pairwise);
if (bss->wpa && bss->ieee802_1x)
bss->ssid.security_policy = SECURITY_WPA;
@@ -264,7 +262,7 @@
goto no_wps;
#ifdef CONFIG_WPS2
if (bss->ssid.security_policy == SECURITY_WPA_PSK &&
- (!(pairwise & WPA_CIPHER_CCMP) || !(bss->wpa & 2)))
+ (!(bss->rsn_pairwise & WPA_CIPHER_CCMP) || !(bss->wpa & 2)))
goto no_wps; /* WPS2 does not allow WPA/TKIP-only
* configuration */
#endif /* CONFIG_WPS2 */
@@ -307,6 +305,11 @@
bss->disassoc_low_ack = wpa_s->conf->disassoc_low_ack;
+ if (wpa_s->conf->ap_vendor_elements) {
+ bss->vendor_elements =
+ wpabuf_dup(wpa_s->conf->ap_vendor_elements);
+ }
+
return 0;
}
@@ -462,20 +465,15 @@
wpa_s->key_mgmt = WPA_KEY_MGMT_NONE;
params.key_mgmt_suite = key_mgmt2driver(wpa_s->key_mgmt);
- if (ssid->pairwise_cipher & WPA_CIPHER_CCMP)
- wpa_s->pairwise_cipher = WPA_CIPHER_CCMP;
- else if (ssid->pairwise_cipher & WPA_CIPHER_GCMP)
- wpa_s->pairwise_cipher = WPA_CIPHER_GCMP;
- else if (ssid->pairwise_cipher & WPA_CIPHER_TKIP)
- wpa_s->pairwise_cipher = WPA_CIPHER_TKIP;
- else if (ssid->pairwise_cipher & WPA_CIPHER_NONE)
- wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
- else {
+ wpa_s->pairwise_cipher = wpa_pick_pairwise_cipher(ssid->pairwise_cipher,
+ 1);
+ if (wpa_s->pairwise_cipher < 0) {
wpa_printf(MSG_WARNING, "WPA: Failed to select pairwise "
"cipher.");
return -1;
}
- params.pairwise_suite = cipher_suite2driver(wpa_s->pairwise_cipher);
+ params.pairwise_suite =
+ wpa_cipher_to_suite_driver(wpa_s->pairwise_cipher);
params.group_suite = params.pairwise_suite;
#ifdef CONFIG_P2P
@@ -500,6 +498,9 @@
hapd_iface->owner = wpa_s;
hapd_iface->drv_flags = wpa_s->drv_flags;
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;
+ hapd_iface->extended_capa_len = wpa_s->extended_capa_len;
wpa_s->ap_iface->conf = conf = hostapd_config_defaults();
if (conf == NULL) {
@@ -599,7 +600,6 @@
wpa_s->current_ssid = NULL;
wpa_s->assoc_freq = 0;
- wpa_s->reassociated_connection = 0;
#ifdef CONFIG_P2P
if (wpa_s->ap_iface->bss)
wpa_s->ap_iface->bss[0]->p2p_group = NULL;
@@ -724,7 +724,8 @@
int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
- const char *pin, char *buf, size_t buflen)
+ const char *pin, char *buf, size_t buflen,
+ int timeout)
{
int ret, ret_len = 0;
@@ -739,7 +740,7 @@
ret_len = os_snprintf(buf, buflen, "%s", pin);
ret = hostapd_wps_add_pin(wpa_s->ap_iface->bss[0], bssid, "any", pin,
- 0);
+ timeout);
if (ret)
return -1;
return ret_len;
@@ -862,6 +863,34 @@
hapd->conf->ap_pin = NULL;
}
+
+#ifdef CONFIG_WPS_NFC
+
+struct wpabuf * wpas_ap_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
+ int ndef)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface == NULL)
+ return NULL;
+ hapd = wpa_s->ap_iface->bss[0];
+ return hostapd_wps_nfc_config_token(hapd, ndef);
+}
+
+
+struct wpabuf * wpas_ap_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s,
+ int ndef)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface == NULL)
+ return NULL;
+ hapd = wpa_s->ap_iface->bss[0];
+ return hostapd_wps_nfc_hs_cr(hapd, ndef);
+}
+
+#endif /* CONFIG_WPS_NFC */
+
#endif /* CONFIG_WPS */
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index bc953d9..fd4c25a 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -18,7 +18,8 @@
int wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
const u8 *p2p_dev_addr);
int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
- const char *pin, char *buf, size_t buflen);
+ const char *pin, char *buf, size_t buflen,
+ int timeout);
int wpa_supplicant_ap_wps_cancel(struct wpa_supplicant *wpa_s);
void wpas_wps_ap_pin_disable(struct wpa_supplicant *wpa_s);
const char * wpas_wps_ap_pin_random(struct wpa_supplicant *wpa_s, int timeout);
@@ -51,5 +52,9 @@
void wpa_supplicant_ap_pwd_auth_fail(struct wpa_supplicant *wpa_s);
void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
int offset);
+struct wpabuf * wpas_ap_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
+ int ndef);
+struct wpabuf * wpas_ap_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s,
+ int ndef);
#endif /* AP_H */
diff --git a/wpa_supplicant/autoscan.c b/wpa_supplicant/autoscan.c
index d0c040a..a2cf7a5 100644
--- a/wpa_supplicant/autoscan.c
+++ b/wpa_supplicant/autoscan.c
@@ -36,7 +36,7 @@
static void request_scan(struct wpa_supplicant *wpa_s)
{
- wpa_s->scan_req = 2;
+ wpa_s->scan_req = MANUAL_SCAN_REQ;
if (wpa_supplicant_req_sched_scan(wpa_s))
wpa_supplicant_req_scan(wpa_s, wpa_s->scan_interval, 0);
diff --git a/wpa_supplicant/bgscan_learn.c b/wpa_supplicant/bgscan_learn.c
index adf82d8..07d31e4 100644
--- a/wpa_supplicant/bgscan_learn.c
+++ b/wpa_supplicant/bgscan_learn.c
@@ -242,8 +242,11 @@
idx = data->probe_idx + 1;
while (idx != data->probe_idx) {
- if (data->supp_freqs[idx] == 0)
+ if (data->supp_freqs[idx] == 0) {
+ if (data->probe_idx == 0)
+ break;
idx = 0;
+ }
if (!in_array(freqs, data->supp_freqs[idx])) {
wpa_printf(MSG_DEBUG, "bgscan learn: Probe new freq "
"%u", data->supp_freqs[idx]);
diff --git a/wpa_supplicant/blacklist.c b/wpa_supplicant/blacklist.c
index 2e01e7f..e53dc38 100644
--- a/wpa_supplicant/blacklist.c
+++ b/wpa_supplicant/blacklist.c
@@ -123,14 +123,19 @@
void wpa_blacklist_clear(struct wpa_supplicant *wpa_s)
{
struct wpa_blacklist *e, *prev;
+ int max_count = 0;
e = wpa_s->blacklist;
wpa_s->blacklist = NULL;
while (e) {
+ if (e->count > max_count)
+ max_count = e->count;
prev = e;
e = e->next;
wpa_printf(MSG_DEBUG, "Removed BSSID " MACSTR " from "
"blacklist (clear)", MAC2STR(prev->bssid));
os_free(prev);
}
+
+ wpa_s->extra_blacklist_count += max_count;
}
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 6223beb..0e1576b 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -1,6 +1,6 @@
/*
* BSS table
- * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -51,6 +51,14 @@
}
+/**
+ * wpa_bss_anqp_alloc - Allocate ANQP data structure for a BSS entry
+ * Returns: Allocated ANQP data structure or %NULL on failure
+ *
+ * The allocated ANQP data structure has its users count set to 1. It may be
+ * shared by multiple BSS entries and each shared entry is freed with
+ * wpa_bss_anqp_free().
+ */
struct wpa_bss_anqp * wpa_bss_anqp_alloc(void)
{
struct wpa_bss_anqp *anqp;
@@ -62,6 +70,77 @@
}
+/**
+ * wpa_bss_anqp_clone - Clone an ANQP data structure
+ * @anqp: ANQP data structure from wpa_bss_anqp_alloc()
+ * Returns: Cloned ANQP data structure or %NULL on failure
+ */
+static struct wpa_bss_anqp * wpa_bss_anqp_clone(struct wpa_bss_anqp *anqp)
+{
+ struct wpa_bss_anqp *n;
+
+ n = os_zalloc(sizeof(*n));
+ if (n == NULL)
+ return NULL;
+
+#define ANQP_DUP(f) if (anqp->f) n->f = wpabuf_dup(anqp->f)
+#ifdef CONFIG_INTERWORKING
+ ANQP_DUP(venue_name);
+ ANQP_DUP(network_auth_type);
+ ANQP_DUP(roaming_consortium);
+ ANQP_DUP(ip_addr_type_availability);
+ ANQP_DUP(nai_realm);
+ ANQP_DUP(anqp_3gpp);
+ ANQP_DUP(domain_name);
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+ ANQP_DUP(hs20_operator_friendly_name);
+ ANQP_DUP(hs20_wan_metrics);
+ ANQP_DUP(hs20_connection_capability);
+ ANQP_DUP(hs20_operating_class);
+#endif /* CONFIG_HS20 */
+#undef ANQP_DUP
+
+ return n;
+}
+
+
+/**
+ * wpa_bss_anqp_unshare_alloc - Unshare ANQP data (if shared) in a BSS entry
+ * @bss: BSS entry
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function ensures the specific BSS entry has an ANQP data structure that
+ * is not shared with any other BSS entry.
+ */
+int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss)
+{
+ struct wpa_bss_anqp *anqp;
+
+ if (bss->anqp && bss->anqp->users > 1) {
+ /* allocated, but shared - clone an unshared copy */
+ anqp = wpa_bss_anqp_clone(bss->anqp);
+ if (anqp == NULL)
+ return -1;
+ anqp->users = 1;
+ bss->anqp->users--;
+ bss->anqp = anqp;
+ return 0;
+ }
+
+ if (bss->anqp)
+ return 0; /* already allocated and not shared */
+
+ /* not allocated - allocate a new storage area */
+ bss->anqp = wpa_bss_anqp_alloc();
+ return bss->anqp ? 0 : -1;
+}
+
+
+/**
+ * wpa_bss_anqp_free - Free an ANQP data structure
+ * @anqp: ANQP data structure from wpa_bss_anqp_alloc() or wpa_bss_anqp_clone()
+ */
static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
{
if (anqp == NULL)
@@ -121,6 +200,14 @@
}
+/**
+ * wpa_bss_get - Fetch a BSS table entry based on BSSID and SSID
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID
+ * @ssid: SSID
+ * @ssid_len: Length of @ssid
+ * Returns: Pointer to the BSS entry or %NULL if not found
+ */
struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
const u8 *ssid, size_t ssid_len)
{
@@ -137,10 +224,27 @@
}
-static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src)
+static void calculate_update_time(const struct os_time *fetch_time,
+ unsigned int age_ms,
+ struct os_time *update_time)
{
os_time_t usec;
+ update_time->sec = fetch_time->sec;
+ update_time->usec = fetch_time->usec;
+ update_time->sec -= age_ms / 1000;
+ usec = (age_ms % 1000) * 1000;
+ if (update_time->usec < usec) {
+ update_time->sec--;
+ update_time->usec += 1000000;
+ }
+ update_time->usec -= usec;
+}
+
+
+static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src,
+ struct os_time *fetch_time)
+{
dst->flags = src->flags;
os_memcpy(dst->bssid, src->bssid, ETH_ALEN);
dst->freq = src->freq;
@@ -151,14 +255,7 @@
dst->level = src->level;
dst->tsf = src->tsf;
- os_get_time(&dst->last_update);
- dst->last_update.sec -= src->age / 1000;
- usec = (src->age % 1000) * 1000;
- if (dst->last_update.usec < usec) {
- dst->last_update.sec--;
- dst->last_update.usec += 1000000;
- }
- dst->last_update.usec -= usec;
+ calculate_update_time(fetch_time, src->age, &dst->last_update);
}
@@ -228,7 +325,8 @@
static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s,
const u8 *ssid, size_t ssid_len,
- struct wpa_scan_res *res)
+ struct wpa_scan_res *res,
+ struct os_time *fetch_time)
{
struct wpa_bss *bss;
@@ -237,7 +335,7 @@
return NULL;
bss->id = wpa_s->bss_next_id++;
bss->last_update_idx = wpa_s->bss_update_idx;
- wpa_bss_copy_res(bss, res);
+ wpa_bss_copy_res(bss, res, fetch_time);
os_memcpy(bss->ssid, ssid, ssid_len);
bss->ssid_len = ssid_len;
bss->ie_len = res->ie_len;
@@ -393,14 +491,14 @@
static struct wpa_bss *
wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
- struct wpa_scan_res *res)
+ struct wpa_scan_res *res, struct os_time *fetch_time)
{
u32 changes;
changes = wpa_bss_compare_res(bss, res);
bss->scan_miss_count = 0;
bss->last_update_idx = wpa_s->bss_update_idx;
- wpa_bss_copy_res(bss, res);
+ wpa_bss_copy_res(bss, res, fetch_time);
/* Move the entry to the end of the list */
dl_list_del(&bss->list);
if (bss->ie_len + bss->beacon_ie_len >=
@@ -442,6 +540,15 @@
}
+/**
+ * wpa_bss_update_start - Start a BSS table update from scan results
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function is called at the start of each BSS table update round for new
+ * scan results. The actual scan result entries are indicated with calls to
+ * wpa_bss_update_scan_res() and the update round is finished with a call to
+ * wpa_bss_update_end().
+ */
void wpa_bss_update_start(struct wpa_supplicant *wpa_s)
{
wpa_s->bss_update_idx++;
@@ -451,12 +558,38 @@
}
+/**
+ * wpa_bss_update_scan_res - Update a BSS table entry based on a scan result
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @res: Scan result
+ * @fetch_time: Time when the result was fetched from the driver
+ *
+ * This function updates a BSS table entry (or adds one) based on a scan result.
+ * This is called separately for each scan result between the calls to
+ * wpa_bss_update_start() and wpa_bss_update_end().
+ */
void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
- struct wpa_scan_res *res)
+ struct wpa_scan_res *res,
+ struct os_time *fetch_time)
{
const u8 *ssid, *p2p;
struct wpa_bss *bss;
+ if (wpa_s->conf->ignore_old_scan_res) {
+ struct os_time update;
+ calculate_update_time(fetch_time, res->age, &update);
+ if (os_time_before(&update, &wpa_s->scan_trigger_time)) {
+ struct os_time age;
+ os_time_sub(&wpa_s->scan_trigger_time, &update, &age);
+ wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Ignore driver BSS "
+ "table entry that is %u.%06u seconds older "
+ "than our scan trigger",
+ (unsigned int) age.sec,
+ (unsigned int) age.usec);
+ return;
+ }
+ }
+
ssid = wpa_scan_get_ie(res, WLAN_EID_SSID);
if (ssid == NULL) {
wpa_dbg(wpa_s, MSG_DEBUG, "BSS: No SSID IE included for "
@@ -490,9 +623,9 @@
* (to save memory) */
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);
+ bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res, fetch_time);
else
- bss = wpa_bss_update(wpa_s, bss, res);
+ bss = wpa_bss_update(wpa_s, bss, res, fetch_time);
if (bss == NULL)
return;
@@ -556,6 +689,16 @@
}
+/**
+ * wpa_bss_update_end - End a BSS table update from scan results
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @info: Information about scan parameters
+ * @new_scan: Whether this update round was based on a new scan
+ *
+ * This function is called at the end of each BSS table update round for new
+ * scan results. The start of the update was indicated with a call to
+ * wpa_bss_update_start().
+ */
void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
int new_scan)
{
@@ -601,6 +744,13 @@
}
+/**
+ * wpa_bss_flush_by_age - Flush old BSS entries
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @age: Maximum entry age in seconds
+ *
+ * Remove BSS entries that have not been updated during the last @age seconds.
+ */
void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age)
{
struct wpa_bss *bss, *n;
@@ -634,6 +784,14 @@
}
+/**
+ * wpa_bss_init - Initialize BSS table
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: 0 on success, -1 on failure
+ *
+ * This prepares BSS table lists and timer for periodic updates. The BSS table
+ * is deinitialized with wpa_bss_deinit() once not needed anymore.
+ */
int wpa_bss_init(struct wpa_supplicant *wpa_s)
{
dl_list_init(&wpa_s->bss);
@@ -644,6 +802,10 @@
}
+/**
+ * wpa_bss_flush - Flush all unused BSS entries
+ * @wpa_s: Pointer to wpa_supplicant data
+ */
void wpa_bss_flush(struct wpa_supplicant *wpa_s)
{
struct wpa_bss *bss, *n;
@@ -659,6 +821,10 @@
}
+/**
+ * wpa_bss_deinit - Deinitialize BSS table
+ * @wpa_s: Pointer to wpa_supplicant data
+ */
void wpa_bss_deinit(struct wpa_supplicant *wpa_s)
{
eloop_cancel_timeout(wpa_bss_timeout, wpa_s, NULL);
@@ -666,6 +832,12 @@
}
+/**
+ * wpa_bss_get_bssid - Fetch a BSS table entry based on BSSID
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID
+ * Returns: Pointer to the BSS entry or %NULL if not found
+ */
struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
const u8 *bssid)
{
@@ -680,7 +852,41 @@
}
+/**
+ * wpa_bss_get_bssid_latest - Fetch the latest BSS table entry based on BSSID
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID
+ * Returns: Pointer to the BSS entry or %NULL if not found
+ *
+ * This function is like wpa_bss_get_bssid(), but full BSS table is iterated to
+ * find the entry that has the most recent update. This can help in finding the
+ * correct entry in cases where the SSID of the AP may have changed recently
+ * (e.g., in WPS reconfiguration cases).
+ */
+struct wpa_bss * wpa_bss_get_bssid_latest(struct wpa_supplicant *wpa_s,
+ const u8 *bssid)
+{
+ struct wpa_bss *bss, *found = NULL;
+ if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
+ return NULL;
+ dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
+ if (os_memcmp(bss->bssid, bssid, ETH_ALEN) != 0)
+ continue;
+ if (found == NULL ||
+ os_time_before(&found->last_update, &bss->last_update))
+ found = bss;
+ }
+ return found;
+}
+
+
#ifdef CONFIG_P2P
+/**
+ * wpa_bss_get_p2p_dev_addr - Fetch a BSS table entry based on P2P Device Addr
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @dev_addr: P2P Device Address of the GO
+ * Returns: Pointer to the BSS entry or %NULL if not found
+ */
struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s,
const u8 *dev_addr)
{
@@ -697,6 +903,12 @@
#endif /* CONFIG_P2P */
+/**
+ * wpa_bss_get_id - Fetch a BSS table entry based on identifier
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @id: Unique identifier (struct wpa_bss::id) assigned for the entry
+ * Returns: Pointer to the BSS entry or %NULL if not found
+ */
struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id)
{
struct wpa_bss *bss;
@@ -708,6 +920,38 @@
}
+/**
+ * wpa_bss_get_id_range - Fetch a BSS table entry based on identifier range
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @idf: Smallest allowed identifier assigned for the entry
+ * @idf: Largest allowed identifier assigned for the entry
+ * Returns: Pointer to the BSS entry or %NULL if not found
+ *
+ * This function is similar to wpa_bss_get_id() but allows a BSS entry with the
+ * smallest id value to be fetched within the specified range without the
+ * caller having to know the exact id.
+ */
+struct wpa_bss * wpa_bss_get_id_range(struct wpa_supplicant *wpa_s,
+ unsigned int idf, unsigned int idl)
+{
+ struct wpa_bss *bss;
+ dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
+ if (bss->id >= idf && bss->id <= idl)
+ return bss;
+ }
+ return NULL;
+}
+
+
+/**
+ * wpa_bss_get_ie - Fetch a specified information element from a BSS entry
+ * @bss: BSS table entry
+ * @ie: Information element identitifier (WLAN_EID_*)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the first matching information element in the BSS
+ * entry.
+ */
const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie)
{
const u8 *end, *pos;
@@ -727,6 +971,15 @@
}
+/**
+ * wpa_bss_get_vendor_ie - Fetch a vendor information element from a BSS entry
+ * @bss: BSS table entry
+ * @vendor_type: Vendor type (four octets starting the IE payload)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the first matching information element in the BSS
+ * entry.
+ */
const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type)
{
const u8 *end, *pos;
@@ -747,6 +1000,16 @@
}
+/**
+ * wpa_bss_get_vendor_ie_multi - Fetch vendor IE data from a BSS entry
+ * @bss: BSS table entry
+ * @vendor_type: Vendor type (four octets starting the IE payload)
+ * Returns: Pointer to the information element payload or %NULL if not found
+ *
+ * This function returns concatenated payload of possibly fragmented vendor
+ * specific information elements in the BSS entry. The caller is responsible for
+ * freeing the returned buffer.
+ */
struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
u32 vendor_type)
{
@@ -778,6 +1041,19 @@
}
+/**
+ * wpa_bss_get_vendor_ie_multi_beacon - Fetch vendor IE data from a BSS entry
+ * @bss: BSS table entry
+ * @vendor_type: Vendor type (four octets starting the IE payload)
+ * Returns: Pointer to the information element payload or %NULL if not found
+ *
+ * This function returns concatenated payload of possibly fragmented vendor
+ * specific information elements in the BSS entry. The caller is responsible for
+ * freeing the returned buffer.
+ *
+ * This function is like wpa_bss_get_vendor_ie_multi(), but uses IE buffer only
+ * from Beacon frames instead of either Beacon or Probe Response frames.
+ */
struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss,
u32 vendor_type)
{
@@ -810,6 +1086,11 @@
}
+/**
+ * wpa_bss_get_max_rate - Get maximum legacy TX rate supported in a BSS
+ * @bss: BSS table entry
+ * Returns: Maximum legacy rate in units of 500 kbps
+ */
int wpa_bss_get_max_rate(const struct wpa_bss *bss)
{
int rate = 0;
@@ -832,6 +1113,15 @@
}
+/**
+ * wpa_bss_get_bit_rates - Get legacy TX rates supported in a BSS
+ * @bss: BSS table entry
+ * @rates: Buffer for returning a pointer to the rates list (units of 500 kbps)
+ * Returns: number of legacy TX rates or -1 on failure
+ *
+ * The caller is responsible for freeing the returned buffer with os_free() in
+ * case of success.
+ */
int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates)
{
const u8 *ie, *ie2;
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index 4a386b6..2b41948 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -19,7 +19,11 @@
#define WPA_BSS_ASSOCIATED BIT(5)
#define WPA_BSS_ANQP_FETCH_TRIED BIT(6)
+/**
+ * struct wpa_bss_anqp - ANQP data for a BSS entry (struct wpa_bss)
+ */
struct wpa_bss_anqp {
+ /** Number of BSS entries referring to this ANQP data instance */
unsigned int users;
#ifdef CONFIG_INTERWORKING
struct wpabuf *venue_name;
@@ -40,49 +44,52 @@
/**
* struct wpa_bss - BSS table
- * @list: List entry for struct wpa_supplicant::bss
- * @list_id: List entry for struct wpa_supplicant::bss_id
- * @id: Unique identifier for this BSS entry
- * @scan_miss_count: Number of counts without seeing this BSS
- * @flags: information flags about the BSS/IBSS (WPA_BSS_*)
- * @last_update_idx: Index of the last scan update
- * @bssid: BSSID
- * @hessid: HESSID
- * @freq: frequency of the channel in MHz (e.g., 2412 = channel 1)
- * @beacon_int: beacon interval in TUs (host byte order)
- * @caps: capability information field in host byte order
- * @qual: signal quality
- * @noise: noise level
- * @level: signal level
- * @tsf: Timestamp of last Beacon/Probe Response frame
- * @last_update: Time of the last update (i.e., Beacon or Probe Response RX)
- * @ie_len: length of the following IE field in octets (from Probe Response)
- * @beacon_ie_len: length of the following Beacon IE field in octets
*
* This structure is used to store information about neighboring BSSes in
* generic format. It is mainly updated based on scan results from the driver.
*/
struct wpa_bss {
+ /** List entry for struct wpa_supplicant::bss */
struct dl_list list;
+ /** List entry for struct wpa_supplicant::bss_id */
struct dl_list list_id;
+ /** Unique identifier for this BSS entry */
unsigned int id;
+ /** Number of counts without seeing this BSS */
unsigned int scan_miss_count;
+ /** Index of the last scan update */
unsigned int last_update_idx;
+ /** Information flags about the BSS/IBSS (WPA_BSS_*) */
unsigned int flags;
+ /** BSSID */
u8 bssid[ETH_ALEN];
+ /** HESSID */
u8 hessid[ETH_ALEN];
+ /** SSID */
u8 ssid[32];
+ /** Length of SSID */
size_t ssid_len;
+ /** Frequency of the channel in MHz (e.g., 2412 = channel 1) */
int freq;
+ /** Beacon interval in TUs (host byte order) */
u16 beacon_int;
+ /** Capability information field in host byte order */
u16 caps;
+ /** Signal quality */
int qual;
+ /** Noise level */
int noise;
+ /** Signal level */
int level;
+ /** Timestamp of last Beacon/Probe Response frame */
u64 tsf;
+ /** Time of the last update (i.e., Beacon or Probe Response RX) */
struct os_time last_update;
+ /** ANQP data */
struct wpa_bss_anqp *anqp;
+ /** Length of the following IE field in octets (from Probe Response) */
size_t ie_len;
+ /** Length of the following Beacon IE field in octets */
size_t beacon_ie_len;
/* followed by ie_len octets of IEs */
/* followed by beacon_ie_len octets of IEs */
@@ -90,7 +97,8 @@
void wpa_bss_update_start(struct wpa_supplicant *wpa_s);
void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
- struct wpa_scan_res *res);
+ struct wpa_scan_res *res,
+ struct os_time *fetch_time);
void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
int new_scan);
int wpa_bss_init(struct wpa_supplicant *wpa_s);
@@ -101,9 +109,13 @@
const u8 *ssid, size_t ssid_len);
struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
const u8 *bssid);
+struct wpa_bss * wpa_bss_get_bssid_latest(struct wpa_supplicant *wpa_s,
+ const u8 *bssid);
struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s,
const u8 *dev_addr);
struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id);
+struct wpa_bss * wpa_bss_get_id_range(struct wpa_supplicant *wpa_s,
+ unsigned int idf, unsigned int idl);
const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie);
const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type);
struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
@@ -113,5 +125,6 @@
int wpa_bss_get_max_rate(const struct wpa_bss *bss);
int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates);
struct wpa_bss_anqp * wpa_bss_anqp_alloc(void);
+int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss);
#endif /* BSS_H */
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index be21029..0d98884 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -178,10 +178,17 @@
struct wpa_ssid *ssid,
int line, const char *value)
{
- int *dst;
+ int val, *dst;
+ char *end;
dst = (int *) (((u8 *) ssid) + (long) data->param1);
- *dst = atoi(value);
+ val = strtol(value, &end, 0);
+ if (*end) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid number \"%s\"",
+ line, value);
+ return -1;
+ }
+ *dst = val;
wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst);
if (data->param3 && *dst < (long) data->param3) {
@@ -504,6 +511,12 @@
else if (os_strcmp(start, "WPS") == 0)
val |= WPA_KEY_MGMT_WPS;
#endif /* CONFIG_WPS */
+#ifdef CONFIG_SAE
+ else if (os_strcmp(start, "SAE") == 0)
+ val |= WPA_KEY_MGMT_SAE;
+ else if (os_strcmp(start, "FT-SAE") == 0)
+ val |= WPA_KEY_MGMT_FT_SAE;
+#endif /* CONFIG_SAE */
else {
wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
line, start);
@@ -623,49 +636,12 @@
static int wpa_config_parse_cipher(int line, const char *value)
{
- int val = 0, last;
- char *start, *end, *buf;
-
- buf = os_strdup(value);
- if (buf == NULL)
+ int val = wpa_parse_cipher(value);
+ if (val < 0) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
+ line, value);
return -1;
- start = buf;
-
- while (*start != '\0') {
- while (*start == ' ' || *start == '\t')
- start++;
- if (*start == '\0')
- break;
- end = start;
- while (*end != ' ' && *end != '\t' && *end != '\0')
- end++;
- last = *end == '\0';
- *end = '\0';
- if (os_strcmp(start, "CCMP") == 0)
- val |= WPA_CIPHER_CCMP;
- else if (os_strcmp(start, "GCMP") == 0)
- val |= WPA_CIPHER_GCMP;
- else if (os_strcmp(start, "TKIP") == 0)
- val |= WPA_CIPHER_TKIP;
- else if (os_strcmp(start, "WEP104") == 0)
- val |= WPA_CIPHER_WEP104;
- else if (os_strcmp(start, "WEP40") == 0)
- val |= WPA_CIPHER_WEP40;
- else if (os_strcmp(start, "NONE") == 0)
- val |= WPA_CIPHER_NONE;
- else {
- wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
- line, start);
- os_free(buf);
- return -1;
- }
-
- if (last)
- break;
- start = end + 1;
}
- os_free(buf);
-
if (val == 0) {
wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.",
line);
@@ -678,72 +654,13 @@
#ifndef NO_CONFIG_WRITE
static char * wpa_config_write_cipher(int cipher)
{
- char *buf, *pos, *end;
- int ret;
-
- pos = buf = os_zalloc(50);
+ char *buf = os_zalloc(50);
if (buf == NULL)
return NULL;
- end = buf + 50;
- if (cipher & WPA_CIPHER_CCMP) {
- ret = os_snprintf(pos, end - pos, "%sCCMP",
- pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos) {
- end[-1] = '\0';
- return buf;
- }
- pos += ret;
- }
-
- if (cipher & WPA_CIPHER_GCMP) {
- ret = os_snprintf(pos, end - pos, "%sGCMP",
- pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos) {
- end[-1] = '\0';
- return buf;
- }
- pos += ret;
- }
-
- if (cipher & WPA_CIPHER_TKIP) {
- ret = os_snprintf(pos, end - pos, "%sTKIP",
- pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos) {
- end[-1] = '\0';
- return buf;
- }
- pos += ret;
- }
-
- if (cipher & WPA_CIPHER_WEP104) {
- ret = os_snprintf(pos, end - pos, "%sWEP104",
- pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos) {
- end[-1] = '\0';
- return buf;
- }
- pos += ret;
- }
-
- if (cipher & WPA_CIPHER_WEP40) {
- ret = os_snprintf(pos, end - pos, "%sWEP40",
- pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos) {
- end[-1] = '\0';
- return buf;
- }
- pos += ret;
- }
-
- if (cipher & WPA_CIPHER_NONE) {
- ret = os_snprintf(pos, end - pos, "%sNONE",
- pos == buf ? "" : " ");
- if (ret < 0 || ret >= end - pos) {
- end[-1] = '\0';
- return buf;
- }
- pos += ret;
+ if (wpa_write_ciphers(buf, buf + 50, cipher, " ") < 0) {
+ os_free(buf);
+ return NULL;
}
return buf;
@@ -759,8 +676,7 @@
val = wpa_config_parse_cipher(line, value);
if (val == -1)
return -1;
- if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP |
- WPA_CIPHER_NONE)) {
+ if (val & ~WPA_ALLOWED_PAIRWISE_CIPHERS) {
wpa_printf(MSG_ERROR, "Line %d: not allowed pairwise cipher "
"(0x%x).", line, val);
return -1;
@@ -789,8 +705,7 @@
val = wpa_config_parse_cipher(line, value);
if (val == -1)
return -1;
- if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP |
- WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)) {
+ if (val & ~WPA_ALLOWED_GROUP_CIPHERS) {
wpa_printf(MSG_ERROR, "Line %d: not allowed group cipher "
"(0x%x).", line, val);
return -1;
@@ -910,9 +825,7 @@
#endif /* NO_CONFIG_WRITE */
-static int * wpa_config_parse_freqs(const struct parse_data *data,
- struct wpa_ssid *ssid, int line,
- const char *value)
+static int * wpa_config_parse_int_array(const char *value)
{
int *freqs;
size_t used, len;
@@ -959,7 +872,7 @@
{
int *freqs;
- freqs = wpa_config_parse_freqs(data, ssid, line, value);
+ freqs = wpa_config_parse_int_array(value);
if (freqs == NULL)
return -1;
os_free(ssid->scan_freq);
@@ -975,7 +888,7 @@
{
int *freqs;
- freqs = wpa_config_parse_freqs(data, ssid, line, value);
+ freqs = wpa_config_parse_int_array(value);
if (freqs == NULL)
return -1;
os_free(ssid->freq_list);
@@ -1621,7 +1534,7 @@
#endif /* CONFIG_IEEE80211W */
{ INT_RANGE(peerkey, 0, 1) },
{ INT_RANGE(mixed_cell, 0, 1) },
- { INT_RANGE(frequency, 0, 10000) },
+ { INT_RANGE(frequency, 0, 65000) },
{ INT(wpa_ptk_rekey) },
{ STR(bgscan) },
{ INT_RANGE(ignore_broadcast_ssid, 0, 2) },
@@ -1631,13 +1544,36 @@
#ifdef CONFIG_HT_OVERRIDES
{ INT_RANGE(disable_ht, 0, 1) },
{ INT_RANGE(disable_ht40, -1, 1) },
+ { INT_RANGE(disable_sgi, 0, 1) },
{ INT_RANGE(disable_max_amsdu, -1, 1) },
{ INT_RANGE(ampdu_factor, -1, 3) },
{ INT_RANGE(ampdu_density, -1, 7) },
{ STR(ht_mcs) },
#endif /* CONFIG_HT_OVERRIDES */
+#ifdef CONFIG_VHT_OVERRIDES
+ { INT_RANGE(disable_vht, 0, 1) },
+ { INT(vht_capa) },
+ { INT(vht_capa_mask) },
+ { INT_RANGE(vht_rx_mcs_nss_1, -1, 3) },
+ { INT_RANGE(vht_rx_mcs_nss_2, -1, 3) },
+ { INT_RANGE(vht_rx_mcs_nss_3, -1, 3) },
+ { INT_RANGE(vht_rx_mcs_nss_4, -1, 3) },
+ { INT_RANGE(vht_rx_mcs_nss_5, -1, 3) },
+ { INT_RANGE(vht_rx_mcs_nss_6, -1, 3) },
+ { INT_RANGE(vht_rx_mcs_nss_7, -1, 3) },
+ { INT_RANGE(vht_rx_mcs_nss_8, -1, 3) },
+ { INT_RANGE(vht_tx_mcs_nss_1, -1, 3) },
+ { INT_RANGE(vht_tx_mcs_nss_2, -1, 3) },
+ { INT_RANGE(vht_tx_mcs_nss_3, -1, 3) },
+ { INT_RANGE(vht_tx_mcs_nss_4, -1, 3) },
+ { INT_RANGE(vht_tx_mcs_nss_5, -1, 3) },
+ { INT_RANGE(vht_tx_mcs_nss_6, -1, 3) },
+ { INT_RANGE(vht_tx_mcs_nss_7, -1, 3) },
+ { INT_RANGE(vht_tx_mcs_nss_8, -1, 3) },
+#endif /* CONFIG_VHT_OVERRIDES */
{ INT(ap_max_inactivity) },
{ INT(dtim_period) },
+ { INT(beacon_int) },
};
#undef OFFSET
@@ -1829,6 +1765,7 @@
os_free(cred->eap_method);
os_free(cred->phase1);
os_free(cred->phase2);
+ os_free(cred->excluded_ssid);
os_free(cred);
}
@@ -1895,6 +1832,8 @@
wpabuf_free(config->wps_nfc_dh_privkey);
wpabuf_free(config->wps_nfc_dev_pw);
os_free(config->ext_password_backend);
+ os_free(config->sae_groups);
+ wpabuf_free(config->ap_vendor_elements);
os_free(config);
}
@@ -2031,10 +1970,33 @@
#ifdef CONFIG_HT_OVERRIDES
ssid->disable_ht = DEFAULT_DISABLE_HT;
ssid->disable_ht40 = DEFAULT_DISABLE_HT40;
+ ssid->disable_sgi = DEFAULT_DISABLE_SGI;
ssid->disable_max_amsdu = DEFAULT_DISABLE_MAX_AMSDU;
ssid->ampdu_factor = DEFAULT_AMPDU_FACTOR;
ssid->ampdu_density = DEFAULT_AMPDU_DENSITY;
#endif /* CONFIG_HT_OVERRIDES */
+#ifdef CONFIG_VHT_OVERRIDES
+ ssid->vht_rx_mcs_nss_1 = -1;
+ ssid->vht_rx_mcs_nss_2 = -1;
+ ssid->vht_rx_mcs_nss_3 = -1;
+ ssid->vht_rx_mcs_nss_4 = -1;
+ ssid->vht_rx_mcs_nss_5 = -1;
+ ssid->vht_rx_mcs_nss_6 = -1;
+ ssid->vht_rx_mcs_nss_7 = -1;
+ ssid->vht_rx_mcs_nss_8 = -1;
+ ssid->vht_tx_mcs_nss_1 = -1;
+ ssid->vht_tx_mcs_nss_2 = -1;
+ ssid->vht_tx_mcs_nss_3 = -1;
+ ssid->vht_tx_mcs_nss_4 = -1;
+ ssid->vht_tx_mcs_nss_5 = -1;
+ ssid->vht_tx_mcs_nss_6 = -1;
+ ssid->vht_tx_mcs_nss_7 = -1;
+ ssid->vht_tx_mcs_nss_8 = -1;
+#endif /* CONFIG_VHT_OVERRIDES */
+ ssid->proactive_key_caching = -1;
+#ifdef CONFIG_IEEE80211W
+ ssid->ieee80211w = MGMT_FRAME_PROTECTION_DEFAULT;
+#endif /* CONFIG_IEEE80211W */
}
@@ -2401,6 +2363,34 @@
return 0;
}
+ if (os_strcmp(var, "excluded_ssid") == 0) {
+ struct excluded_ssid *e;
+
+ if (len > MAX_SSID_LEN) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "excluded_ssid length %d", line, (int) len);
+ os_free(val);
+ return -1;
+ }
+
+ e = os_realloc_array(cred->excluded_ssid,
+ cred->num_excluded_ssid + 1,
+ sizeof(struct excluded_ssid));
+ if (e == NULL) {
+ os_free(val);
+ return -1;
+ }
+ cred->excluded_ssid = e;
+
+ e = &cred->excluded_ssid[cred->num_excluded_ssid++];
+ os_memcpy(e->ssid, val, len);
+ e->ssid_len = len;
+
+ os_free(val);
+
+ return 0;
+ }
+
if (line) {
wpa_printf(MSG_ERROR, "Line %d: unknown cred field '%s'.",
line, var);
@@ -2647,9 +2637,18 @@
struct wpa_config *config, int line,
const char *pos)
{
- int *dst;
+ int val, *dst;
+ char *end;
+
dst = (int *) (((u8 *) config) + (long) data->param1);
- *dst = atoi(pos);
+ val = strtol(pos, &end, 0);
+ if (*end) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid number \"%s\"",
+ line, pos);
+ return -1;
+ }
+ *dst = val;
+
wpa_printf(MSG_DEBUG, "%s=%d", data->name, *dst);
if (data->param2 && *dst < (long) data->param2) {
@@ -2937,6 +2936,61 @@
}
+static int wpa_config_process_sae_groups(
+ const struct global_parse_data *data,
+ struct wpa_config *config, int line, const char *pos)
+{
+ int *groups = wpa_config_parse_int_array(pos);
+ if (groups == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid sae_groups '%s'",
+ line, pos);
+ return -1;
+ }
+
+ os_free(config->sae_groups);
+ config->sae_groups = groups;
+
+ return 0;
+}
+
+
+static int wpa_config_process_ap_vendor_elements(
+ const struct global_parse_data *data,
+ struct wpa_config *config, int line, const char *pos)
+{
+ struct wpabuf *tmp;
+ int len = os_strlen(pos) / 2;
+ u8 *p;
+
+ if (!len) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid ap_vendor_elements",
+ line);
+ return -1;
+ }
+
+ tmp = wpabuf_alloc(len);
+ if (tmp) {
+ p = wpabuf_put(tmp, len);
+
+ if (hexstr2bin(pos, p, len)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "ap_vendor_elements", line);
+ wpabuf_free(tmp);
+ return -1;
+ }
+
+ wpabuf_free(config->ap_vendor_elements);
+ config->ap_vendor_elements = tmp;
+ } else {
+ wpa_printf(MSG_ERROR, "Cannot allocate memory for "
+ "ap_vendor_elements");
+ return -1;
+ }
+
+ return 0;
+}
+
+
#ifdef OFFSET
#undef OFFSET
#endif /* OFFSET */
@@ -3000,6 +3054,10 @@
{ INT_RANGE(p2p_intra_bss, 0, 1), CFG_CHANGED_P2P_INTRA_BSS },
{ INT(p2p_group_idle), 0 },
{ FUNC(p2p_pref_chan), CFG_CHANGED_P2P_PREF_CHAN },
+ { INT(p2p_go_ht40), 0 },
+ { INT(p2p_disabled), 0 },
+ { INT(p2p_no_group_iface), 0 },
+ { INT_RANGE(p2p_ignore_shared_freq, 0, 1), 0 },
#endif /* CONFIG_P2P */
{ FUNC(country), CFG_CHANGED_COUNTRY },
{ INT(bss_max_count), 0 },
@@ -3017,13 +3075,21 @@
{ INT_RANGE(access_network_type, 0, 15), 0 },
{ INT_RANGE(pbc_in_m1, 0, 1), 0 },
{ STR(autoscan), 0 },
- { INT_RANGE(wps_nfc_dev_pw_id, 0x10, 0xffff), 0 },
- { BIN(wps_nfc_dh_pubkey), 0 },
- { BIN(wps_nfc_dh_privkey), 0 },
- { BIN(wps_nfc_dev_pw), 0 },
+ { INT_RANGE(wps_nfc_dev_pw_id, 0x10, 0xffff),
+ CFG_CHANGED_NFC_PASSWORD_TOKEN },
+ { BIN(wps_nfc_dh_pubkey), CFG_CHANGED_NFC_PASSWORD_TOKEN },
+ { BIN(wps_nfc_dh_privkey), CFG_CHANGED_NFC_PASSWORD_TOKEN },
+ { BIN(wps_nfc_dev_pw), CFG_CHANGED_NFC_PASSWORD_TOKEN },
{ STR(ext_password_backend), CFG_CHANGED_EXT_PW_BACKEND },
{ INT(p2p_go_max_inactivity), 0 },
{ INT_RANGE(auto_interworking, 0, 1), 0 },
+ { INT(okc), 0 },
+ { INT(pmf), 0 },
+ { FUNC(sae_groups), 0 },
+ { INT(dtim_period), 0 },
+ { INT(beacon_int), 0 },
+ { FUNC(ap_vendor_elements), 0 },
+ { INT_RANGE(ignore_old_scan_res, 0, 1), 0 },
};
#undef FUNC
@@ -3054,6 +3120,8 @@
"parse '%s'.", line, pos);
ret = -1;
}
+ if (field->changed_flag == CFG_CHANGED_NFC_PASSWORD_TOKEN)
+ config->wps_nfc_pw_from_config = 1;
config->changed_parameters |= field->changed_flag;
break;
}
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index b889ab8..4a175ce 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -196,6 +196,12 @@
* Pre-configured EAP parameters or %NULL.
*/
char *phase2;
+
+ struct excluded_ssid {
+ u8 ssid[MAX_SSID_LEN];
+ size_t ssid_len;
+ } *excluded_ssid;
+ size_t num_excluded_ssid;
};
@@ -214,6 +220,7 @@
#define CFG_CHANGED_P2P_OPER_CHANNEL BIT(12)
#define CFG_CHANGED_P2P_PREF_CHAN BIT(13)
#define CFG_CHANGED_EXT_PW_BACKEND BIT(14)
+#define CFG_CHANGED_NFC_PASSWORD_TOKEN BIT(15)
/**
* struct wpa_config - wpa_supplicant configuration data
@@ -564,6 +571,7 @@
int p2p_intra_bss;
unsigned int num_p2p_pref_chan;
struct p2p_channel *p2p_pref_chan;
+ int p2p_ignore_shared_freq;
struct wpabuf *wps_vendor_ext_m1;
@@ -700,6 +708,15 @@
char *autoscan;
/**
+ * wps_nfc_pw_from_config - NFC Device Password was read from config
+ *
+ * This parameter can be determined whether the NFC Device Password was
+ * included in the configuration (1) or generated dynamically (0). Only
+ * the former case is re-written back to the configuration file.
+ */
+ int wps_nfc_pw_from_config;
+
+ /**
* wps_nfc_dev_pw_id - NFC Device Password ID for password token
*/
int wps_nfc_dev_pw_id;
@@ -710,12 +727,12 @@
struct wpabuf *wps_nfc_dh_pubkey;
/**
- * wps_nfc_dh_pubkey - NFC DH Private Key for password token
+ * wps_nfc_dh_privkey - NFC DH Private Key for password token
*/
struct wpabuf *wps_nfc_dh_privkey;
/**
- * wps_nfc_dh_pubkey - NFC Device Password for password token
+ * wps_nfc_dev_pw - NFC Device Password for password token
*/
struct wpabuf *wps_nfc_dev_pw;
@@ -747,6 +764,96 @@
* matching network block
*/
int auto_interworking;
+
+ /**
+ * p2p_go_ht40 - Default mode for HT40 enable when operating as GO.
+ *
+ * This will take effect for p2p_group_add, p2p_connect, and p2p_invite.
+ * Note that regulatory constraints and driver capabilities are
+ * consulted anyway, so setting it to 1 can't do real harm.
+ * By default: 0 (disabled)
+ */
+ int p2p_go_ht40;
+
+ /**
+ * p2p_disabled - Whether P2P operations are disabled for this interface
+ */
+ int p2p_disabled;
+
+ /**
+ * p2p_no_group_iface - Whether group interfaces can be used
+ *
+ * By default, wpa_supplicant will create a separate interface for P2P
+ * group operations if the driver supports this. This functionality can
+ * be disabled by setting this parameter to 1. In that case, the same
+ * interface that was used for the P2P management operations is used
+ * also for the group operation.
+ */
+ int p2p_no_group_iface;
+
+ /**
+ * okc - Whether to enable opportunistic key caching by default
+ *
+ * By default, OKC is disabled unless enabled by the per-network
+ * proactive_key_caching=1 parameter. okc=1 can be used to change this
+ * default behavior.
+ */
+ int okc;
+
+ /**
+ * pmf - Whether to enable/require PMF by default
+ *
+ * By default, PMF is disabled unless enabled by the per-network
+ * ieee80211w=1 or ieee80211w=2 parameter. pmf=1/2 can be used to change
+ * this default behavior.
+ */
+ enum mfp_options pmf;
+
+ /**
+ * sae_groups - Preference list of enabled groups for SAE
+ *
+ * By default (if this parameter is not set), the mandatory group 19
+ * (ECC group defined over a 256-bit prime order field) is preferred,
+ * but other groups are also enabled. If this parameter is set, the
+ * groups will be tried in the indicated order.
+ */
+ int *sae_groups;
+
+ /**
+ * dtim_period - Default DTIM period in Beacon intervals
+ *
+ * This parameter can be used to set the default value for network
+ * blocks that do not specify dtim_period.
+ */
+ int dtim_period;
+
+ /**
+ * beacon_int - Default Beacon interval in TU
+ *
+ * This parameter can be used to set the default value for network
+ * blocks that do not specify beacon_int.
+ */
+ int beacon_int;
+
+ /**
+ * ap_vendor_elements: Vendor specific elements for Beacon/ProbeResp
+ *
+ * This parameter can be used to define additional vendor specific
+ * elements for Beacon and Probe Response frames in AP/P2P GO mode. The
+ * format for these element(s) is a hexdump of the raw information
+ * elements (id+len+payload for one or more elements).
+ */
+ struct wpabuf *ap_vendor_elements;
+
+ /**
+ * ignore_old_scan_res - Ignore scan results older than request
+ *
+ * The driver may have a cache of scan results that makes it return
+ * information that is older than our scan trigger. This parameter can
+ * be used to configure such old information to be ignored instead of
+ * allowing it to update the internal BSS table.
+ */
+ int ignore_old_scan_res;
};
@@ -805,6 +912,7 @@
* wpa_config_read - Read and parse configuration database
* @name: Name of the configuration (e.g., path and file name for the
* configuration file)
+ * @cfgp: Pointer to previously allocated configuration data or %NULL if none
* Returns: Pointer to allocated configuration data or %NULL on failure
*
* This function reads configuration data, parses its contents, and allocates
@@ -813,7 +921,7 @@
*
* Each configuration backend needs to implement this function.
*/
-struct wpa_config * wpa_config_read(const char *name);
+struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp);
/**
* wpa_config_write - Write or update configuration data
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 531957a..8604ae8 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -17,6 +17,8 @@
#include "base64.h"
#include "uuid.h"
#include "p2p/p2p.h"
+#include "eap_peer/eap_methods.h"
+#include "eap_peer/eap.h"
static int newline_terminated(const char *buf, size_t buflen)
@@ -343,7 +345,7 @@
#endif /* CONFIG_NO_CONFIG_BLOBS */
-struct wpa_config * wpa_config_read(const char *name)
+struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp)
{
FILE *f;
char buf[512], *pos;
@@ -354,12 +356,19 @@
int id = 0;
int cred_id = 0;
- config = wpa_config_alloc_empty(NULL, NULL);
+ if (name == NULL)
+ return NULL;
+ if (cfgp)
+ config = cfgp;
+ else
+ config = wpa_config_alloc_empty(NULL, NULL);
if (config == NULL) {
wpa_printf(MSG_ERROR, "Failed to allocate config file "
"structure");
return NULL;
}
+ head = config->ssid;
+ cred_head = config->cred;
wpa_printf(MSG_DEBUG, "Reading configuration file '%s'", name);
f = fopen(name, "r");
@@ -676,16 +685,20 @@
INT_DEFe(fragment_size, DEFAULT_FRAGMENT_SIZE);
#endif /* IEEE8021X_EAPOL */
INT(mode);
- INT(proactive_key_caching);
+ INT(frequency);
+ write_int(f, "proactive_key_caching", ssid->proactive_key_caching, -1);
INT(disabled);
INT(peerkey);
#ifdef CONFIG_IEEE80211W
- INT(ieee80211w);
+ write_int(f, "ieee80211w", ssid->ieee80211w,
+ MGMT_FRAME_PROTECTION_DEFAULT);
#endif /* CONFIG_IEEE80211W */
STR(id_str);
#ifdef CONFIG_P2P
write_p2p_client_list(f, ssid);
#endif /* CONFIG_P2P */
+ INT(dtim_period);
+ INT(beacon_int);
#undef STR
#undef INT
@@ -703,16 +716,52 @@
fprintf(f, "\trealm=\"%s\"\n", cred->realm);
if (cred->username)
fprintf(f, "\tusername=\"%s\"\n", cred->username);
- if (cred->password)
+ if (cred->password && cred->ext_password)
+ fprintf(f, "\tpassword=ext:%s\n", cred->password);
+ else if (cred->password)
fprintf(f, "\tpassword=\"%s\"\n", cred->password);
if (cred->ca_cert)
fprintf(f, "\tca_cert=\"%s\"\n", cred->ca_cert);
+ if (cred->client_cert)
+ fprintf(f, "\tclient_cert=\"%s\"\n", cred->client_cert);
+ if (cred->private_key)
+ fprintf(f, "\tprivate_key=\"%s\"\n", cred->private_key);
+ if (cred->private_key_passwd)
+ fprintf(f, "\tprivate_key_passwd=\"%s\"\n",
+ cred->private_key_passwd);
if (cred->imsi)
fprintf(f, "\timsi=\"%s\"\n", cred->imsi);
if (cred->milenage)
fprintf(f, "\tmilenage=\"%s\"\n", cred->milenage);
if (cred->domain)
fprintf(f, "\tdomain=\"%s\"\n", cred->domain);
+ if (cred->roaming_consortium_len) {
+ size_t i;
+ fprintf(f, "\troaming_consortium=");
+ for (i = 0; i < cred->roaming_consortium_len; i++)
+ fprintf(f, "%02x", cred->roaming_consortium[i]);
+ fprintf(f, "\n");
+ }
+ if (cred->eap_method) {
+ const char *name;
+ name = eap_get_name(cred->eap_method[0].vendor,
+ cred->eap_method[0].method);
+ fprintf(f, "\teap=%s\n", name);
+ }
+ if (cred->phase1)
+ fprintf(f, "\tphase1=\"%s\"\n", cred->phase1);
+ if (cred->phase2)
+ fprintf(f, "\tphase2=\"%s\"\n", cred->phase2);
+ if (cred->excluded_ssid) {
+ size_t i, j;
+ for (i = 0; i < cred->num_excluded_ssid; i++) {
+ struct excluded_ssid *e = &cred->excluded_ssid[i];
+ fprintf(f, "\texcluded_ssid=");
+ for (j = 0; j < e->ssid_len; j++)
+ fprintf(f, "%02x", e->ssid[j]);
+ fprintf(f, "\n");
+ }
+ }
}
@@ -868,6 +917,16 @@
}
fprintf(f, "\n");
}
+ if (config->p2p_go_ht40)
+ fprintf(f, "p2p_go_ht40=%u\n", config->p2p_go_ht40);
+ if (config->p2p_disabled)
+ fprintf(f, "p2p_disabled=%u\n", config->p2p_disabled);
+ if (config->p2p_no_group_iface)
+ fprintf(f, "p2p_no_group_iface=%u\n",
+ config->p2p_no_group_iface);
+ if (config->p2p_ignore_shared_freq)
+ fprintf(f, "p2p_ignore_shared_freq=%u\n",
+ config->p2p_ignore_shared_freq);
#endif /* CONFIG_P2P */
if (config->country[0] && config->country[1]) {
fprintf(f, "country=%c%c\n",
@@ -903,12 +962,16 @@
#endif /* CONFIG_INTERWORKING */
if (config->pbc_in_m1)
fprintf(f, "pbc_in_m1=%u\n", config->pbc_in_m1);
- if (config->wps_nfc_dev_pw_id)
- fprintf(f, "wps_nfc_dev_pw_id=%d\n",
- config->wps_nfc_dev_pw_id);
- write_global_bin(f, "wps_nfc_dh_pubkey", config->wps_nfc_dh_pubkey);
- write_global_bin(f, "wps_nfc_dh_privkey", config->wps_nfc_dh_privkey);
- write_global_bin(f, "wps_nfc_dev_pw", config->wps_nfc_dev_pw);
+ if (config->wps_nfc_pw_from_config) {
+ if (config->wps_nfc_dev_pw_id)
+ fprintf(f, "wps_nfc_dev_pw_id=%d\n",
+ config->wps_nfc_dev_pw_id);
+ write_global_bin(f, "wps_nfc_dh_pubkey",
+ config->wps_nfc_dh_pubkey);
+ write_global_bin(f, "wps_nfc_dh_privkey",
+ config->wps_nfc_dh_privkey);
+ write_global_bin(f, "wps_nfc_dev_pw", config->wps_nfc_dev_pw);
+ }
if (config->ext_password_backend)
fprintf(f, "ext_password_backend=%s\n",
@@ -919,6 +982,39 @@
if (config->auto_interworking)
fprintf(f, "auto_interworking=%d\n",
config->auto_interworking);
+ if (config->okc)
+ fprintf(f, "okc=%d\n", config->okc);
+ if (config->pmf)
+ fprintf(f, "pmf=%d\n", config->pmf);
+ if (config->dtim_period)
+ fprintf(f, "dtim_period=%d\n", config->dtim_period);
+ if (config->beacon_int)
+ fprintf(f, "beacon_int=%d\n", config->beacon_int);
+
+ if (config->sae_groups) {
+ int i;
+ fprintf(f, "sae_groups=");
+ for (i = 0; config->sae_groups[i] >= 0; i++) {
+ fprintf(f, "%s%d", i > 0 ? " " : "",
+ config->sae_groups[i]);
+ }
+ fprintf(f, "\n");
+ }
+
+ if (config->ap_vendor_elements) {
+ int i, len = wpabuf_len(config->ap_vendor_elements);
+ const u8 *p = wpabuf_head_u8(config->ap_vendor_elements);
+ if (len > 0) {
+ fprintf(f, "ap_vendor_elements=");
+ for (i = 0; i < len; i++)
+ fprintf(f, "%02x", *p++);
+ fprintf(f, "\n");
+ }
+ }
+
+ if (config->ignore_old_scan_res)
+ fprintf(f, "ignore_old_scan_res=%d\n",
+ config->ignore_old_scan_res);
}
#endif /* CONFIG_NO_CONFIG_WRITE */
diff --git a/wpa_supplicant/config_none.c b/wpa_supplicant/config_none.c
index 589ea36..2aac28f 100644
--- a/wpa_supplicant/config_none.c
+++ b/wpa_supplicant/config_none.c
@@ -17,11 +17,16 @@
#include "base64.h"
-struct wpa_config * wpa_config_read(const char *name)
+struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp)
{
struct wpa_config *config;
- config = wpa_config_alloc_empty(NULL, NULL);
+ if (name == NULL)
+ return NULL;
+ if (cfgp)
+ config = cfgp;
+ else
+ config = wpa_config_alloc_empty(NULL, NULL);
if (config == NULL)
return NULL;
/* TODO: fill in configuration data */
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index ff97379..baa28b3 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -28,6 +28,7 @@
#define DEFAULT_BG_SCAN_PERIOD -1
#define DEFAULT_DISABLE_HT 0
#define DEFAULT_DISABLE_HT40 0
+#define DEFAULT_DISABLE_SGI 0
#define DEFAULT_DISABLE_MAX_AMSDU -1 /* no change */
#define DEFAULT_AMPDU_FACTOR -1 /* no change */
#define DEFAULT_AMPDU_DENSITY -1 /* no change */
@@ -228,13 +229,18 @@
*
* This field can be used to enable proactive key caching which is also
* known as opportunistic PMKSA caching for WPA2. This is disabled (0)
- * by default. Enable by setting this to 1.
+ * by default unless default value is changed with the global okc=1
+ * parameter. Enable by setting this to 1.
*
* Proactive key caching is used to make supplicant assume that the APs
* are using the same PMK and generate PMKSA cache entries without
* doing RSN pre-authentication. This requires support from the AP side
* and is normally used with wireless switches that co-locate the
* authenticator.
+ *
+ * Internally, special value -1 is used to indicate that the parameter
+ * was not specified in the configuration (i.e., default behavior is
+ * followed).
*/
int proactive_key_caching;
@@ -323,6 +329,14 @@
int disabled;
/**
+ * disabled_for_connect - Whether this network was temporarily disabled
+ *
+ * This flag is used to reenable all the temporarily disabled networks
+ * after either the success or failure of a WPS connection.
+ */
+ int disabled_for_connect;
+
+ /**
* peerkey - Whether PeerKey handshake for direct links is allowed
*
* This is only used when both RSN/WPA2 and IEEE 802.11e (QoS) are
@@ -348,6 +362,12 @@
*
* This value is used to configure policy for management frame
* protection (IEEE 802.11w). 0 = disabled, 1 = optional, 2 = required.
+ * This is disabled by default unless the default value has been changed
+ * with the global pmf=1/2 parameter.
+ *
+ * Internally, special value 3 is used to indicate that the parameter
+ * was not specified in the configuration (i.e., default behavior is
+ * followed).
*/
enum mfp_options ieee80211w;
#endif /* CONFIG_IEEE80211W */
@@ -483,6 +503,14 @@
int disable_ht40;
/**
+ * disable_sgi - Disable SGI (Short Guard Interval) for this network
+ *
+ * By default, use it if it is available, but this can be configured
+ * to 1 to have it disabled.
+ */
+ int disable_sgi;
+
+ /**
* disable_max_amsdu - Disable MAX A-MSDU
*
* A-MDSU will be 3839 bytes when disabled, or 7935
@@ -513,6 +541,35 @@
char *ht_mcs;
#endif /* CONFIG_HT_OVERRIDES */
+#ifdef CONFIG_VHT_OVERRIDES
+ /**
+ * disable_vht - Disable VHT (IEEE 802.11ac) for this network
+ *
+ * By default, use it if it is available, but this can be configured
+ * to 1 to have it disabled.
+ */
+ int disable_vht;
+
+ /**
+ * vht_capa - VHT capabilities to use
+ */
+ unsigned int vht_capa;
+
+ /**
+ * vht_capa_mask - mask for VHT capabilities
+ */
+ unsigned int vht_capa_mask;
+
+ int vht_rx_mcs_nss_1, vht_rx_mcs_nss_2,
+ vht_rx_mcs_nss_3, vht_rx_mcs_nss_4,
+ vht_rx_mcs_nss_5, vht_rx_mcs_nss_6,
+ vht_rx_mcs_nss_7, vht_rx_mcs_nss_8;
+ int vht_tx_mcs_nss_1, vht_tx_mcs_nss_2,
+ vht_tx_mcs_nss_3, vht_tx_mcs_nss_4,
+ vht_tx_mcs_nss_5, vht_tx_mcs_nss_6,
+ vht_tx_mcs_nss_7, vht_tx_mcs_nss_8;
+#endif /* CONFIG_VHT_OVERRIDES */
+
/**
* ap_max_inactivity - Timeout in seconds to detect STA's inactivity
*
@@ -528,6 +585,11 @@
int dtim_period;
/**
+ * beacon_int - Beacon interval (default: 100 TU)
+ */
+ int beacon_int;
+
+ /**
* auth_failures - Number of consecutive authentication failures
*/
unsigned int auth_failures;
@@ -536,6 +598,15 @@
* disabled_until - Network block disabled until this time if non-zero
*/
struct os_time disabled_until;
+
+ /**
+ * parent_cred - Pointer to parent wpa_cred entry
+ *
+ * This pointer can be used to delete temporary networks when a wpa_cred
+ * that was used to create them is removed. This pointer should not be
+ * dereferences since it may not be updated in all cases.
+ */
+ void *parent_cred;
};
#endif /* CONFIG_SSID_H */
diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c
index 6d9876c..3cf3a91 100644
--- a/wpa_supplicant/config_winreg.c
+++ b/wpa_supplicant/config_winreg.c
@@ -202,6 +202,7 @@
static int wpa_config_read_global(struct wpa_config *config, HKEY hk)
{
int errors = 0;
+ int val;
wpa_config_read_reg_dword(hk, TEXT("ap_scan"), &config->ap_scan);
wpa_config_read_reg_dword(hk, TEXT("fast_reauth"),
@@ -271,6 +272,10 @@
wpa_config_read_reg_dword(hk, TEXT("disassoc_low_ack"),
(int *) &config->disassoc_low_ack);
+ wpa_config_read_reg_dword(hk, TEXT("okc"), &config->okc);
+ wpa_config_read_reg_dword(hk, TEXT("pmf"), &val);
+ config->pmf = val;
+
return errors ? -1 : 0;
}
@@ -429,7 +434,7 @@
}
-struct wpa_config * wpa_config_read(const char *name)
+struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp)
{
TCHAR buf[256];
int errors = 0;
@@ -437,7 +442,12 @@
HKEY hk;
LONG ret;
- config = wpa_config_alloc_empty(NULL, NULL);
+ if (name == NULL)
+ return NULL;
+ if (cfgp)
+ config = cfgp;
+ else
+ config = wpa_config_alloc_empty(NULL, NULL);
if (config == NULL)
return NULL;
wpa_printf(MSG_DEBUG, "Reading configuration profile '%s'", name);
@@ -609,6 +619,9 @@
wpa_config_write_reg_dword(hk, TEXT("disassoc_low_ack"),
config->disassoc_low_ack, 0);
+ wpa_config_write_reg_dword(hk, TEXT("okc"), config->okc, 0);
+ wpa_config_write_reg_dword(hk, TEXT("pmf"), config->pmf, 0);
+
return 0;
}
@@ -904,11 +917,13 @@
INT_DEFe(fragment_size, DEFAULT_FRAGMENT_SIZE);
#endif /* IEEE8021X_EAPOL */
INT(mode);
- INT(proactive_key_caching);
+ write_int(netw, "proactive_key_caching", ssid->proactive_key_caching,
+ -1);
INT(disabled);
INT(peerkey);
#ifdef CONFIG_IEEE80211W
- INT(ieee80211w);
+ write_int(netw, "ieee80211w", ssid->ieee80211w,
+ MGMT_FRAME_PROTECTION_DEFAULT);
#endif /* CONFIG_IEEE80211W */
STR(id_str);
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index bcf27be..ad0392f 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -37,8 +37,8 @@
#include "ctrl_iface.h"
#include "interworking.h"
#include "blacklist.h"
-#include "wpas_glue.h"
#include "autoscan.h"
+#include "wnm_sta.h"
extern struct wpa_driver_ops *wpa_drivers[];
@@ -58,6 +58,11 @@
if (wpa_s->pno)
return 0;
+ if (wpa_s->wpa_state == WPA_SCANNING) {
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpa_supplicant_cancel_scan(wpa_s);
+ }
+
os_memset(¶ms, 0, sizeof(params));
num_ssid = 0;
@@ -113,11 +118,17 @@
static int pno_stop(struct wpa_supplicant *wpa_s)
{
+ int ret = 0;
+
if (wpa_s->pno) {
wpa_s->pno = 0;
- return wpa_drv_stop_sched_scan(wpa_s);
+ ret = wpa_drv_stop_sched_scan(wpa_s);
}
- return 0;
+
+ if (wpa_s->wpa_state == WPA_SCANNING)
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+ return ret;
}
@@ -158,6 +169,128 @@
}
+static int set_disallow_aps(struct wpa_supplicant *wpa_s, char *val)
+{
+ char *pos;
+ u8 addr[ETH_ALEN], *bssid = NULL, *n;
+ struct wpa_ssid_value *ssid = NULL, *ns;
+ size_t count = 0, ssid_count = 0;
+ struct wpa_ssid *c;
+
+ /*
+ * disallow_list ::= <ssid_spec> | <bssid_spec> | <disallow_list> | “”
+ * SSID_SPEC ::= ssid <SSID_HEX>
+ * BSSID_SPEC ::= bssid <BSSID_HEX>
+ */
+
+ pos = val;
+ while (pos) {
+ if (*pos == '\0')
+ break;
+ if (os_strncmp(pos, "bssid ", 6) == 0) {
+ int res;
+ pos += 6;
+ res = hwaddr_aton2(pos, addr);
+ if (res < 0) {
+ os_free(ssid);
+ os_free(bssid);
+ wpa_printf(MSG_DEBUG, "Invalid disallow_aps "
+ "BSSID value '%s'", pos);
+ return -1;
+ }
+ pos += res;
+ n = os_realloc_array(bssid, count + 1, ETH_ALEN);
+ if (n == NULL) {
+ os_free(ssid);
+ os_free(bssid);
+ return -1;
+ }
+ bssid = n;
+ os_memcpy(bssid + count * ETH_ALEN, addr, ETH_ALEN);
+ count++;
+ } else if (os_strncmp(pos, "ssid ", 5) == 0) {
+ char *end;
+ pos += 5;
+
+ end = pos;
+ while (*end) {
+ if (*end == '\0' || *end == ' ')
+ break;
+ end++;
+ }
+
+ ns = os_realloc_array(ssid, ssid_count + 1,
+ sizeof(struct wpa_ssid_value));
+ if (ns == NULL) {
+ os_free(ssid);
+ os_free(bssid);
+ return -1;
+ }
+ ssid = ns;
+
+ if ((end - pos) & 0x01 || end - pos > 2 * 32 ||
+ hexstr2bin(pos, ssid[ssid_count].ssid,
+ (end - pos) / 2) < 0) {
+ os_free(ssid);
+ os_free(bssid);
+ wpa_printf(MSG_DEBUG, "Invalid disallow_aps "
+ "SSID value '%s'", pos);
+ return -1;
+ }
+ ssid[ssid_count].ssid_len = (end - pos) / 2;
+ wpa_hexdump_ascii(MSG_DEBUG, "disallow_aps SSID",
+ ssid[ssid_count].ssid,
+ ssid[ssid_count].ssid_len);
+ ssid_count++;
+ pos = end;
+ } else {
+ wpa_printf(MSG_DEBUG, "Unexpected disallow_aps value "
+ "'%s'", pos);
+ os_free(ssid);
+ os_free(bssid);
+ return -1;
+ }
+
+ pos = os_strchr(pos, ' ');
+ if (pos)
+ pos++;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "disallow_aps_bssid", bssid, count * ETH_ALEN);
+ os_free(wpa_s->disallow_aps_bssid);
+ wpa_s->disallow_aps_bssid = bssid;
+ wpa_s->disallow_aps_bssid_count = count;
+
+ wpa_printf(MSG_DEBUG, "disallow_aps_ssid_count %d", (int) ssid_count);
+ os_free(wpa_s->disallow_aps_ssid);
+ wpa_s->disallow_aps_ssid = ssid;
+ wpa_s->disallow_aps_ssid_count = ssid_count;
+
+ if (!wpa_s->current_ssid || wpa_s->wpa_state < WPA_AUTHENTICATING)
+ return 0;
+
+ c = wpa_s->current_ssid;
+ if (c->mode != WPAS_MODE_INFRA && c->mode != WPAS_MODE_IBSS)
+ return 0;
+
+ if (!disallowed_bssid(wpa_s, wpa_s->bssid) &&
+ !disallowed_ssid(wpa_s, c->ssid, c->ssid_len))
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "Disconnect and try to find another network "
+ "because current AP was marked disallowed");
+
+#ifdef CONFIG_SME
+ wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
+ wpa_s->reassociate = 1;
+ wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+ return 0;
+}
+
+
static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
char *cmd)
{
@@ -291,6 +424,10 @@
#endif /* CONFIG_WIFI_DISPLAY */
} else if (os_strcasecmp(cmd, "bssid_filter") == 0) {
ret = set_bssid_filter(wpa_s, value);
+ } else if (os_strcasecmp(cmd, "disallow_aps") == 0) {
+ ret = set_disallow_aps(wpa_s, value);
+ } else if (os_strcasecmp(cmd, "no_keep_alive") == 0) {
+ wpa_s->no_keep_alive = !!atoi(value);
} else {
value[-1] = '=';
ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
@@ -417,13 +554,12 @@
wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP " MACSTR,
MAC2STR(peer));
- ret = wpa_tdls_reneg(wpa_s->wpa, peer);
- if (ret) {
- if (wpa_tdls_is_external_setup(wpa_s->wpa))
- ret = wpa_tdls_start(wpa_s->wpa, peer);
- else
- ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
- }
+ wpa_tdls_remove(wpa_s->wpa, peer);
+
+ if (wpa_tdls_is_external_setup(wpa_s->wpa))
+ ret = wpa_tdls_start(wpa_s->wpa, peer);
+ else
+ ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
return ret;
}
@@ -540,9 +676,21 @@
}
#ifdef CONFIG_AP
- if (wpa_s->ap_iface)
+ if (wpa_s->ap_iface) {
+ int timeout = 0;
+ char *pos;
+
+ if (pin) {
+ pos = os_strchr(pin, ' ');
+ if (pos) {
+ *pos++ = '\0';
+ timeout = atoi(pos);
+ }
+ }
+
return wpa_supplicant_ap_wps_pin(wpa_s, _bssid, pin,
- buf, buflen);
+ buf, buflen, timeout);
+ }
#endif /* CONFIG_AP */
if (pin) {
@@ -614,31 +762,6 @@
}
-#ifdef CONFIG_WPS_OOB
-static int wpa_supplicant_ctrl_iface_wps_oob(struct wpa_supplicant *wpa_s,
- char *cmd)
-{
- char *path, *method, *name;
-
- path = os_strchr(cmd, ' ');
- if (path == NULL)
- return -1;
- *path++ = '\0';
-
- method = os_strchr(path, ' ');
- if (method == NULL)
- return -1;
- *method++ = '\0';
-
- name = os_strchr(method, ' ');
- if (name != NULL)
- *name++ = '\0';
-
- return wpas_wps_start_oob(wpa_s, cmd, path, method, name);
-}
-#endif /* CONFIG_WPS_OOB */
-
-
#ifdef CONFIG_WPS_NFC
static int wpa_supplicant_ctrl_iface_wps_nfc(struct wpa_supplicant *wpa_s,
@@ -655,6 +778,39 @@
}
+static int wpa_supplicant_ctrl_iface_wps_nfc_config_token(
+ struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
+{
+ int ndef;
+ struct wpabuf *buf;
+ int res;
+ char *pos;
+
+ pos = os_strchr(cmd, ' ');
+ if (pos)
+ *pos++ = '\0';
+ if (os_strcmp(cmd, "WPS") == 0)
+ ndef = 0;
+ else if (os_strcmp(cmd, "NDEF") == 0)
+ ndef = 1;
+ else
+ return -1;
+
+ buf = wpas_wps_nfc_config_token(wpa_s, ndef, pos);
+ if (buf == NULL)
+ return -1;
+
+ res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+ wpabuf_len(buf));
+ reply[res++] = '\n';
+ reply[res] = '\0';
+
+ wpabuf_free(buf);
+
+ return res;
+}
+
+
static int wpa_supplicant_ctrl_iface_wps_nfc_token(
struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
{
@@ -710,6 +866,230 @@
return ret;
}
+
+static int wpas_ctrl_nfc_get_handover_req_wps(struct wpa_supplicant *wpa_s,
+ char *reply, size_t max_len,
+ int cr)
+{
+ struct wpabuf *buf;
+ int res;
+
+ buf = wpas_wps_nfc_handover_req(wpa_s, cr);
+ if (buf == NULL)
+ return -1;
+
+ res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+ wpabuf_len(buf));
+ reply[res++] = '\n';
+ reply[res] = '\0';
+
+ wpabuf_free(buf);
+
+ return res;
+}
+
+
+static int wpas_ctrl_nfc_get_handover_req(struct wpa_supplicant *wpa_s,
+ char *cmd, char *reply,
+ size_t max_len)
+{
+ char *pos;
+
+ pos = os_strchr(cmd, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ if (os_strcmp(cmd, "NDEF") != 0)
+ return -1;
+
+ if (os_strcmp(pos, "WPS") == 0 || os_strcmp(pos, "WPS-CR") == 0) {
+ return wpas_ctrl_nfc_get_handover_req_wps(
+ wpa_s, reply, max_len, os_strcmp(pos, "WPS-CR") == 0);
+ }
+
+ return -1;
+}
+
+
+static int wpas_ctrl_nfc_get_handover_sel_wps(struct wpa_supplicant *wpa_s,
+ char *reply, size_t max_len,
+ int ndef, int cr, char *uuid)
+{
+ struct wpabuf *buf;
+ int res;
+
+ buf = wpas_wps_nfc_handover_sel(wpa_s, ndef, cr, uuid);
+ if (buf == NULL)
+ return -1;
+
+ res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+ wpabuf_len(buf));
+ reply[res++] = '\n';
+ reply[res] = '\0';
+
+ wpabuf_free(buf);
+
+ return res;
+}
+
+
+static int wpas_ctrl_nfc_get_handover_sel(struct wpa_supplicant *wpa_s,
+ char *cmd, char *reply,
+ size_t max_len)
+{
+ char *pos, *pos2;
+ int ndef;
+
+ pos = os_strchr(cmd, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ if (os_strcmp(cmd, "WPS") == 0)
+ ndef = 0;
+ else if (os_strcmp(cmd, "NDEF") == 0)
+ ndef = 1;
+ else
+ return -1;
+
+ pos2 = os_strchr(pos, ' ');
+ if (pos2)
+ *pos2++ = '\0';
+ if (os_strcmp(pos, "WPS") == 0 || os_strcmp(pos, "WPS-CR") == 0) {
+ return wpas_ctrl_nfc_get_handover_sel_wps(
+ wpa_s, reply, max_len, ndef,
+ os_strcmp(pos, "WPS-CR") == 0, pos2);
+ }
+
+ return -1;
+}
+
+
+static int wpas_ctrl_nfc_rx_handover_req(struct wpa_supplicant *wpa_s,
+ char *cmd, char *reply,
+ size_t max_len)
+{
+ size_t len;
+ struct wpabuf *buf;
+ int ret;
+
+ len = os_strlen(cmd);
+ if (len & 0x01)
+ return -1;
+ len /= 2;
+
+ buf = wpabuf_alloc(len);
+ if (buf == NULL)
+ return -1;
+ if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
+ wpabuf_free(buf);
+ return -1;
+ }
+
+ ret = wpas_wps_nfc_rx_handover_req(wpa_s, buf);
+ wpabuf_free(buf);
+
+ return ret;
+}
+
+
+static int wpas_ctrl_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ size_t len;
+ struct wpabuf *buf;
+ int ret;
+
+ len = os_strlen(cmd);
+ if (len & 0x01)
+ return -1;
+ len /= 2;
+
+ buf = wpabuf_alloc(len);
+ if (buf == NULL)
+ return -1;
+ if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
+ wpabuf_free(buf);
+ return -1;
+ }
+
+ ret = wpas_wps_nfc_rx_handover_sel(wpa_s, buf);
+ wpabuf_free(buf);
+
+ return ret;
+}
+
+
+static int wpas_ctrl_nfc_report_handover(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ size_t len;
+ struct wpabuf *req, *sel;
+ int ret;
+ char *pos, *role, *type, *pos2;
+
+ role = cmd;
+ pos = os_strchr(role, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ type = pos;
+ pos = os_strchr(type, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ pos2 = os_strchr(pos, ' ');
+ if (pos2 == NULL)
+ return -1;
+ *pos2++ = '\0';
+
+ len = os_strlen(pos);
+ if (len & 0x01)
+ return -1;
+ len /= 2;
+
+ req = wpabuf_alloc(len);
+ if (req == NULL)
+ return -1;
+ if (hexstr2bin(pos, wpabuf_put(req, len), len) < 0) {
+ wpabuf_free(req);
+ return -1;
+ }
+
+ len = os_strlen(pos2);
+ if (len & 0x01) {
+ wpabuf_free(req);
+ return -1;
+ }
+ len /= 2;
+
+ sel = wpabuf_alloc(len);
+ if (sel == NULL) {
+ wpabuf_free(req);
+ return -1;
+ }
+ if (hexstr2bin(pos2, wpabuf_put(sel, len), len) < 0) {
+ wpabuf_free(req);
+ wpabuf_free(sel);
+ return -1;
+ }
+
+ if (os_strcmp(role, "INIT") == 0 && os_strcmp(type, "WPS") == 0) {
+ ret = wpas_wps_nfc_report_handover(wpa_s, req, sel);
+ } else {
+ wpa_printf(MSG_DEBUG, "NFC: Unsupported connection handover "
+ "reported: role=%s type=%s", role, type);
+ ret = -1;
+ }
+ wpabuf_free(req);
+ wpabuf_free(sel);
+
+ return ret;
+}
+
#endif /* CONFIG_WPS_NFC */
@@ -1106,6 +1486,16 @@
#endif /* CONFIG_AP */
pos += wpa_sm_get_status(wpa_s->wpa, pos, end - pos, verbose);
}
+#ifdef CONFIG_SAE
+ if (wpa_s->wpa_state >= WPA_ASSOCIATED &&
+ wpa_s->sme.sae.state == SAE_ACCEPTED && !wpa_s->ap_iface) {
+ ret = os_snprintf(pos, end - pos, "sae_group=%d\n",
+ wpa_s->sme.sae.group);
+ if (ret < 0 || ret >= end - pos)
+ 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)
@@ -1146,6 +1536,45 @@
return pos - buf;
pos += ret;
}
+
+ if (wpa_s->current_ssid) {
+ struct wpa_cred *cred;
+ char *type;
+
+ for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+ if (wpa_s->current_ssid->parent_cred != cred)
+ continue;
+ if (!cred->domain)
+ continue;
+
+ ret = os_snprintf(pos, end - pos, "home_sp=%s\n",
+ cred->domain);
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+
+ if (wpa_s->current_bss == NULL ||
+ wpa_s->current_bss->anqp == NULL)
+ res = -1;
+ else
+ res = interworking_home_sp_cred(
+ wpa_s, cred,
+ wpa_s->current_bss->anqp->domain_name);
+ if (res > 0)
+ type = "home";
+ else if (res == 0)
+ type = "roaming";
+ else
+ type = "unknown";
+
+ ret = os_snprintf(pos, end - pos, "sp_type=%s\n", type);
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+
+ break;
+ }
+ }
#endif /* CONFIG_HS20 */
if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
@@ -1173,8 +1602,7 @@
struct wpa_ssid *ssid = wpa_s->current_ssid;
wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED "- connection to "
MACSTR " completed %s [id=%d id_str=%s]",
- MAC2STR(wpa_s->bssid), wpa_s->reassociated_connection ?
- "(reauth)" : "(auth)",
+ MAC2STR(wpa_s->bssid), "(auth)",
ssid ? ssid->id : -1,
ssid && ssid->id_str ? ssid->id_str : "");
}
@@ -1421,54 +1849,15 @@
static char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher)
{
- int first = 1, ret;
+ int ret;
ret = os_snprintf(pos, end - pos, "-");
if (ret < 0 || ret >= end - pos)
return pos;
pos += ret;
- if (cipher & WPA_CIPHER_NONE) {
- ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : "+");
- if (ret < 0 || ret >= end - pos)
- return pos;
- pos += ret;
- first = 0;
- }
- if (cipher & WPA_CIPHER_WEP40) {
- ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : "+");
- if (ret < 0 || ret >= end - pos)
- return pos;
- pos += ret;
- first = 0;
- }
- if (cipher & WPA_CIPHER_WEP104) {
- ret = os_snprintf(pos, end - pos, "%sWEP104",
- first ? "" : "+");
- if (ret < 0 || ret >= end - pos)
- return pos;
- pos += ret;
- first = 0;
- }
- if (cipher & WPA_CIPHER_TKIP) {
- ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : "+");
- if (ret < 0 || ret >= end - pos)
- return pos;
- pos += ret;
- first = 0;
- }
- if (cipher & WPA_CIPHER_CCMP) {
- ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : "+");
- if (ret < 0 || ret >= end - pos)
- return pos;
- pos += ret;
- first = 0;
- }
- if (cipher & WPA_CIPHER_GCMP) {
- ret = os_snprintf(pos, end - pos, "%sGCMP", first ? "" : "+");
- if (ret < 0 || ret >= end - pos)
- return pos;
- pos += ret;
- first = 0;
- }
+ ret = wpa_write_ciphers(pos, end, cipher, "+");
+ if (ret < 0)
+ return pos;
+ pos += ret;
return pos;
}
@@ -1850,18 +2239,14 @@
{
int id;
struct wpa_ssid *ssid;
+ int was_disabled;
/* cmd: "<network id>" or "all" */
if (os_strcmp(cmd, "all") == 0) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK all");
- ssid = wpa_s->conf->ssid;
- while (ssid) {
- struct wpa_ssid *remove_ssid = ssid;
- id = ssid->id;
- ssid = ssid->next;
- wpas_notify_network_removed(wpa_s, remove_ssid);
- wpa_config_remove_network(wpa_s->conf, id);
- }
+ if (wpa_s->sched_scanning)
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+
eapol_sm_invalidate_cached_session(wpa_s->eapol);
if (wpa_s->current_ssid) {
#ifdef CONFIG_SME
@@ -1869,8 +2254,16 @@
#endif /* CONFIG_SME */
wpa_sm_set_config(wpa_s->wpa, NULL);
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
- wpa_supplicant_disassociate(wpa_s,
- WLAN_REASON_DEAUTH_LEAVING);
+ wpa_supplicant_deauthenticate(
+ wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ }
+ ssid = wpa_s->conf->ssid;
+ while (ssid) {
+ struct wpa_ssid *remove_ssid = ssid;
+ id = ssid->id;
+ ssid = ssid->next;
+ wpas_notify_network_removed(wpa_s, remove_ssid);
+ wpa_config_remove_network(wpa_s->conf, id);
}
return 0;
}
@@ -1902,15 +2295,25 @@
wpa_sm_set_config(wpa_s->wpa, NULL);
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
- wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ wpa_supplicant_deauthenticate(wpa_s,
+ WLAN_REASON_DEAUTH_LEAVING);
}
+ was_disabled = ssid->disabled;
+
if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Not able to remove the "
"network id=%d", id);
return -1;
}
+ if (!was_disabled && wpa_s->sched_scanning) {
+ 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);
+ }
+
return 0;
}
@@ -1952,7 +2355,9 @@
return -1;
}
- wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
+ if (os_strcmp(name, "bssid") != 0 &&
+ os_strcmp(name, "priority") != 0)
+ wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
if (wpa_s->current_ssid == ssid || wpa_s->current_ssid == NULL) {
/*
@@ -2069,20 +2474,62 @@
}
+static int wpas_ctrl_remove_cred(struct wpa_supplicant *wpa_s,
+ struct wpa_cred *cred)
+{
+ struct wpa_ssid *ssid;
+ char str[20];
+
+ if (cred == NULL || wpa_config_remove_cred(wpa_s->conf, cred->id) < 0) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred");
+ return -1;
+ }
+
+ /* Remove any network entry created based on the removed credential */
+ ssid = wpa_s->conf->ssid;
+ while (ssid) {
+ if (ssid->parent_cred == cred) {
+ wpa_printf(MSG_DEBUG, "Remove network id %d since it "
+ "used the removed credential", ssid->id);
+ os_snprintf(str, sizeof(str), "%d", ssid->id);
+ ssid = ssid->next;
+ wpa_supplicant_ctrl_iface_remove_network(wpa_s, str);
+ } else
+ ssid = ssid->next;
+ }
+
+ return 0;
+}
+
+
static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s,
char *cmd)
{
int id;
- struct wpa_cred *cred;
+ struct wpa_cred *cred, *prev;
- /* cmd: "<cred id>" or "all" */
+ /* cmd: "<cred id>", "all", or "sp_fqdn=<FQDN>" */
if (os_strcmp(cmd, "all") == 0) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED all");
cred = wpa_s->conf->cred;
while (cred) {
- id = cred->id;
+ prev = cred;
cred = cred->next;
- wpa_config_remove_cred(wpa_s->conf, id);
+ wpas_ctrl_remove_cred(wpa_s, prev);
+ }
+ return 0;
+ }
+
+ if (os_strncmp(cmd, "sp_fqdn=", 8) == 0) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED SP FQDN '%s'",
+ cmd + 8);
+ cred = wpa_s->conf->cred;
+ while (cred) {
+ prev = cred;
+ cred = cred->next;
+ if (prev->domain &&
+ os_strcmp(prev->domain, cmd + 8) == 0)
+ wpas_ctrl_remove_cred(wpa_s, prev);
}
return 0;
}
@@ -2091,14 +2538,7 @@
wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED id=%d", id);
cred = wpa_config_get_cred(wpa_s->conf, id);
- if (cred == NULL ||
- wpa_config_remove_cred(wpa_s->conf, id) < 0) {
- wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred id=%d",
- id);
- return -1;
- }
-
- return 0;
+ return wpas_ctrl_remove_cred(wpa_s, cred);
}
@@ -2433,6 +2873,46 @@
}
+static int ctrl_iface_get_capability_modes(int res, char *strict,
+ struct wpa_driver_capa *capa,
+ char *buf, size_t buflen)
+{
+ int ret, first = 1;
+ char *pos, *end;
+ size_t len;
+
+ pos = buf;
+ end = pos + buflen;
+
+ if (res < 0) {
+ if (strict)
+ return 0;
+ len = os_strlcpy(buf, "IBSS AP", buflen);
+ if (len >= buflen)
+ return -1;
+ return len;
+ }
+
+ if (capa->flags & WPA_DRIVER_FLAGS_IBSS) {
+ ret = os_snprintf(pos, end - pos, "%sIBSS", first ? "" : " ");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ first = 0;
+ }
+
+ if (capa->flags & WPA_DRIVER_FLAGS_AP) {
+ ret = os_snprintf(pos, end - pos, "%sAP", first ? "" : " ");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ first = 0;
+ }
+
+ return pos - buf;
+}
+
+
static int ctrl_iface_get_capability_channels(struct wpa_supplicant *wpa_s,
char *buf, size_t buflen)
{
@@ -2454,6 +2934,9 @@
case HOSTAPD_MODE_IEEE80211A:
hmode = "A";
break;
+ case HOSTAPD_MODE_IEEE80211AD:
+ hmode = "AD";
+ break;
default:
continue;
}
@@ -2530,6 +3013,10 @@
return ctrl_iface_get_capability_auth_alg(res, strict, &capa,
buf, buflen);
+ if (os_strcmp(field, "modes") == 0)
+ return ctrl_iface_get_capability_modes(res, strict, &capa,
+ buf, buflen);
+
if (os_strcmp(field, "channels") == 0)
return ctrl_iface_get_capability_channels(wpa_s, buf, buflen);
@@ -2727,7 +3214,7 @@
if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) {
ret = os_snprintf(pos, end - pos, "[HS20]");
if (ret < 0 || ret >= end - pos)
- return -1;
+ return 0;
pos += ret;
}
#endif /* CONFIG_HS20 */
@@ -2775,7 +3262,7 @@
if (wfd) {
ret = os_snprintf(pos, end - pos, "wfd_subelems=");
if (ret < 0 || ret >= end - pos)
- return pos - buf;
+ return 0;
pos += ret;
pos += wpa_snprintf_hex(pos, end - pos,
@@ -2785,7 +3272,7 @@
ret = os_snprintf(pos, end - pos, "\n");
if (ret < 0 || ret >= end - pos)
- return pos - buf;
+ return 0;
pos += ret;
}
}
@@ -2818,12 +3305,12 @@
}
#endif /* CONFIG_INTERWORKING */
-#ifdef ANDROID
- ret = os_snprintf(pos, end - pos, "====\n");
- if (ret < 0 || ret >= end - pos)
- return 0;
- pos += ret;
-#endif
+ if (mask & WPA_BSS_MASK_DELIM) {
+ ret = os_snprintf(pos, end - pos, "====\n");
+ if (ret < 0 || ret >= end - pos)
+ return 0;
+ pos += ret;
+ }
return pos - buf;
}
@@ -2858,10 +3345,17 @@
return 0;
}
- id1 = atoi(cmd + 6);
- bss = wpa_bss_get_id(wpa_s, id1);
- id2 = atoi(ctmp + 1);
- if (id2 == 0)
+ if (*(cmd + 6) == '-')
+ id1 = 0;
+ else
+ id1 = atoi(cmd + 6);
+ ctmp++;
+ if (*ctmp >= '0' && *ctmp <= '9')
+ id2 = atoi(ctmp);
+ else
+ id2 = (unsigned int) -1;
+ bss = wpa_bss_get_id_range(wpa_s, id1, id2);
+ if (id2 == (unsigned int) -1)
bsslast = dl_list_last(&wpa_s->bss_id,
struct wpa_bss,
list_id);
@@ -2883,8 +3377,10 @@
}
}
}
- } else if (os_strcmp(cmd, "FIRST") == 0)
+ } else if (os_strncmp(cmd, "FIRST", 5) == 0)
bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss, list_id);
+ else if (os_strncmp(cmd, "LAST", 4) == 0)
+ bss = dl_list_last(&wpa_s->bss_id, struct wpa_bss, list_id);
else if (os_strncmp(cmd, "ID-", 3) == 0) {
i = atoi(cmd + 3);
bss = wpa_bss_get_id(wpa_s, i);
@@ -2937,8 +3433,13 @@
ret += len;
buf += len;
buflen -= len;
- if (bss == bsslast)
+ 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");
break;
+ }
next = bss->list_id.next;
if (next == &wpa_s->bss_id)
break;
@@ -3035,7 +3536,13 @@
wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM " MACSTR, MAC2STR(bssid));
- bss = wpa_bss_get_bssid(wpa_s, bssid);
+ if (!ssid) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: No network "
+ "configuration known for the target AP");
+ return -1;
+ }
+
+ bss = wpa_bss_get(wpa_s, bssid, ssid->ssid, ssid->ssid_len);
if (!bss) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: Target AP not found "
"from BSS table");
@@ -3047,12 +3554,6 @@
* allow roaming to other networks
*/
- if (!ssid) {
- wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: No network "
- "configuration known for the target AP");
- return -1;
- }
-
wpa_s->reassociate = 1;
wpa_supplicant_connect(wpa_s, bss, ssid);
@@ -3144,7 +3645,7 @@
auth = os_strstr(pos, " auth") != NULL;
automatic = os_strstr(pos, " auto") != NULL;
pd = os_strstr(pos, " provdisc") != NULL;
- ht40 = os_strstr(pos, " ht40") != NULL;
+ ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
pos2 = os_strstr(pos, " go_intent=");
if (pos2) {
@@ -3548,7 +4049,7 @@
int id;
struct wpa_ssid *ssid;
u8 *_peer = NULL, peer[ETH_ALEN];
- int freq = 0;
+ int freq = 0, pref_freq = 0;
int ht40;
id = atoi(cmd);
@@ -3575,9 +4076,17 @@
return -1;
}
- ht40 = os_strstr(cmd, " ht40") != NULL;
+ pos = os_strstr(cmd, " pref=");
+ if (pos) {
+ pos += 6;
+ pref_freq = atoi(pos);
+ if (pref_freq <= 0)
+ return -1;
+ }
- return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, ht40);
+ ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
+
+ return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, ht40, pref_freq);
}
@@ -3638,7 +4147,7 @@
return -1;
}
- return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, ht40);
+ return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, ht40, NULL);
}
@@ -3651,7 +4160,7 @@
if (pos)
freq = atoi(pos + 5);
- ht40 = os_strstr(cmd, "ht40") != NULL;
+ ht40 = (os_strstr(cmd, "ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
if (os_strncmp(cmd, "persistent=", 11) == 0)
return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq,
@@ -3679,6 +4188,7 @@
char *pos, *end;
char devtype[WPS_DEV_TYPE_BUFSIZE];
struct wpa_ssid *ssid;
+ size_t i;
if (!wpa_s->global->p2p)
return -1;
@@ -3732,6 +4242,18 @@
return pos - buf;
pos += res;
+ for (i = 0; i < info->wps_sec_dev_type_list_len / WPS_DEV_TYPE_LEN; i++)
+ {
+ const u8 *t;
+ t = &info->wps_sec_dev_type_list[i * WPS_DEV_TYPE_LEN];
+ 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)
+ return pos - buf;
+ pos += res;
+ }
+
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);
@@ -3960,6 +4482,30 @@
if (os_strcmp(cmd, "disallow_freq") == 0)
return p2p_ctrl_disallow_freq(wpa_s, param);
+ if (os_strcmp(cmd, "disc_int") == 0) {
+ int min_disc_int, max_disc_int, max_disc_tu;
+ char *pos;
+
+ pos = param;
+
+ min_disc_int = atoi(pos);
+ pos = os_strchr(pos, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ max_disc_int = atoi(pos);
+ pos = os_strchr(pos, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ max_disc_tu = atoi(pos);
+
+ return p2p_set_disc_int(wpa_s->global->p2p, min_disc_int,
+ max_disc_int, max_disc_tu);
+ }
+
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'",
cmd);
@@ -3967,6 +4513,15 @@
}
+static void p2p_ctrl_flush(struct wpa_supplicant *wpa_s)
+{
+ os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
+ wpa_s->force_long_sd = 0;
+ if (wpa_s->global->p2p)
+ p2p_flush(wpa_s->global->p2p);
+}
+
+
static int p2p_ctrl_presence_req(struct wpa_supplicant *wpa_s, char *cmd)
{
char *pos, *pos2;
@@ -4331,6 +4886,60 @@
#endif /* CONFIG_AUTOSCAN */
+#ifdef CONFIG_WNM
+
+static int wpas_ctrl_iface_wnm_sleep(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ int enter;
+ int intval = 0;
+ char *pos;
+ int ret;
+ struct wpabuf *tfs_req = NULL;
+
+ if (os_strncmp(cmd, "enter", 5) == 0)
+ enter = 1;
+ else if (os_strncmp(cmd, "exit", 4) == 0)
+ enter = 0;
+ else
+ return -1;
+
+ pos = os_strstr(cmd, " interval=");
+ if (pos)
+ intval = atoi(pos + 10);
+
+ pos = os_strstr(cmd, " tfs_req=");
+ if (pos) {
+ char *end;
+ size_t len;
+ pos += 9;
+ end = os_strchr(pos, ' ');
+ if (end)
+ len = end - pos;
+ else
+ len = os_strlen(pos);
+ if (len & 1)
+ return -1;
+ len /= 2;
+ tfs_req = wpabuf_alloc(len);
+ if (tfs_req == NULL)
+ return -1;
+ if (hexstr2bin(pos, wpabuf_put(tfs_req, len), len) < 0) {
+ wpabuf_free(tfs_req);
+ return -1;
+ }
+ }
+
+ ret = ieee802_11_send_wnmsleep_req(wpa_s, enter ? WNM_SLEEP_MODE_ENTER :
+ WNM_SLEEP_MODE_EXIT, intval,
+ tfs_req);
+ wpabuf_free(tfs_req);
+
+ return ret;
+}
+
+#endif /* CONFIG_WNM */
+
+
static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf,
size_t buflen)
{
@@ -4383,6 +4992,54 @@
#endif
+static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
+{
+ wpa_dbg(wpa_s, MSG_DEBUG, "Flush all wpa_supplicant state");
+
+#ifdef CONFIG_P2P
+ wpas_p2p_stop_find(wpa_s);
+ p2p_ctrl_flush(wpa_s);
+ wpas_p2p_group_remove(wpa_s, "*");
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_WPS_TESTING
+ wps_version_number = 0x20;
+ wps_testing_dummy_cred = 0;
+#endif /* CONFIG_WPS_TESTING */
+#ifdef CONFIG_WPS
+ wpas_wps_cancel(wpa_s);
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_TDLS_TESTING
+ extern unsigned int tdls_testing;
+ tdls_testing = 0;
+#endif /* CONFIG_TDLS_TESTING */
+#ifdef CONFIG_TDLS
+ wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL);
+ wpa_tdls_enable(wpa_s->wpa, 1);
+#endif /* CONFIG_TDLS */
+
+ wpa_s->no_keep_alive = 0;
+
+ os_free(wpa_s->disallow_aps_bssid);
+ wpa_s->disallow_aps_bssid = NULL;
+ wpa_s->disallow_aps_bssid_count = 0;
+ os_free(wpa_s->disallow_aps_ssid);
+ wpa_s->disallow_aps_ssid = NULL;
+ wpa_s->disallow_aps_ssid_count = 0;
+
+ wpa_s->set_sta_uapsd = 0;
+ wpa_s->sta_uapsd = 0;
+
+ wpa_drv_radio_disable(wpa_s, 0);
+
+ wpa_bss_flush(wpa_s);
+ wpa_blacklist_clear(wpa_s);
+ wpa_supplicant_ctrl_iface_remove_network(wpa_s, "all");
+ wpa_supplicant_ctrl_iface_remove_cred(wpa_s, "all");
+}
+
+
char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
char *buf, size_t *resp_len)
{
@@ -4392,7 +5049,10 @@
int reply_len;
if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
- os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
+ os_strncmp(buf, "SET_NETWORK ", 12) == 0 ||
+ os_strncmp(buf, "WPS_NFC_TAG_READ", 16) == 0 ||
+ os_strncmp(buf, "NFC_REPORT_HANDOVER", 19) == 0 ||
+ os_strncmp(buf, "NFC_RX_HANDOVER_SEL", 19) == 0) {
wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
(const u8 *) buf, os_strlen(buf));
} else {
@@ -4452,25 +5112,15 @@
} else if (os_strcmp(buf, "LOGOFF") == 0) {
eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
} else if (os_strcmp(buf, "REASSOCIATE") == 0) {
- wpa_s->normal_scans = 0;
- wpa_supplicant_reinit_autoscan(wpa_s);
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
reply_len = -1;
- else {
- wpa_s->disconnected = 0;
- wpa_s->reassociate = 1;
- wpa_supplicant_req_scan(wpa_s, 0, 0);
- }
+ else
+ wpas_request_connection(wpa_s);
} else if (os_strcmp(buf, "RECONNECT") == 0) {
- wpa_s->normal_scans = 0;
- wpa_supplicant_reinit_autoscan(wpa_s);
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
reply_len = -1;
- else if (wpa_s->disconnected) {
- wpa_s->disconnected = 0;
- wpa_s->reassociate = 1;
- wpa_supplicant_req_scan(wpa_s, 0, 0);
- }
+ else if (wpa_s->disconnected)
+ wpas_request_connection(wpa_s);
#ifdef IEEE8021X_EAPOL
} else if (os_strncmp(buf, "PREAUTH ", 8) == 0) {
if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
@@ -4511,11 +5161,6 @@
} else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
if (wpas_wps_cancel(wpa_s))
reply_len = -1;
-#ifdef CONFIG_WPS_OOB
- } else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) {
- if (wpa_supplicant_ctrl_iface_wps_oob(wpa_s, buf + 8))
- reply_len = -1;
-#endif /* CONFIG_WPS_OOB */
#ifdef CONFIG_WPS_NFC
} else if (os_strcmp(buf, "WPS_NFC") == 0) {
if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, NULL))
@@ -4523,6 +5168,9 @@
} else if (os_strncmp(buf, "WPS_NFC ", 8) == 0) {
if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, buf + 8))
reply_len = -1;
+ } else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) {
+ reply_len = wpa_supplicant_ctrl_iface_wps_nfc_config_token(
+ wpa_s, buf + 21, reply, reply_size);
} else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
reply_len = wpa_supplicant_ctrl_iface_wps_nfc_token(
wpa_s, buf + 14, reply, reply_size);
@@ -4530,6 +5178,21 @@
if (wpa_supplicant_ctrl_iface_wps_nfc_tag_read(wpa_s,
buf + 17))
reply_len = -1;
+ } else if (os_strncmp(buf, "NFC_GET_HANDOVER_REQ ", 21) == 0) {
+ reply_len = wpas_ctrl_nfc_get_handover_req(
+ wpa_s, buf + 21, reply, reply_size);
+ } else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
+ reply_len = wpas_ctrl_nfc_get_handover_sel(
+ wpa_s, buf + 21, reply, reply_size);
+ } else if (os_strncmp(buf, "NFC_RX_HANDOVER_REQ ", 20) == 0) {
+ reply_len = wpas_ctrl_nfc_rx_handover_req(
+ wpa_s, buf + 20, reply, reply_size);
+ } else if (os_strncmp(buf, "NFC_RX_HANDOVER_SEL ", 20) == 0) {
+ if (wpas_ctrl_nfc_rx_handover_sel(wpa_s, buf + 20))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) {
+ if (wpas_ctrl_nfc_report_handover(wpa_s, buf + 20))
+ reply_len = -1;
#endif /* CONFIG_WPS_NFC */
} else if (os_strncmp(buf, "WPS_REG ", 8) == 0) {
if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8))
@@ -4658,10 +5321,7 @@
if (p2p_ctrl_set(wpa_s, buf + 8) < 0)
reply_len = -1;
} else if (os_strcmp(buf, "P2P_FLUSH") == 0) {
- os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
- wpa_s->force_long_sd = 0;
- if (wpa_s->global->p2p)
- p2p_flush(wpa_s->global->p2p);
+ p2p_ctrl_flush(wpa_s);
} else if (os_strncmp(buf, "P2P_UNAUTHORIZE ", 16) == 0) {
if (wpas_p2p_unauthorize(wpa_s, buf + 16) < 0)
reply_len = -1;
@@ -4754,22 +5414,26 @@
wpa_supplicant_cancel_scan(wpa_s);
wpa_supplicant_deauthenticate(wpa_s,
WLAN_REASON_DEAUTH_LEAVING);
- } else if (os_strcmp(buf, "SCAN") == 0) {
+ } else if (os_strcmp(buf, "SCAN") == 0 ||
+ os_strncmp(buf, "SCAN ", 5) == 0) {
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
reply_len = -1;
else {
- if (!wpa_s->scanning &&
+ if (os_strlen(buf) > 4 &&
+ os_strncasecmp(buf + 5, "TYPE=ONLY", 9) == 0)
+ wpa_s->scan_res_handler = scan_only_handler;
+ if (!wpa_s->sched_scanning && !wpa_s->scanning &&
((wpa_s->wpa_state <= WPA_SCANNING) ||
(wpa_s->wpa_state == WPA_COMPLETED))) {
wpa_s->normal_scans = 0;
- wpa_s->scan_req = 2;
+ wpa_s->scan_req = MANUAL_SCAN_REQ;
wpa_supplicant_req_scan(wpa_s, 0, 0);
} else if (wpa_s->sched_scanning) {
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 = 2;
+ wpa_s->scan_req = MANUAL_SCAN_REQ;
wpa_supplicant_req_scan(wpa_s, 0, 0);
} else {
wpa_printf(MSG_DEBUG, "Ongoing scan action - "
@@ -4903,7 +5567,15 @@
reply_size);
#endif
} else if (os_strcmp(buf, "REAUTHENTICATE") == 0) {
+ pmksa_cache_clear_current(wpa_s->wpa);
eapol_sm_request_reauth(wpa_s->eapol);
+#ifdef CONFIG_WNM
+ } else if (os_strncmp(buf, "WNM_SLEEP ", 10) == 0) {
+ if (wpas_ctrl_iface_wnm_sleep(wpa_s, buf + 10))
+ reply_len = -1;
+#endif /* CONFIG_WNM */
+ } else if (os_strcmp(buf, "FLUSH") == 0) {
+ wpa_supplicant_ctrl_iface_flush(wpa_s);
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c
index 80db27e..4dfabc8 100644
--- a/wpa_supplicant/ctrl_iface_unix.c
+++ b/wpa_supplicant/ctrl_iface_unix.c
@@ -329,6 +329,22 @@
}
}
+#ifdef ANDROID
+ /*
+ * wpa_supplicant is started from /init.*.rc on Android and that seems
+ * to be using umask 0077 which would leave the control interface
+ * directory without group access. This breaks things since Wi-Fi
+ * framework assumes that this directory can be accessed by other
+ * applications in the wifi group. Fix this by adding group access even
+ * if umask value would prevent this.
+ */
+ if (chmod(dir, S_IRWXU | S_IRWXG) < 0) {
+ wpa_printf(MSG_ERROR, "CTRL: Could not chmod directory: %s",
+ strerror(errno));
+ /* Try to continue anyway */
+ }
+#endif /* ANDROID */
+
if (gid_str) {
grp = getgrnam(gid_str);
if (grp) {
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index 4eeb93a..136dd1a 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -1808,6 +1808,9 @@
case WPAS_DBUS_BSS_PROP_RSN:
prop = "RSN";
break;
+ case WPAS_DBUS_BSS_PROP_WPS:
+ prop = "WPS";
+ break;
case WPAS_DBUS_BSS_PROP_IES:
prop = "IEs";
break;
@@ -1950,6 +1953,10 @@
wpas_dbus_getter_eap_methods,
NULL
},
+ { "Capabilities", WPAS_DBUS_NEW_INTERFACE, "as",
+ wpas_dbus_getter_global_capabilities,
+ NULL
+ },
{ NULL, NULL, NULL, NULL, NULL }
};
@@ -2232,6 +2239,10 @@
wpas_dbus_getter_bss_rsn,
NULL
},
+ { "WPS", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
+ wpas_dbus_getter_bss_wps,
+ NULL
+ },
{ "IEs", WPAS_DBUS_NEW_IFACE_BSS, "ay",
wpas_dbus_getter_bss_ies,
NULL
@@ -2419,6 +2430,7 @@
END_ARGS
}
},
+#ifndef CONFIG_NO_CONFIG_BLOBS
{ "AddBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
(WPADBusMethodHandler) &wpas_dbus_handler_add_blob,
{
@@ -2442,6 +2454,7 @@
END_ARGS
}
},
+#endif /* CONFIG_NO_CONFIG_BLOBS */
#ifdef CONFIG_WPS
{ "Start", WPAS_DBUS_NEW_IFACE_WPS,
(WPADBusMethodHandler) &wpas_dbus_handler_wps_start,
diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h
index 44cde42..363a7e5 100644
--- a/wpa_supplicant/dbus/dbus_new.h
+++ b/wpa_supplicant/dbus/dbus_new.h
@@ -39,6 +39,7 @@
WPAS_DBUS_BSS_PROP_RATES,
WPAS_DBUS_BSS_PROP_WPA,
WPAS_DBUS_BSS_PROP_RSN,
+ WPAS_DBUS_BSS_PROP_WPS,
WPAS_DBUS_BSS_PROP_IES,
};
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 5668e1a..335c25f 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -21,7 +21,6 @@
#include "../notify.h"
#include "../bss.h"
#include "../scan.h"
-#include "../ctrl_iface.h"
#include "../autoscan.h"
#include "dbus_new_helpers.h"
#include "dbus_new.h"
@@ -124,7 +123,7 @@
static const char *dont_quote[] = {
"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
"opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
- "bssid", NULL
+ "bssid", "scan_freq", "freq_list", NULL
};
static dbus_bool_t should_quote_opt(const char *key)
@@ -924,6 +923,44 @@
}
+/**
+ * wpas_dbus_getter_global_capabilities - Request supported global capabilities
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "Capabilities" property. Handles requests by dbus clients to
+ * return a list of strings with supported capabilities like AP, RSN IBSS,
+ * and P2P that are determined at compile time.
+ */
+dbus_bool_t wpas_dbus_getter_global_capabilities(DBusMessageIter *iter,
+ DBusError *error,
+ void *user_data)
+{
+ const char *capabilities[5] = { NULL, NULL, NULL, NULL, NULL };
+ size_t num_items = 0;
+
+#ifdef CONFIG_AP
+ capabilities[num_items++] = "ap";
+#endif /* CONFIG_AP */
+#ifdef CONFIG_IBSS_RSN
+ capabilities[num_items++] = "ibss-rsn";
+#endif /* CONFIG_IBSS_RSN */
+#ifdef CONFIG_P2P
+ capabilities[num_items++] = "p2p";
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_INTERWORKING
+ capabilities[num_items++] = "interworking";
+#endif /* CONFIG_INTERWORKING */
+
+ return wpas_dbus_simple_array_property_getter(iter,
+ DBUS_TYPE_STRING,
+ capabilities,
+ num_items, error);
+}
+
+
static int wpas_dbus_get_scan_type(DBusMessage *message, DBusMessageIter *var,
char **type, DBusMessage **reply)
{
@@ -1275,7 +1312,7 @@
} else if (params.freqs && params.freqs[0]) {
wpa_supplicant_trigger_scan(wpa_s, ¶ms);
} else {
- wpa_s->scan_req = 2;
+ wpa_s->scan_req = MANUAL_SCAN_REQ;
wpa_supplicant_req_scan(wpa_s, 0, 0);
}
} else if (!os_strcmp(type, "active")) {
@@ -1417,12 +1454,7 @@
struct wpa_supplicant *wpa_s)
{
if (wpa_s->current_ssid != NULL) {
- wpa_s->normal_scans = 0;
- wpa_supplicant_reinit_autoscan(wpa_s);
- wpa_s->disconnected = 0;
- wpa_s->reassociate = 1;
- wpa_supplicant_req_scan(wpa_s, 0, 0);
-
+ wpas_request_connection(wpa_s);
return NULL;
}
@@ -1447,6 +1479,7 @@
char *iface = NULL, *net_id = NULL;
int id;
struct wpa_ssid *ssid;
+ int was_disabled;
dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
DBUS_TYPE_INVALID);
@@ -1454,13 +1487,15 @@
/* 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);
- if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+ if (iface == NULL || net_id == NULL ||
+ os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
reply = wpas_dbus_error_invalid_args(message, op);
goto out;
}
+ errno = 0;
id = strtoul(net_id, NULL, 10);
- if (errno == EINVAL) {
+ if (errno != 0) {
reply = wpas_dbus_error_invalid_args(message, op);
goto out;
}
@@ -1471,6 +1506,8 @@
goto out;
}
+ was_disabled = ssid->disabled;
+
wpas_notify_network_removed(wpa_s, ssid);
if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
@@ -1486,6 +1523,13 @@
if (ssid == wpa_s->current_ssid)
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_supplicant_cancel_sched_scan(wpa_s);
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ }
+
out:
os_free(iface);
@@ -1509,7 +1553,8 @@
}
if (ssid == wpa_s->current_ssid)
- wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ wpa_supplicant_deauthenticate(wpa_s,
+ WLAN_REASON_DEAUTH_LEAVING);
}
@@ -1524,6 +1569,9 @@
DBusMessage * wpas_dbus_handler_remove_all_networks(
DBusMessage *message, struct wpa_supplicant *wpa_s)
{
+ if (wpa_s->sched_scanning)
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+
/* NB: could check for failure and return an error */
wpa_config_foreach_network(wpa_s->conf, remove_network, wpa_s);
return NULL;
@@ -1553,13 +1601,15 @@
/* 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);
- if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+ if (iface == NULL || net_id == NULL ||
+ os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
reply = wpas_dbus_error_invalid_args(message, op);
goto out;
}
+ errno = 0;
id = strtoul(net_id, NULL, 10);
- if (errno == EINVAL) {
+ if (errno != 0) {
reply = wpas_dbus_error_invalid_args(message, op);
goto out;
}
@@ -1608,13 +1658,15 @@
/* 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);
- if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+ if (iface == NULL || net_id == NULL ||
+ os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
reply = wpas_dbus_error_invalid_args(message, op);
goto out;
}
+ errno = 0;
id = strtoul(net_id, NULL, 10);
- if (errno == EINVAL) {
+ if (errno != 0) {
reply = wpas_dbus_error_invalid_args(message, net_id);
goto out;
}
@@ -1644,6 +1696,8 @@
}
+#ifndef CONFIG_NO_CONFIG_BLOBS
+
/**
* wpas_dbus_handler_add_blob - Store named binary blob (ie, for certificates)
* @message: Pointer to incoming dbus message
@@ -1808,6 +1862,9 @@
}
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+
+
/*
* wpas_dbus_handler_flush_bss - Flush the BSS cache
* @message: Pointer to incoming dbus message
@@ -3366,6 +3423,63 @@
/**
+ * wpas_dbus_getter_bss_wps - Return the WPS options of a BSS
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "WPS" property.
+ */
+dbus_bool_t wpas_dbus_getter_bss_wps(DBusMessageIter *iter, DBusError *error,
+ void *user_data)
+{
+ struct bss_handler_args *args = user_data;
+ struct wpa_bss *res;
+#ifdef CONFIG_WPS
+ struct wpabuf *wps_ie;
+#endif /* CONFIG_WPS */
+ DBusMessageIter iter_dict, variant_iter;
+ const char *type = "";
+
+ res = get_bss_helper(args, error, __func__);
+ if (!res)
+ 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))
+ goto nomem;
+
+#ifdef CONFIG_WPS
+ wps_ie = wpa_bss_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE);
+ if (wps_ie) {
+ if (wps_is_selected_pbc_registrar(wps_ie))
+ type = "pbc";
+ else if (wps_is_selected_pin_registrar(wps_ie))
+ type = "pin";
+ }
+#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))
+ goto nomem;
+
+ return TRUE;
+
+nomem:
+ dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+ return FALSE;
+}
+
+
+/**
* wpas_dbus_getter_bss_ies - Return all IEs of a BSS
* @iter: Pointer to incoming dbus message iter
* @error: Location to store error on failure
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index 178a76b..aa56550 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -80,6 +80,10 @@
dbus_bool_t wpas_dbus_getter_eap_methods(DBusMessageIter *iter,
DBusError *error, void *user_data);
+dbus_bool_t wpas_dbus_getter_global_capabilities(DBusMessageIter *iter,
+ DBusError *error,
+ void *user_data);
+
DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
struct wpa_supplicant *wpa_s);
@@ -238,6 +242,9 @@
dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error,
void *user_data);
+dbus_bool_t wpas_dbus_getter_bss_wps(DBusMessageIter *iter, DBusError *error,
+ void *user_data);
+
dbus_bool_t wpas_dbus_getter_bss_ies(DBusMessageIter *iter, DBusError *error,
void *user_data);
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index 30e0eb3..6ec96df 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -346,7 +346,8 @@
if (ssid == NULL || ssid->disabled != 2)
goto inv_args;
- if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0)) {
+ if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0,
+ NULL)) {
reply = wpas_dbus_error_unknown_error(
message,
"Failed to reinvoke a persistent group");
@@ -630,7 +631,8 @@
if (ssid == NULL || ssid->disabled != 2)
goto err;
- if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0) < 0) {
+ if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0, 0) < 0)
+ {
reply = wpas_dbus_error_unknown_error(
message,
"Failed to reinvoke a persistent group");
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_wps.c b/wpa_supplicant/dbus/dbus_new_handlers_wps.c
index 8489ce7..4ad5e7e 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_wps.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_wps.c
@@ -273,7 +273,7 @@
ret = wpa_supplicant_ap_wps_pin(wpa_s,
params.bssid,
params.pin,
- npin, sizeof(npin));
+ npin, sizeof(npin), 0);
else
#endif /* CONFIG_AP */
{
diff --git a/wpa_supplicant/dbus/dbus_old.c b/wpa_supplicant/dbus/dbus_old.c
index 5f298e7..85d8a78 100644
--- a/wpa_supplicant/dbus/dbus_old.c
+++ b/wpa_supplicant/dbus/dbus_old.c
@@ -268,10 +268,12 @@
reply = wpas_dbus_iface_get_state(message, wpa_s);
else if (!strcmp(method, "scanning"))
reply = wpas_dbus_iface_get_scanning(message, wpa_s);
+#ifndef CONFIG_NO_CONFIG_BLOBS
else if (!strcmp(method, "setBlobs"))
reply = wpas_dbus_iface_set_blobs(message, wpa_s);
else if (!strcmp(method, "removeBlobs"))
reply = wpas_dbus_iface_remove_blobs(message, wpa_s);
+#endif /* CONFIG_NO_CONFIG_BLOBS */
#ifdef CONFIG_WPS
else if (!os_strcmp(method, "wpsPbc"))
reply = wpas_dbus_iface_wps_pbc(message, wpa_s);
diff --git a/wpa_supplicant/dbus/dbus_old_handlers.c b/wpa_supplicant/dbus/dbus_old_handlers.c
index e217a72..e565de9 100644
--- a/wpa_supplicant/dbus/dbus_old_handlers.c
+++ b/wpa_supplicant/dbus/dbus_old_handlers.c
@@ -331,7 +331,7 @@
DBusMessage * wpas_dbus_iface_scan(DBusMessage *message,
struct wpa_supplicant *wpa_s)
{
- wpa_s->scan_req = 2;
+ wpa_s->scan_req = MANUAL_SCAN_REQ;
wpa_supplicant_req_scan(wpa_s, 0, 0);
return wpas_dbus_new_success_reply(message);
}
@@ -1300,6 +1300,8 @@
}
+#ifndef CONFIG_NO_CONFIG_BLOBS
+
/**
* wpas_dbus_iface_set_blobs - Store named binary blobs (ie, for certificates)
* @message: Pointer to incoming dbus message
@@ -1429,6 +1431,8 @@
return wpas_dbus_new_success_reply(message);
}
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+
/**
* wpas_dbus_iface_flush - Clear BSS of old or all inactive entries
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index 711b407..e867bae 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -225,6 +225,9 @@
# Support HT overrides (disable HT/HT40, mask MCS rates, etc.)
#CONFIG_HT_OVERRIDES=y
+# Support VHT overrides (disable VHT, mask MCS rates, etc.)
+#CONFIG_VHT_OVERRIDES=y
+
# Development testing
#CONFIG_EAPOL_TEST=y
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index bc148ca..6bab19c 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -139,16 +139,6 @@
return -1;
}
-static inline int wpa_drv_disassociate(struct wpa_supplicant *wpa_s,
- const u8 *addr, int reason_code)
-{
- if (wpa_s->driver->disassociate) {
- return wpa_s->driver->disassociate(wpa_s->drv_priv, addr,
- reason_code);
- }
- return -1;
-}
-
static inline int wpa_drv_add_pmkid(struct wpa_supplicant *wpa_s,
const u8 *bssid, const u8 *pmkid)
{
diff --git a/wpa_supplicant/eap_proxy_dummy.mk b/wpa_supplicant/eap_proxy_dummy.mk
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/wpa_supplicant/eap_proxy_dummy.mk
diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c
index 03b8c7e..dad2765 100644
--- a/wpa_supplicant/eapol_test.c
+++ b/wpa_supplicant/eapol_test.c
@@ -21,7 +21,6 @@
#include "eloop.h"
#include "utils/base64.h"
#include "rsn_supp/wpa.h"
-#include "eap_peer/eap_i.h"
#include "wpa_supplicant_i.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
@@ -98,7 +97,7 @@
size_t len;
char *pos;
u32 val;
- char buf[128];
+ char buf[RADIUS_MAX_ATTR_LEN + 1];
switch (attr->syntax) {
case 's':
@@ -114,7 +113,7 @@
if (pos[0] == '0' && pos[1] == 'x')
pos += 2;
len = os_strlen(pos);
- if ((len & 1) || (len / 2) > sizeof(buf)) {
+ if ((len & 1) || (len / 2) > RADIUS_MAX_ATTR_LEN) {
printf("Invalid extra attribute hexstring\n");
return -1;
}
@@ -171,7 +170,7 @@
const u8 *eap, size_t len)
{
struct radius_msg *msg;
- char buf[128];
+ char buf[RADIUS_MAX_ATTR_LEN + 1];
const struct eap_hdr *hdr;
const u8 *pos;
@@ -1173,7 +1172,7 @@
wait_for_monitor++;
break;
case 'N':
- p1 = os_zalloc(sizeof(p1));
+ p1 = os_zalloc(sizeof(*p1));
if (p1 == NULL)
break;
if (!p)
@@ -1233,7 +1232,7 @@
os_memset(&wpa_s, 0, sizeof(wpa_s));
eapol_test.wpa_s = &wpa_s;
- wpa_s.conf = wpa_config_read(conf);
+ wpa_s.conf = wpa_config_read(conf, NULL);
if (wpa_s.conf == NULL) {
printf("Failed to parse configuration file '%s'.\n", conf);
return -1;
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 4b1d992..6c0a246 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -44,6 +44,9 @@
#include "interworking.h"
+static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s);
+
+
static int wpas_temp_disabled(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
@@ -84,6 +87,12 @@
return -1;
}
+ if (disallowed_bssid(wpa_s, wpa_s->bssid) ||
+ disallowed_ssid(wpa_s, ssid->ssid, ssid->ssid_len)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Selected BSS is disallowed");
+ return -1;
+ }
+
res = wpas_temp_disabled(wpa_s, ssid);
if (res > 0) {
wpa_dbg(wpa_s, MSG_DEBUG, "Selected network is temporarily "
@@ -96,8 +105,9 @@
if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
u8 wpa_ie[80];
size_t wpa_ie_len = sizeof(wpa_ie);
- wpa_supplicant_set_suites(wpa_s, NULL, ssid,
- wpa_ie, &wpa_ie_len);
+ if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
+ wpa_ie, &wpa_ie_len) < 0)
+ wpa_dbg(wpa_s, MSG_DEBUG, "Could not set WPA suites");
} else {
wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
}
@@ -423,7 +433,9 @@
#ifdef CONFIG_IEEE80211W
if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
- ssid->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) {
+ (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+ wpa_s->conf->pmf : ssid->ieee80211w) ==
+ MGMT_FRAME_PROTECTION_REQUIRED) {
wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - no mgmt "
"frame protection");
break;
@@ -627,6 +639,28 @@
}
+static int bss_is_dmg(struct wpa_bss *bss)
+{
+ return bss->freq > 45000;
+}
+
+
+/*
+ * Test whether BSS is in an ESS.
+ * This is done differently in DMG (60 GHz) and non-DMG bands
+ */
+static int bss_is_ess(struct wpa_bss *bss)
+{
+ if (bss_is_dmg(bss)) {
+ return (bss->caps & IEEE80211_CAP_DMG_MASK) ==
+ IEEE80211_CAP_DMG_AP;
+ }
+
+ return ((bss->caps & (IEEE80211_CAP_ESS | IEEE80211_CAP_IBSS)) ==
+ IEEE80211_CAP_ESS);
+}
+
+
static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
int i, struct wpa_bss *bss,
struct wpa_ssid *group)
@@ -675,6 +709,16 @@
return NULL;
}
+ if (disallowed_bssid(wpa_s, bss->bssid)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - BSSID disallowed");
+ return NULL;
+ }
+
+ if (disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID disallowed");
+ return NULL;
+ }
+
wpa = wpa_ie_len > 0 || rsn_ie_len > 0;
for (ssid = group; ssid; ssid = ssid->pnext) {
@@ -750,9 +794,8 @@
continue;
}
- if (bss->caps & IEEE80211_CAP_IBSS) {
- wpa_dbg(wpa_s, MSG_DEBUG, " skip - IBSS (adhoc) "
- "network");
+ if (!bss_is_ess(bss)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - not ESS network");
continue;
}
@@ -811,9 +854,8 @@
}
-static struct wpa_bss *
-wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
- struct wpa_ssid **selected_ssid)
+struct wpa_bss * wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid **selected_ssid)
{
struct wpa_bss *selected = NULL;
int prio;
@@ -862,6 +904,8 @@
#endif /* CONFIG_P2P */
return;
}
+
+ wpa_s->scan_for_connection = 1;
wpa_supplicant_req_scan(wpa_s, timeout_sec, timeout_usec);
}
@@ -1012,6 +1056,12 @@
return 1;
}
+ if (current_bss->level < 0 && current_bss->level > selected->level) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - Current BSS has better "
+ "signal level");
+ return 0;
+ }
+
min_diff = 2;
if (current_bss->level < 0) {
if (current_bss->level < -85)
@@ -1040,13 +1090,9 @@
/* Return != 0 if no scan results could be fetched or if scan results should not
* be shared with other virtual interfaces. */
-#ifdef ANDROID_P2P
static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
- union wpa_event_data *data, int suppress_event)
-#else
-static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
- union wpa_event_data *data)
-#endif
+ union wpa_event_data *data,
+ int own_request)
{
struct wpa_scan_results *scan_res;
int ap = 0;
@@ -1062,7 +1108,7 @@
wpa_supplicant_notify_scanning(wpa_s, 0);
#ifdef CONFIG_P2P
- if (wpa_s->global->p2p_cb_on_scan_complete &&
+ if (own_request && wpa_s->global->p2p_cb_on_scan_complete &&
!wpa_s->global->p2p_disabled &&
wpa_s->global->p2p != NULL && !wpa_s->sta_scan_pending &&
!wpa_s->scan_res_handler) {
@@ -1082,7 +1128,10 @@
data ? &data->scan_info :
NULL, 1);
if (scan_res == NULL) {
- if (wpa_s->conf->ap_scan == 2 || ap)
+ if (wpa_s->conf->ap_scan == 2 || ap ||
+ wpa_s->scan_res_handler == scan_only_handler)
+ return -1;
+ if (!own_request)
return -1;
wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results - try "
"scanning again");
@@ -1106,7 +1155,7 @@
}
#endif /* CONFIG_NO_RANDOM_POOL */
- if (wpa_s->scan_res_handler) {
+ if (own_request && wpa_s->scan_res_handler) {
void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res);
@@ -1127,18 +1176,10 @@
wpa_scan_results_free(scan_res);
return 0;
}
-#ifdef ANDROID_P2P
- if(!suppress_event)
- {
- wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available");
- wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS);
- wpas_notify_scan_results(wpa_s);
- }
-#else
+
wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available");
wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS);
wpas_notify_scan_results(wpa_s);
-#endif
wpas_notify_scan_done(wpa_s, 1);
@@ -1177,7 +1218,7 @@
}
-int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s)
+static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s)
{
struct wpa_bss *selected;
struct wpa_ssid *ssid = NULL;
@@ -1255,11 +1296,8 @@
{
const char *rn, *rn2;
struct wpa_supplicant *ifs;
-#ifdef ANDROID_P2P
- if (_wpa_supplicant_event_scan_results(wpa_s, data, 0) != 0) {
-#else
- if (_wpa_supplicant_event_scan_results(wpa_s, data) != 0) {
-#endif
+
+ if (_wpa_supplicant_event_scan_results(wpa_s, data, 1) != 0) {
/*
* If no scan results could be fetched, then no need to
* notify those interfaces that did not actually request
@@ -1292,27 +1330,7 @@
if (rn2 && os_strcmp(rn, rn2) == 0) {
wpa_printf(MSG_DEBUG, "%s: Updating scan results from "
"sibling", ifs->ifname);
-#ifdef ANDROID_P2P
- if ( (ifs->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE) || (ifs->p2p_group_interface != NOT_P2P_GROUP_INTERFACE)) {
- /* Do not update the scan results from STA interface to p2p interfaces */
- wpa_printf(MSG_DEBUG, "Not Updating scan results on interface %s from "
- "sibling %s", ifs->ifname, wpa_s->ifname);
- continue;
- }
- else {
- /* P2P_FIND will result in too many SCAN_RESULT_EVENTS within
- * no time. Avoid announcing it to application as it may not
- * be that useful (since results will be that of only 1,6,11).
- * over to any other interface as it
- */
- if(p2p_search_in_progress(wpa_s->global->p2p))
- _wpa_supplicant_event_scan_results(ifs, data, 1);
- else
- _wpa_supplicant_event_scan_results(ifs, data, 0);
- }
-#else
- _wpa_supplicant_event_scan_results(ifs, data);
-#endif
+ _wpa_supplicant_event_scan_results(ifs, data, 0);
}
}
}
@@ -1320,6 +1338,26 @@
#endif /* CONFIG_NO_SCAN_PROCESSING */
+int wpa_supplicant_fast_associate(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_NO_SCAN_PROCESSING
+ return -1;
+#else /* CONFIG_NO_SCAN_PROCESSING */
+ struct os_time now;
+
+ if (wpa_s->last_scan_res_used <= 0)
+ return -1;
+
+ os_get_time(&now);
+ if (now.sec - wpa_s->last_scan.sec > 5) {
+ wpa_printf(MSG_DEBUG, "Fast associate: Old scan results");
+ return -1;
+ }
+
+ return wpas_select_network_from_last_scan(wpa_s);
+#endif /* CONFIG_NO_SCAN_PROCESSING */
+}
+
#ifdef CONFIG_WNM
static void wnm_bss_keep_alive(void *eloop_ctx, void *sock_ctx)
@@ -1329,12 +1367,16 @@
if (wpa_s->wpa_state < WPA_ASSOCIATED)
return;
- wpa_printf(MSG_DEBUG, "WNM: Send keep-alive to AP " MACSTR,
- MAC2STR(wpa_s->bssid));
- /* TODO: could skip this if normal data traffic has been sent */
- /* TODO: Consider using some more appropriate data frame for this */
- if (wpa_s->l2)
- l2_packet_send(wpa_s->l2, wpa_s->bssid, 0x0800, (u8 *) "", 0);
+ if (!wpa_s->no_keep_alive) {
+ wpa_printf(MSG_DEBUG, "WNM: Send keep-alive to AP " MACSTR,
+ MAC2STR(wpa_s->bssid));
+ /* TODO: could skip this if normal data traffic has been sent */
+ /* TODO: Consider using some more appropriate data frame for
+ * this */
+ if (wpa_s->l2)
+ l2_packet_send(wpa_s->l2, wpa_s->bssid, 0x0800,
+ (u8 *) "", 0);
+ }
#ifdef CONFIG_SME
if (wpa_s->sme.bss_max_idle_period) {
@@ -1401,6 +1443,9 @@
{
int l, len, found = 0, wpa_found, rsn_found;
const u8 *p;
+#ifdef CONFIG_IEEE80211R
+ u8 bssid[ETH_ALEN];
+#endif /* CONFIG_IEEE80211R */
wpa_dbg(wpa_s, MSG_DEBUG, "Association info event");
if (data->assoc_info.req_ies)
@@ -1455,7 +1500,6 @@
#ifdef CONFIG_IEEE80211R
#ifdef CONFIG_SME
if (wpa_s->sme.auth_alg == WPA_AUTH_ALG_FT) {
- u8 bssid[ETH_ALEN];
if (wpa_drv_get_bssid(wpa_s, bssid) < 0 ||
wpa_ft_validate_reassoc_resp(wpa_s->wpa,
data->assoc_info.resp_ies,
@@ -1513,6 +1557,23 @@
}
#endif /* CONFIG_SME */
+ /* Process FT when SME is in the driver */
+ if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
+ wpa_ft_is_completed(wpa_s->wpa)) {
+ if (wpa_drv_get_bssid(wpa_s, bssid) < 0 ||
+ wpa_ft_validate_reassoc_resp(wpa_s->wpa,
+ data->assoc_info.resp_ies,
+ data->assoc_info.resp_ies_len,
+ bssid) < 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "FT: Validation of "
+ "Reassociation Response failed");
+ wpa_supplicant_deauthenticate(
+ wpa_s, WLAN_REASON_INVALID_IE);
+ return -1;
+ }
+ wpa_dbg(wpa_s, MSG_DEBUG, "FT: Reassociation Response done");
+ }
+
wpa_sm_set_ft_params(wpa_s->wpa, data->assoc_info.resp_ies,
data->assoc_info.resp_ies_len);
#endif /* CONFIG_IEEE80211R */
@@ -1632,7 +1693,7 @@
if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
wpa_dbg(wpa_s, MSG_ERROR, "Failed to get BSSID");
- wpa_supplicant_disassociate(
+ wpa_supplicant_deauthenticate(
wpa_s, WLAN_REASON_DEAUTH_LEAVING);
return;
}
@@ -1650,7 +1711,7 @@
wpa_clear_keys(wpa_s, bssid);
}
if (wpa_supplicant_select_config(wpa_s) < 0) {
- wpa_supplicant_disassociate(
+ wpa_supplicant_deauthenticate(
wpa_s, WLAN_REASON_DEAUTH_LEAVING);
return;
}
@@ -1669,8 +1730,12 @@
wpa_s->current_bss = bss;
}
+#ifdef ANDROID
+ if (wpa_s->conf->ap_scan == 1) {
+#else
if (wpa_s->conf->ap_scan == 1 &&
wpa_s->drv_flags & WPA_DRIVER_FLAGS_BSS_SELECTION) {
+#endif
if (wpa_supplicant_assoc_update_ie(wpa_s) < 0)
wpa_msg(wpa_s, MSG_WARNING,
"WPA/RSN IEs not updated");
@@ -1752,6 +1817,8 @@
eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
}
+ wpa_s->last_eapol_matches_bssid = 0;
+
if (wpa_s->pending_eapol_rx) {
struct os_time now, age;
os_get_time(&now);
@@ -1838,6 +1905,28 @@
}
+static int could_be_psk_mismatch(struct wpa_supplicant *wpa_s, u16 reason_code,
+ int locally_generated)
+{
+ if (wpa_s->wpa_state != WPA_4WAY_HANDSHAKE ||
+ !wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt))
+ return 0; /* Not in 4-way handshake with PSK */
+
+ /*
+ * It looks like connection was lost while trying to go through PSK
+ * 4-way handshake. Filter out known disconnection cases that are caused
+ * by something else than PSK mismatch to avoid confusing reports.
+ */
+
+ if (locally_generated) {
+ if (reason_code == WLAN_REASON_IE_IN_4WAY_DIFFERS)
+ return 0;
+ }
+
+ return 1;
+}
+
+
static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
u16 reason_code,
int locally_generated)
@@ -1863,8 +1952,7 @@
return;
}
- if (wpa_s->wpa_state == WPA_4WAY_HANDSHAKE &&
- wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
+ if (could_be_psk_mismatch(wpa_s, reason_code, locally_generated)) {
wpa_msg(wpa_s, MSG_INFO, "WPA: 4-Way Handshake failed - "
"pre-shared key may be incorrect");
wpas_auth_failed(wpa_s);
@@ -2123,10 +2211,14 @@
return;
switch (data->tdls.oper) {
case TDLS_REQUEST_SETUP:
- wpa_tdls_start(wpa_s->wpa, data->tdls.peer);
+ wpa_tdls_remove(wpa_s->wpa, data->tdls.peer);
+ if (wpa_tdls_is_external_setup(wpa_s->wpa))
+ wpa_tdls_start(wpa_s->wpa, data->tdls.peer);
+ else
+ wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, data->tdls.peer);
break;
case TDLS_REQUEST_TEARDOWN:
- wpa_tdls_send_teardown(wpa_s->wpa, data->tdls.peer,
+ wpa_tdls_teardown_link(wpa_s->wpa, data->tdls.peer,
data->tdls.reason_code);
break;
}
@@ -2134,7 +2226,7 @@
#endif /* CONFIG_TDLS */
-#ifdef CONFIG_IEEE80211V
+#ifdef CONFIG_WNM
static void wpa_supplicant_event_wnm(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
@@ -2146,11 +2238,11 @@
"(action=%d, intval=%d)",
data->wnm.sleep_action, data->wnm.sleep_intval);
ieee802_11_send_wnmsleep_req(wpa_s, data->wnm.sleep_action,
- data->wnm.sleep_intval);
+ data->wnm.sleep_intval, NULL);
break;
}
}
-#endif /* CONFIG_IEEE80211V */
+#endif /* CONFIG_WNM */
#ifdef CONFIG_IEEE80211R
@@ -2273,50 +2365,6 @@
}
-static void wnm_action_rx(struct wpa_supplicant *wpa_s, struct rx_action *rx)
-{
- u8 action, mode;
- const u8 *pos, *end;
-
- if (rx->data == NULL || rx->len == 0)
- return;
-
- pos = rx->data;
- end = pos + rx->len;
- action = *pos++;
-
- wpa_printf(MSG_DEBUG, "WNM: RX action %u from " MACSTR,
- action, MAC2STR(rx->sa));
- switch (action) {
- case WNM_BSS_TRANS_MGMT_REQ:
- if (pos + 5 > end)
- break;
- wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management "
- "Request: dialog_token=%u request_mode=0x%x "
- "disassoc_timer=%u validity_interval=%u",
- pos[0], pos[1], WPA_GET_LE16(pos + 2), pos[4]);
- mode = pos[1];
- pos += 5;
- if (mode & 0x08)
- pos += 12; /* BSS Termination Duration */
- if (mode & 0x10) {
- char url[256];
- if (pos + 1 > end || pos + 1 + pos[0] > end) {
- wpa_printf(MSG_DEBUG, "WNM: Invalid BSS "
- "Transition Management Request "
- "(URL)");
- break;
- }
- os_memcpy(url, pos + 1, pos[0]);
- url[pos[0]] = '\0';
- wpa_msg(wpa_s, MSG_INFO, "WNM: ESS Disassociation "
- "Imminent - session_info_url=%s", url);
- }
- break;
- }
-}
-
-
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data)
{
@@ -2470,18 +2518,9 @@
#ifndef CONFIG_NO_SCAN_PROCESSING
case EVENT_SCAN_RESULTS:
wpa_supplicant_event_scan_results(wpa_s, data);
-#ifdef CONFIG_P2P
- if (wpa_s->global->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled &&
- wpa_s->global->p2p != NULL &&
- wpa_s->wpa_state != WPA_AUTHENTICATING &&
- wpa_s->wpa_state != WPA_ASSOCIATING) {
- wpa_s->global->p2p_cb_on_scan_complete = 0;
- if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
- wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
- "continued after scan result processing");
- }
- }
-#endif /* CONFIG_P2P */
+ if (wpa_s->wpa_state != WPA_AUTHENTICATING &&
+ wpa_s->wpa_state != WPA_ASSOCIATING)
+ wpas_p2p_continue_after_scan(wpa_s);
break;
#endif /* CONFIG_NO_SCAN_PROCESSING */
case EVENT_ASSOCINFO:
@@ -2503,11 +2542,11 @@
wpa_supplicant_event_tdls(wpa_s, data);
break;
#endif /* CONFIG_TDLS */
-#ifdef CONFIG_IEEE80211V
+#ifdef CONFIG_WNM
case EVENT_WNM:
wpa_supplicant_event_wnm(wpa_s, data);
break;
-#endif /* CONFIG_IEEE80211V */
+#endif /* CONFIG_WNM */
#ifdef CONFIG_IEEE80211R
case EVENT_FT_RESPONSE:
wpa_supplicant_event_ft_response(wpa_s, data);
@@ -2530,9 +2569,8 @@
data->assoc_reject.status_code);
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
sme_event_assoc_reject(wpa_s, data);
-#ifdef ANDROID_P2P
-#ifdef CONFIG_P2P
else {
+#ifdef ANDROID_P2P
if(!wpa_s->current_ssid) {
wpa_printf(MSG_ERROR, "current_ssid == NULL");
break;
@@ -2571,9 +2609,14 @@
wpa_supplicant_disable_network(wpa_s, wpa_s->current_ssid);
wpas_p2p_group_remove(wpa_s, wpa_s->ifname);
}
- }
-#endif
+#else
+ const u8 *bssid = data->assoc_reject.bssid;
+ if (bssid == NULL || is_zero_ether_addr(bssid))
+ bssid = wpa_s->pending_bssid;
+ wpas_connection_failed(wpa_s, bssid);
+ wpa_supplicant_mark_disassoc(wpa_s);
#endif /* ANDROID_P2P */
+ }
break;
case EVENT_AUTH_TIMED_OUT:
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
@@ -2742,12 +2785,12 @@
}
#endif /* CONFIG_SME */
#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_IEEE80211V
+#ifdef CONFIG_WNM
if (data->rx_action.category == WLAN_ACTION_WNM) {
ieee802_11_rx_wnm_action(wpa_s, &data->rx_action);
break;
}
-#endif /* CONFIG_IEEE80211V */
+#endif /* CONFIG_WNM */
#ifdef CONFIG_GAS
if (data->rx_action.category == WLAN_ACTION_PUBLIC &&
gas_query_rx(wpa_s->gas, data->rx_action.da,
@@ -2756,10 +2799,6 @@
data->rx_action.freq) == 0)
break;
#endif /* CONFIG_GAS */
- if (data->rx_action.category == WLAN_ACTION_WNM) {
- wnm_action_rx(wpa_s, &data->rx_action);
- break;
- }
#ifdef CONFIG_TDLS
if (data->rx_action.category == WLAN_ACTION_PUBLIC &&
data->rx_action.len >= 4 &&
@@ -3009,6 +3048,16 @@
wpas_wps_start_pbc(wpa_s, NULL, 0);
#endif /* CONFIG_WPS */
break;
+ case EVENT_CONNECT_FAILED_REASON:
+#ifdef CONFIG_AP
+ if (!wpa_s->ap_iface || !data)
+ break;
+ hostapd_event_connect_failed_reason(
+ wpa_s->ap_iface->bss[0],
+ data->connect_failed_reason.addr,
+ data->connect_failed_reason.code);
+#endif /* CONFIG_AP */
+ break;
default:
wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event);
break;
diff --git a/wpa_supplicant/examples/wps-nfc.py b/wpa_supplicant/examples/wps-nfc.py
new file mode 100755
index 0000000..dbc143a
--- /dev/null
+++ b/wpa_supplicant/examples/wps-nfc.py
@@ -0,0 +1,410 @@
+#!/usr/bin/python
+#
+# Example nfcpy to wpa_supplicant wrapper for WPS NFC operations
+# Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import os
+import sys
+import time
+import random
+import StringIO
+
+import nfc
+import nfc.ndef
+import nfc.llcp
+import nfc.handover
+
+import logging
+logging.basicConfig()
+
+import wpaspy
+
+wpas_ctrl = '/var/run/wpa_supplicant'
+
+def wpas_connect():
+ ifaces = []
+ if os.path.isdir(wpas_ctrl):
+ try:
+ ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
+ except OSError, error:
+ print "Could not find wpa_supplicant: ", error
+ return None
+
+ if len(ifaces) < 1:
+ print "No wpa_supplicant control interface found"
+ return None
+
+ for ctrl in ifaces:
+ try:
+ wpas = wpaspy.Ctrl(ctrl)
+ return wpas
+ except Exception, e:
+ pass
+ return None
+
+
+def wpas_tag_read(message):
+ wpas = wpas_connect()
+ if (wpas == None):
+ return
+ print wpas.request("WPS_NFC_TAG_READ " + message.encode("hex"))
+
+
+def wpas_get_config_token(id=None):
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ if id:
+ return wpas.request("WPS_NFC_CONFIG_TOKEN NDEF " + id).rstrip().decode("hex")
+ return wpas.request("WPS_NFC_CONFIG_TOKEN NDEF").rstrip().decode("hex")
+
+
+def wpas_get_er_config_token(uuid):
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ return wpas.request("WPS_ER_NFC_CONFIG_TOKEN NDEF " + uuid).rstrip().decode("hex")
+
+
+def wpas_get_password_token():
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ return wpas.request("WPS_NFC_TOKEN NDEF").rstrip().decode("hex")
+
+
+def wpas_get_handover_req():
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ return wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS-CR").rstrip().decode("hex")
+
+
+def wpas_get_handover_sel(uuid):
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ if uuid is None:
+ return wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR").rstrip().decode("hex")
+ return wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR " + uuid).rstrip().decode("hex")
+
+
+def wpas_report_handover(req, sel, type):
+ wpas = wpas_connect()
+ if (wpas == None):
+ return None
+ return wpas.request("NFC_REPORT_HANDOVER " + type + " WPS " +
+ str(req).encode("hex") + " " +
+ str(sel).encode("hex"))
+
+
+class HandoverServer(nfc.handover.HandoverServer):
+ def __init__(self):
+ super(HandoverServer, self).__init__()
+
+ def process_request(self, request):
+ print "HandoverServer - request received"
+ print "Parsed handover request: " + request.pretty()
+
+ sel = nfc.ndef.HandoverSelectMessage(version="1.2")
+
+ for carrier in request.carriers:
+ print "Remote carrier type: " + carrier.type
+ if carrier.type == "application/vnd.wfa.wsc":
+ print "WPS carrier type match - add WPS carrier record"
+ self.received_carrier = carrier.record
+ data = wpas_get_handover_sel(self.uuid)
+ if data is None:
+ print "Could not get handover select carrier record from wpa_supplicant"
+ continue
+ print "Handover select carrier record from wpa_supplicant:"
+ print data.encode("hex")
+ self.sent_carrier = data
+
+ message = nfc.ndef.Message(data);
+ sel.add_carrier(message[0], "active", message[1:])
+
+ print "Handover select:"
+ print sel.pretty()
+ print str(sel).encode("hex")
+
+ print "Sending handover select"
+ return sel
+
+
+def wps_handover_resp(peer, uuid):
+ if uuid is None:
+ print "Trying to handle WPS handover"
+ else:
+ print "Trying to handle WPS handover with AP " + uuid
+
+ srv = HandoverServer()
+ srv.sent_carrier = None
+ srv.uuid = uuid
+
+ nfc.llcp.activate(peer);
+
+ try:
+ print "Trying handover";
+ srv.start()
+ print "Wait for disconnect"
+ while nfc.llcp.connected():
+ time.sleep(0.1)
+ print "Disconnected after handover"
+ except nfc.llcp.ConnectRefused:
+ print "Handover connection refused"
+ nfc.llcp.shutdown()
+ return
+
+ if srv.sent_carrier:
+ wpas_report_handover(srv.received_carrier, srv.sent_carrier, "RESP")
+
+ print "Remove peer"
+ nfc.llcp.shutdown()
+ print "Done with handover"
+ time.sleep(1)
+
+
+def wps_handover_init(peer):
+ print "Trying to initiate WPS handover"
+
+ data = wpas_get_handover_req()
+ if (data == None):
+ print "Could not get handover request carrier record from wpa_supplicant"
+ return
+ print "Handover request carrier record from wpa_supplicant: " + data.encode("hex")
+ record = nfc.ndef.Record()
+ f = StringIO.StringIO(data)
+ record._read(f)
+ record = nfc.ndef.HandoverCarrierRecord(record)
+ print "Parsed handover request carrier record:"
+ print record.pretty()
+
+ message = nfc.ndef.HandoverRequestMessage(version="1.2")
+ message.nonce = random.randint(0, 0xffff)
+ message.add_carrier(record, "active")
+
+ print "Handover request:"
+ print message.pretty()
+
+ nfc.llcp.activate(peer);
+
+ client = nfc.handover.HandoverClient()
+ try:
+ print "Trying handover";
+ client.connect()
+ print "Connected for handover"
+ except nfc.llcp.ConnectRefused:
+ print "Handover connection refused"
+ nfc.llcp.shutdown()
+ client.close()
+ return
+
+ print "Sending handover request"
+
+ if not client.send(message):
+ print "Failed to send handover request"
+
+ print "Receiving handover response"
+ message = client._recv()
+ if message is None:
+ print "No response received"
+ nfc.llcp.shutdown()
+ client.close()
+ return
+ if message.type != "urn:nfc:wkt:Hs":
+ print "Response was not Hs - received: " + message.type
+ nfc.llcp.shutdown()
+ client.close()
+ return
+
+ print "Received message"
+ print message.pretty()
+ message = nfc.ndef.HandoverSelectMessage(message)
+ print "Handover select received"
+ print message.pretty()
+
+ for carrier in message.carriers:
+ print "Remote carrier type: " + carrier.type
+ if carrier.type == "application/vnd.wfa.wsc":
+ print "WPS carrier type match - send to wpa_supplicant"
+ wpas_report_handover(data, carrier.record, "INIT")
+ wifi = nfc.ndef.WifiConfigRecord(carrier.record)
+ print wifi.pretty()
+
+ print "Remove peer"
+ nfc.llcp.shutdown()
+ client.close()
+ print "Done with handover"
+
+
+def wps_tag_read(tag):
+ if len(tag.ndef.message):
+ message = nfc.ndef.Message(tag.ndef.message)
+ print "message type " + message.type
+
+ for record in message:
+ print "record type " + record.type
+ if record.type == "application/vnd.wfa.wsc":
+ print "WPS tag - send to wpa_supplicant"
+ wpas_tag_read(tag.ndef.message)
+ break
+ else:
+ print "Empty tag"
+
+ print "Remove tag"
+ while tag.is_present:
+ time.sleep(0.1)
+
+
+def wps_write_config_tag(clf, id=None):
+ print "Write WPS config token"
+ data = wpas_get_config_token(id)
+ if (data == None):
+ print "Could not get WPS config token from wpa_supplicant"
+ return
+
+ print "Touch an NFC tag"
+ while True:
+ tag = clf.poll()
+ if tag == None:
+ time.sleep(0.1)
+ continue
+ break
+
+ print "Tag found - writing"
+ tag.ndef.message = data
+ print "Done - remove tag"
+ while tag.is_present:
+ time.sleep(0.1)
+
+
+def wps_write_er_config_tag(clf, uuid):
+ print "Write WPS ER config token"
+ data = wpas_get_er_config_token(uuid)
+ if (data == None):
+ print "Could not get WPS config token from wpa_supplicant"
+ return
+
+ print "Touch an NFC tag"
+ while True:
+ tag = clf.poll()
+ if tag == None:
+ time.sleep(0.1)
+ continue
+ break
+
+ print "Tag found - writing"
+ tag.ndef.message = data
+ print "Done - remove tag"
+ while tag.is_present:
+ time.sleep(0.1)
+
+
+def wps_write_password_tag(clf):
+ print "Write WPS password token"
+ data = wpas_get_password_token()
+ if (data == None):
+ print "Could not get WPS password token from wpa_supplicant"
+ return
+
+ print "Touch an NFC tag"
+ while True:
+ tag = clf.poll()
+ if tag == None:
+ time.sleep(0.1)
+ continue
+ break
+
+ print "Tag found - writing"
+ tag.ndef.message = data
+ print "Done - remove tag"
+ while tag.is_present:
+ time.sleep(0.1)
+
+
+def find_peer(clf):
+ while True:
+ if nfc.llcp.connected():
+ print "LLCP connected"
+ general_bytes = nfc.llcp.startup({})
+ peer = clf.listen(ord(os.urandom(1)) + 250, general_bytes)
+ if isinstance(peer, nfc.DEP):
+ print "listen -> DEP";
+ if peer.general_bytes.startswith("Ffm"):
+ print "Found DEP"
+ return peer
+ print "mismatch in general_bytes"
+ print peer.general_bytes
+
+ peer = clf.poll(general_bytes)
+ if isinstance(peer, nfc.DEP):
+ print "poll -> DEP";
+ if peer.general_bytes.startswith("Ffm"):
+ print "Found DEP"
+ return peer
+ print "mismatch in general_bytes"
+ print peer.general_bytes
+
+ if peer:
+ print "Found tag"
+ return peer
+
+
+def main():
+ clf = nfc.ContactlessFrontend()
+
+ try:
+ arg_uuid = None
+ if len(sys.argv) > 1:
+ arg_uuid = sys.argv[1]
+
+ if len(sys.argv) > 1 and sys.argv[1] == "write-config":
+ wps_write_config_tag(clf)
+ raise SystemExit
+
+ if len(sys.argv) > 2 and sys.argv[1] == "write-config-id":
+ wps_write_config_tag(clf, sys.argv[2])
+ raise SystemExit
+
+ if len(sys.argv) > 2 and sys.argv[1] == "write-er-config":
+ wps_write_er_config_tag(clf, sys.argv[2])
+ raise SystemExit
+
+ if len(sys.argv) > 1 and sys.argv[1] == "write-password":
+ wps_write_password_tag(clf)
+ raise SystemExit
+
+ while True:
+ print "Waiting for a tag or peer to be touched"
+
+ tag = find_peer(clf)
+ if isinstance(tag, nfc.DEP):
+ if arg_uuid is None:
+ wps_handover_init(tag)
+ elif arg_uuid is "ap":
+ wps_handover_resp(tag, None)
+ else:
+ wps_handover_resp(tag, arg_uuid)
+ continue
+
+ if tag.ndef:
+ wps_tag_read(tag)
+ continue
+
+ print "Not an NDEF tag - remove tag"
+ while tag.is_present:
+ time.sleep(0.1)
+
+ except KeyboardInterrupt:
+ raise SystemExit
+ finally:
+ clf.close()
+
+ raise SystemExit
+
+if __name__ == '__main__':
+ main()
diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c
index efa9be8..27bcc7a 100644
--- a/wpa_supplicant/gas_query.c
+++ b/wpa_supplicant/gas_query.c
@@ -19,9 +19,13 @@
#include "gas_query.h"
+/** GAS query timeout in seconds */
#define GAS_QUERY_TIMEOUT_PERIOD 5
+/**
+ * struct gas_query_pending - Pending GAS query
+ */
struct gas_query_pending {
struct dl_list list;
u8 addr[ETH_ALEN];
@@ -40,6 +44,9 @@
void *ctx;
};
+/**
+ * struct gas_query - Internal GAS query data
+ */
struct gas_query {
struct wpa_supplicant *wpa_s;
struct dl_list pending; /* struct gas_query_pending */
@@ -50,6 +57,11 @@
static void gas_query_timeout(void *eloop_data, void *user_ctx);
+/**
+ * gas_query_init - Initialize GAS query component
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: Pointer to GAS query data or %NULL on failure
+ */
struct gas_query * gas_query_init(struct wpa_supplicant *wpa_s)
{
struct gas_query *gas;
@@ -82,6 +94,10 @@
}
+/**
+ * gas_query_deinit - Deinitialize GAS query component
+ * @gas: GAS query data from gas_query_init()
+ */
void gas_query_deinit(struct gas_query *gas)
{
struct gas_query_pending *query, *next;
@@ -274,6 +290,17 @@
}
+/**
+ * gas_query_rx - Indicate reception of a Public Action frame
+ * @gas: GAS query data from gas_query_init()
+ * @da: Destination MAC address of the Action frame
+ * @sa: Source MAC address of the Action frame
+ * @bssid: BSSID of the Action frame
+ * @data: Payload of the Action frame
+ * @len: Length of @data
+ * @freq: Frequency (in MHz) on which the frame was received
+ * Returns: 0 if the Public Action frame was a GAS frame or -1 if not
+ */
int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa,
const u8 *bssid, const u8 *data, size_t len, int freq)
{
@@ -414,6 +441,16 @@
}
+/**
+ * gas_query_req - Request a GAS query
+ * @gas: GAS query data from gas_query_init()
+ * @dst: Destination MAC address for the query
+ * @freq: Frequency (in MHz) for the channel on which to send the query
+ * @req: GAS query payload
+ * @cb: Callback function for reporting GAS query result and response
+ * @ctx: Context pointer to use with the @cb call
+ * Returns: dialog token (>= 0) on success or -1 on failure
+ */
int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
struct wpabuf *req,
void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
@@ -453,6 +490,7 @@
if (gas_query_tx(gas, query, req) < 0) {
wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
MACSTR, MAC2STR(query->addr));
+ dl_list_del(&query->list);
os_free(query);
return -1;
}
@@ -464,6 +502,12 @@
}
+/**
+ * gas_query_cancel - Cancel a pending GAS query
+ * @gas: GAS query data from gas_query_init()
+ * @dst: Destination MAC address for the query
+ * @dialog_token: Dialog token from gas_query_req()
+ */
void gas_query_cancel(struct gas_query *gas, const u8 *dst, u8 dialog_token)
{
struct gas_query_pending *query;
diff --git a/wpa_supplicant/gas_query.h b/wpa_supplicant/gas_query.h
index 01aba6e..5c3d161 100644
--- a/wpa_supplicant/gas_query.h
+++ b/wpa_supplicant/gas_query.h
@@ -19,6 +19,9 @@
int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa,
const u8 *bssid, const u8 *data, size_t len, int freq);
+/**
+ * enum gas_query_result - GAS query result
+ */
enum gas_query_result {
GAS_QUERY_SUCCESS,
GAS_QUERY_FAILURE,
diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c
index 0eb6119..1404241 100644
--- a/wpa_supplicant/hs20_supplicant.c
+++ b/wpa_supplicant/hs20_supplicant.c
@@ -79,8 +79,10 @@
freq = wpa_s->assoc_freq;
bss = wpa_bss_get_bssid(wpa_s, dst);
- if (bss)
+ if (bss) {
+ wpa_bss_anqp_unshare_alloc(bss);
freq = bss->freq;
+ }
if (freq <= 0)
return -1;
@@ -141,9 +143,16 @@
}
break;
case HS20_STYPE_WAN_METRICS:
+ wpa_hexdump(MSG_DEBUG, "WAN Metrics", pos, slen);
+ if (slen < 13) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short WAN "
+ "Metrics value from " MACSTR, MAC2STR(sa));
+ break;
+ }
wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
- " WAN Metrics", MAC2STR(sa));
- wpa_hexdump_ascii(MSG_DEBUG, "WAN Metrics", pos, slen);
+ " WAN Metrics %02x:%u:%u:%u:%u:%u", MAC2STR(sa),
+ pos[0], WPA_GET_LE32(pos + 1), WPA_GET_LE32(pos + 5),
+ pos[9], pos[10], WPA_GET_LE16(pos + 11));
if (anqp) {
wpabuf_free(anqp->hs20_wan_metrics);
anqp->hs20_wan_metrics = wpabuf_alloc_copy(pos, slen);
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index 22f709f..b59dd6a 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -13,6 +13,7 @@
#include "common/gas.h"
#include "common/wpa_ctrl.h"
#include "utils/pcsc_funcs.h"
+#include "utils/eloop.h"
#include "drivers/driver.h"
#include "eap_common/eap_defs.h"
#include "eap_peer/eap.h"
@@ -41,6 +42,10 @@
#endif
static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s);
+static struct wpa_cred * interworking_credentials_available_realm(
+ struct wpa_supplicant *wpa_s, struct wpa_bss *bss);
+static struct wpa_cred * interworking_credentials_available_3gpp(
+ struct wpa_supplicant *wpa_s, struct wpa_bss *bss);
static void interworking_reconnect(struct wpa_supplicant *wpa_s)
@@ -53,16 +58,8 @@
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
- if (wpa_s->last_scan_res_used > 0) {
- struct os_time now;
- os_get_time(&now);
- if (now.sec - wpa_s->last_scan.sec <= 5) {
- wpa_printf(MSG_DEBUG, "Interworking: Old scan results "
- "are fresh - connect without new scan");
- if (wpas_select_network_from_last_scan(wpa_s) >= 0)
- return;
- }
- }
+ if (wpa_supplicant_fast_associate(wpa_s) >= 0)
+ return;
wpa_supplicant_req_scan(wpa_s, 0, 0);
}
@@ -170,6 +167,13 @@
}
+static void interworking_continue_anqp(void *eloop_ctx, void *sock_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ interworking_next_anqp_fetch(wpa_s);
+}
+
+
static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss)
{
@@ -183,6 +187,7 @@
wpa_printf(MSG_DEBUG, "Interworking: ANQP Query Request to " MACSTR,
MAC2STR(bss->bssid));
+ wpa_s->interworking_gas_bss = bss;
info_ids[num_info_ids++] = ANQP_CAPABILITY_LIST;
if (all) {
@@ -238,6 +243,8 @@
if (res < 0) {
wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
ret = -1;
+ eloop_register_timeout(0, 0, interworking_continue_anqp, wpa_s,
+ NULL);
} else
wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
"%u", res);
@@ -516,13 +523,18 @@
return 0;
}
- if (eap->method == EAP_TYPE_PEAP &&
- eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL)
- return 0;
+ if (eap->method == EAP_TYPE_PEAP) {
+ if (eap->inner_method &&
+ eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL)
+ return 0;
+ if (!eap->inner_method &&
+ eap_get_name(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2) == NULL)
+ return 0;
+ }
if (eap->method == EAP_TYPE_TTLS) {
if (eap->inner_method == 0 && eap->inner_non_eap == 0)
- return 0;
+ return 1; /* Assume TTLS/MSCHAPv2 is used */
if (eap->inner_method &&
eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL)
return 0;
@@ -717,9 +729,12 @@
#endif /* INTERWORKING_3GPP */
-static int interworking_set_hs20_params(struct wpa_ssid *ssid)
+static int interworking_set_hs20_params(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
{
- if (wpa_config_set(ssid, "key_mgmt", "WPA-EAP", 0) < 0)
+ if (wpa_config_set(ssid, "key_mgmt",
+ wpa_s->conf->pmf != NO_MGMT_FRAME_PROTECTION ?
+ "WPA-EAP WPA-EAP-SHA256" : "WPA-EAP", 0) < 0)
return -1;
if (wpa_config_set(ssid, "proto", "RSN", 0) < 0)
return -1;
@@ -730,10 +745,10 @@
static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
+ struct wpa_cred *cred,
struct wpa_bss *bss)
{
#ifdef INTERWORKING_3GPP
- struct wpa_cred *cred;
struct wpa_ssid *ssid;
const u8 *ie;
int eap_type;
@@ -743,40 +758,6 @@
if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL)
return -1;
- for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
- char *sep;
- const char *imsi;
- int mnc_len;
-
-#ifdef PCSC_FUNCS
- if (cred->pcsc && wpa_s->conf->pcsc_reader && wpa_s->scard &&
- wpa_s->imsi[0]) {
- imsi = wpa_s->imsi;
- mnc_len = wpa_s->mnc_len;
- goto compare;
- }
-#endif /* PCSC_FUNCS */
-
- if (cred->imsi == NULL || !cred->imsi[0] ||
- cred->milenage == NULL || !cred->milenage[0])
- continue;
-
- sep = os_strchr(cred->imsi, '-');
- if (sep == NULL ||
- (sep - cred->imsi != 5 && sep - cred->imsi != 6))
- continue;
- mnc_len = sep - cred->imsi - 3;
- imsi = cred->imsi;
-
-#ifdef PCSC_FUNCS
- compare:
-#endif /* PCSC_FUNCS */
- if (plmn_id_match(bss->anqp->anqp_3gpp, imsi, mnc_len))
- break;
- }
- if (cred == NULL)
- return -1;
-
ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
if (ie == NULL)
return -1;
@@ -786,6 +767,7 @@
ssid = wpa_config_add_network(wpa_s->conf);
if (ssid == NULL)
return -1;
+ ssid->parent_cred = cred;
wpas_notify_network_added(wpa_s, ssid);
wpa_config_set_network_defaults(ssid);
@@ -797,7 +779,7 @@
os_memcpy(ssid->ssid, ie + 2, ie[1]);
ssid->ssid_len = ie[1];
- if (interworking_set_hs20_params(ssid) < 0)
+ if (interworking_set_hs20_params(wpa_s, ssid) < 0)
goto fail;
eap_type = EAP_TYPE_SIM;
@@ -944,6 +926,24 @@
}
+static int cred_excluded_ssid(struct wpa_cred *cred, struct wpa_bss *bss)
+{
+ size_t i;
+
+ if (!cred->excluded_ssid)
+ return 0;
+
+ for (i = 0; i < cred->num_excluded_ssid; i++) {
+ struct excluded_ssid *e = &cred->excluded_ssid[i];
+ if (bss->ssid_len == e->ssid_len &&
+ os_memcmp(bss->ssid, e->ssid, e->ssid_len) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+
static struct wpa_cred * interworking_credentials_available_roaming_consortium(
struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
{
@@ -971,6 +971,9 @@
cred->roaming_consortium_len))
continue;
+ if (cred_excluded_ssid(cred, bss))
+ continue;
+
if (selected == NULL ||
selected->priority < cred->priority)
selected = cred;
@@ -1046,6 +1049,17 @@
wpa_config_set_quoted(ssid, "client_cert", cred->client_cert) < 0)
return -1;
+#ifdef ANDROID
+ if (cred->private_key &&
+ os_strncmp(cred->private_key, "keystore://", 11) == 0) {
+ /* Use OpenSSL engine configuration for Android keystore */
+ if (wpa_config_set_quoted(ssid, "engine_id", "keystore") < 0 ||
+ wpa_config_set_quoted(ssid, "key_id",
+ cred->private_key + 11) < 0 ||
+ wpa_config_set(ssid, "engine", "1", 0) < 0)
+ return -1;
+ } else
+#endif /* ANDROID */
if (cred->private_key && cred->private_key[0] &&
wpa_config_set_quoted(ssid, "private_key", cred->private_key) < 0)
return -1;
@@ -1084,6 +1098,7 @@
ssid = wpa_config_add_network(wpa_s->conf);
if (ssid == NULL)
return -1;
+ ssid->parent_cred = cred;
wpas_notify_network_added(wpa_s, ssid);
wpa_config_set_network_defaults(ssid);
ssid->priority = cred->priority;
@@ -1094,7 +1109,7 @@
os_memcpy(ssid->ssid, ssid_ie + 2, ssid_ie[1]);
ssid->ssid_len = ssid_ie[1];
- if (interworking_set_hs20_params(ssid) < 0)
+ if (interworking_set_hs20_params(wpa_s, ssid) < 0)
goto fail;
if (cred->eap_method == NULL) {
@@ -1123,7 +1138,7 @@
int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
{
- struct wpa_cred *cred;
+ struct wpa_cred *cred, *cred_rc, *cred_3gpp;
struct wpa_ssid *ssid;
struct nai_realm *realm;
struct nai_realm_eap *eap = NULL;
@@ -1150,39 +1165,61 @@
return -1;
}
- cred = interworking_credentials_available_roaming_consortium(wpa_s,
- bss);
- if (cred)
- return interworking_connect_roaming_consortium(wpa_s, cred,
+ cred_rc = interworking_credentials_available_roaming_consortium(wpa_s,
+ bss);
+ if (cred_rc) {
+ wpa_printf(MSG_DEBUG, "Interworking: Highest roaming "
+ "consortium matching credential priority %d",
+ cred_rc->priority);
+ }
+
+ cred = interworking_credentials_available_realm(wpa_s, bss);
+ if (cred) {
+ wpa_printf(MSG_DEBUG, "Interworking: Highest NAI Realm list "
+ "matching credential priority %d",
+ cred->priority);
+ }
+
+ cred_3gpp = interworking_credentials_available_3gpp(wpa_s, bss);
+ if (cred_3gpp) {
+ wpa_printf(MSG_DEBUG, "Interworking: Highest 3GPP matching "
+ "credential priority %d", cred_3gpp->priority);
+ }
+
+ if (cred_rc &&
+ (cred == NULL || cred_rc->priority >= cred->priority) &&
+ (cred_3gpp == NULL || cred_rc->priority >= cred_3gpp->priority))
+ return interworking_connect_roaming_consortium(wpa_s, cred_rc,
bss, ie);
+ if (cred_3gpp &&
+ (cred == NULL || cred_3gpp->priority >= cred->priority)) {
+ return interworking_connect_3gpp(wpa_s, cred_3gpp, bss);
+ }
+
+ if (cred == NULL) {
+ wpa_printf(MSG_DEBUG, "Interworking: No matching credentials "
+ "found for " MACSTR, MAC2STR(bss->bssid));
+ return -1;
+ }
+
realm = nai_realm_parse(bss->anqp ? bss->anqp->nai_realm : NULL,
&count);
if (realm == NULL) {
wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
"Realm list from " MACSTR, MAC2STR(bss->bssid));
- count = 0;
+ return -1;
}
- for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
- for (i = 0; i < count; i++) {
- if (!nai_realm_match(&realm[i], cred->realm))
- continue;
- eap = nai_realm_find_eap(cred, &realm[i]);
- if (eap)
- break;
- }
+ for (i = 0; i < count; i++) {
+ if (!nai_realm_match(&realm[i], cred->realm))
+ continue;
+ eap = nai_realm_find_eap(cred, &realm[i]);
if (eap)
break;
}
if (!eap) {
- if (interworking_connect_3gpp(wpa_s, bss) == 0) {
- if (realm)
- nai_realm_free(realm, count);
- return 0;
- }
-
wpa_printf(MSG_DEBUG, "Interworking: No matching credentials "
"and EAP method found for " MACSTR,
MAC2STR(bss->bssid));
@@ -1198,6 +1235,7 @@
nai_realm_free(realm, count);
return -1;
}
+ ssid->parent_cred = cred;
wpas_notify_network_added(wpa_s, ssid);
wpa_config_set_network_defaults(ssid);
ssid->priority = cred->priority;
@@ -1208,7 +1246,7 @@
os_memcpy(ssid->ssid, ie + 2, ie[1]);
ssid->ssid_len = ie[1];
- if (interworking_set_hs20_params(ssid) < 0)
+ if (interworking_set_hs20_params(wpa_s, ssid) < 0)
goto fail;
if (wpa_config_set(ssid, "eap", eap_get_name(EAP_VENDOR_IETF,
@@ -1246,11 +1284,20 @@
0) < 0)
goto fail;
break;
+ default:
+ /* EAP params were not set - assume TTLS/MSCHAPv2 */
+ if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAPV2\"",
+ 0) < 0)
+ goto fail;
+ break;
}
break;
case EAP_TYPE_PEAP:
os_snprintf(buf, sizeof(buf), "\"auth=%s\"",
- eap_get_name(EAP_VENDOR_IETF, eap->inner_method));
+ eap_get_name(EAP_VENDOR_IETF,
+ eap->inner_method ?
+ eap->inner_method :
+ EAP_TYPE_MSCHAPV2));
if (wpa_config_set(ssid, "phase2", buf, 0) < 0)
goto fail;
break;
@@ -1280,10 +1327,11 @@
static struct wpa_cred * interworking_credentials_available_3gpp(
struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
{
- struct wpa_cred *cred, *selected = NULL;
+ struct wpa_cred *selected = NULL;
+#ifdef INTERWORKING_3GPP
+ struct wpa_cred *cred;
int ret;
-#ifdef INTERWORKING_3GPP
if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL)
return NULL;
@@ -1320,6 +1368,8 @@
ret = plmn_id_match(bss->anqp->anqp_3gpp, imsi, mnc_len);
wpa_printf(MSG_DEBUG, "PLMN match %sfound", ret ? "" : "not ");
if (ret) {
+ if (cred_excluded_ssid(cred, bss))
+ continue;
if (selected == NULL ||
selected->priority < cred->priority)
selected = cred;
@@ -1360,6 +1410,8 @@
if (!nai_realm_match(&realm[i], cred->realm))
continue;
if (nai_realm_find_eap(cred, &realm[i])) {
+ if (cred_excluded_ssid(cred, bss))
+ continue;
if (selected == NULL ||
selected->priority < cred->priority)
selected = cred;
@@ -1424,50 +1476,61 @@
}
+int interworking_home_sp_cred(struct wpa_supplicant *wpa_s,
+ struct wpa_cred *cred,
+ struct wpabuf *domain_names)
+{
+#ifdef INTERWORKING_3GPP
+ char nai[100], *realm;
+
+ char *imsi = NULL;
+ int mnc_len = 0;
+ if (cred->imsi)
+ imsi = cred->imsi;
+#ifdef CONFIG_PCSC
+ else if (cred->pcsc && wpa_s->conf->pcsc_reader &&
+ wpa_s->scard && wpa_s->imsi[0]) {
+ imsi = wpa_s->imsi;
+ mnc_len = wpa_s->mnc_len;
+ }
+#endif /* CONFIG_PCSC */
+ if (domain_names &&
+ imsi && build_root_nai(nai, sizeof(nai), imsi, mnc_len, 0) == 0) {
+ realm = os_strchr(nai, '@');
+ if (realm)
+ realm++;
+ wpa_printf(MSG_DEBUG, "Interworking: Search for match "
+ "with SIM/USIM domain %s", realm);
+ if (realm &&
+ domain_name_list_contains(domain_names, realm))
+ return 1;
+ }
+#endif /* INTERWORKING_3GPP */
+
+ if (domain_names == NULL || cred->domain == NULL)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "Interworking: Search for match with "
+ "home SP FQDN %s", cred->domain);
+ if (domain_name_list_contains(domain_names, cred->domain))
+ return 1;
+
+ return 0;
+}
+
+
static int interworking_home_sp(struct wpa_supplicant *wpa_s,
struct wpabuf *domain_names)
{
struct wpa_cred *cred;
-#ifdef INTERWORKING_3GPP
- char nai[100], *realm;
-#endif /* INTERWORKING_3GPP */
if (domain_names == NULL || wpa_s->conf->cred == NULL)
return -1;
for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
-#ifdef INTERWORKING_3GPP
- char *imsi = NULL;
- int mnc_len = 0;
- if (cred->imsi)
- imsi = cred->imsi;
-#ifdef CONFIG_PCSC
- else if (cred->pcsc && wpa_s->conf->pcsc_reader &&
- wpa_s->scard && wpa_s->imsi[0]) {
- imsi = wpa_s->imsi;
- mnc_len = wpa_s->mnc_len;
- }
-#endif /* CONFIG_PCSC */
- if (imsi && build_root_nai(nai, sizeof(nai), imsi, mnc_len, 0)
- == 0) {
- realm = os_strchr(nai, '@');
- if (realm)
- realm++;
- wpa_printf(MSG_DEBUG, "Interworking: Search for match "
- "with SIM/USIM domain %s", realm);
- if (realm &&
- domain_name_list_contains(domain_names, realm))
- return 1;
- }
-#endif /* INTERWORKING_3GPP */
-
- if (cred->domain == NULL)
- continue;
-
- wpa_printf(MSG_DEBUG, "Interworking: Search for match with "
- "home SP FQDN %s", cred->domain);
- if (domain_name_list_contains(domain_names, cred->domain))
- return 1;
+ int res = interworking_home_sp_cred(wpa_s, cred, domain_names);
+ if (res)
+ return res;
}
return 0;
@@ -1603,6 +1666,11 @@
continue;
if (other->anqp == NULL)
continue;
+ if (other->anqp->roaming_consortium == NULL &&
+ other->anqp->nai_realm == NULL &&
+ other->anqp->anqp_3gpp == NULL &&
+ other->anqp->domain_name == NULL)
+ continue;
if (!(other->flags & WPA_BSS_ANQP_FETCH_TRIED))
continue;
if (os_memcmp(bss->hessid, other->hessid, ETH_ALEN) != 0)
@@ -1628,7 +1696,7 @@
int found = 0;
const u8 *ie;
- if (!wpa_s->fetch_anqp_in_progress)
+ if (eloop_terminated() || !wpa_s->fetch_anqp_in_progress)
return;
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
@@ -1714,8 +1782,10 @@
freq = wpa_s->assoc_freq;
bss = wpa_bss_get_bssid(wpa_s, dst);
- if (bss)
+ if (bss) {
+ wpa_bss_anqp_unshare_alloc(bss);
freq = bss->freq;
+ }
if (freq <= 0)
return -1;
@@ -1740,11 +1810,11 @@
static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
- const u8 *sa, u16 info_id,
+ struct wpa_bss *bss, const u8 *sa,
+ u16 info_id,
const u8 *data, size_t slen)
{
const u8 *pos = data;
- struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa);
struct wpa_bss_anqp *anqp = NULL;
#ifdef CONFIG_HS20
u8 type;
@@ -1880,6 +1950,7 @@
const u8 *end;
u16 info_id;
u16 slen;
+ struct wpa_bss *bss = NULL, *tmp;
if (result != GAS_QUERY_SUCCESS)
return;
@@ -1892,6 +1963,21 @@
return;
}
+ /*
+ * If possible, select the BSS entry based on which BSS entry was used
+ * for the request. This can help in cases where multiple BSS entries
+ * may exist for the same AP.
+ */
+ dl_list_for_each_reverse(tmp, &wpa_s->bss, struct wpa_bss, list) {
+ if (tmp == wpa_s->interworking_gas_bss &&
+ os_memcmp(tmp->bssid, dst, ETH_ALEN) == 0) {
+ bss = tmp;
+ break;
+ }
+ }
+ if (bss == NULL)
+ bss = wpa_bss_get_bssid(wpa_s, dst);
+
pos = wpabuf_head(resp);
end = pos + wpabuf_len(resp);
@@ -1909,7 +1995,7 @@
"for Info ID %u", info_id);
break;
}
- interworking_parse_rx_anqp_resp(wpa_s, dst, info_id, pos,
+ interworking_parse_rx_anqp_resp(wpa_s, bss, dst, info_id, pos,
slen);
pos += slen;
}
@@ -1935,7 +2021,7 @@
wpa_printf(MSG_DEBUG, "Interworking: Start scan for network "
"selection");
wpa_s->scan_res_handler = interworking_scan_res_handler;
- wpa_s->scan_req = 2;
+ wpa_s->scan_req = MANUAL_SCAN_REQ;
wpa_supplicant_req_scan(wpa_s, 0, 0);
return 0;
diff --git a/wpa_supplicant/interworking.h b/wpa_supplicant/interworking.h
index cb8438e..4a4af82 100644
--- a/wpa_supplicant/interworking.h
+++ b/wpa_supplicant/interworking.h
@@ -25,5 +25,8 @@
int interworking_select(struct wpa_supplicant *wpa_s, int auto_select);
int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss);
void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s);
+int interworking_home_sp_cred(struct wpa_supplicant *wpa_s,
+ struct wpa_cred *cred,
+ struct wpabuf *domain_names);
#endif /* INTERWORKING_H */
diff --git a/wpa_supplicant/main.c b/wpa_supplicant/main.c
index 19f7ce6..1744620 100644
--- a/wpa_supplicant/main.c
+++ b/wpa_supplicant/main.c
@@ -32,7 +32,8 @@
" [-o<override driver>] [-O<override ctrl>] \\\n"
" [-N -i<ifname> -c<conf> [-C<ctrl>] "
"[-D<driver>] \\\n"
- " [-p<driver_param>] [-b<br_ifname>] ...]\n"
+ " [-p<driver_param>] [-b<br_ifname>] [-I<config file>] "
+ "...]\n"
"\n"
"drivers:\n",
wpa_supplicant_version, wpa_supplicant_license);
@@ -50,6 +51,7 @@
" -c = Configuration file\n"
" -C = ctrl_interface parameter (only used if -c is not)\n"
" -i = interface name\n"
+ " -I = additional configuration file\n"
" -d = increase debugging verbosity (-dd even more)\n"
" -D = driver name (can be multiple drivers: nl80211,wext)\n"
" -e = entropy file\n");
@@ -155,7 +157,7 @@
for (;;) {
c = getopt(argc, argv,
- "b:Bc:C:D:de:f:g:hi:KLNo:O:p:P:qsTtuvW");
+ "b:Bc:C:D:de:f:g:hi:I:KLNo:O:p:P:qsTtuvW");
if (c < 0)
break;
switch (c) {
@@ -202,6 +204,9 @@
case 'i':
iface->ifname = optarg;
break;
+ case 'I':
+ iface->confanother = optarg;
+ break;
case 'K':
params.wpa_debug_show_keys++;
break;
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index 770907c..4479c09 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -327,6 +327,9 @@
void wpas_notify_bss_wps_changed(struct wpa_supplicant *wpa_s,
unsigned int id)
{
+#ifdef CONFIG_WPS
+ wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_WPS, id);
+#endif /* CONFIG_WPS */
}
diff --git a/wpa_supplicant/offchannel.c b/wpa_supplicant/offchannel.c
index b88eab1..856eca7 100644
--- a/wpa_supplicant/offchannel.c
+++ b/wpa_supplicant/offchannel.c
@@ -132,6 +132,17 @@
}
+/**
+ * offchannel_send_action_tx_status - TX status callback
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @dst: Destination MAC address of the transmitted Action frame
+ * @data: Transmitted frame payload
+ * @data_len: Length of @data in bytes
+ * @result: TX status
+ *
+ * This function is called whenever the driver indicates a TX status event for
+ * a frame sent by offchannel_send_action() using wpa_drv_send_action().
+ */
void offchannel_send_action_tx_status(
struct wpa_supplicant *wpa_s, const u8 *dst, const u8 *data,
size_t data_len, enum offchannel_send_action_result result)
@@ -164,6 +175,27 @@
}
+/**
+ * offchannel_send_action - Request off-channel Action frame TX
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @freq: The frequency in MHz indicating the channel on which the frame is to
+ * transmitted or 0 for the current channel (only if associated)
+ * @dst: Action frame destination MAC address
+ * @src: Action frame source MAC address
+ * @bssid: Action frame BSSID
+ * @buf: Frame to transmit starting from the Category field
+ * @len: Length of @buf in bytes
+ * @wait_time: Wait time for response in milliseconds
+ * @tx_cb: Callback function for indicating TX status or %NULL for now callback
+ * @no_cck: Whether CCK rates are to be disallowed for TX rate selection
+ * Returns: 0 on success or -1 on failure
+ *
+ * This function is used to request an Action frame to be transmitted on the
+ * current operating channel or on another channel (off-channel). The actual
+ * frame transmission will be delayed until the driver is ready on the specified
+ * channel. The @wait_time parameter can be used to request the driver to remain
+ * awake on the channel to wait for a response.
+ */
int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq,
const u8 *dst, const u8 *src, const u8 *bssid,
const u8 *buf, size_t len, unsigned int wait_time,
@@ -266,6 +298,13 @@
}
+/**
+ * offchannel_send_send_action_done - Notify completion of Action frame sequence
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function can be used to cancel a wait for additional response frames on
+ * the channel that was used with offchannel_send_action().
+ */
void offchannel_send_action_done(struct wpa_supplicant *wpa_s)
{
wpa_printf(MSG_DEBUG, "Off-channel: Action frame sequence done "
@@ -284,6 +323,15 @@
}
+/**
+ * offchannel_remain_on_channel_cb - Remain-on-channel callback function
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @freq: Frequency (in MHz) of the selected channel
+ * @duration: Duration of the remain-on-channel operation in milliseconds
+ *
+ * This function is called whenever the driver notifies beginning of a
+ * remain-on-channel operation.
+ */
void offchannel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
unsigned int freq, unsigned int duration)
{
@@ -293,6 +341,14 @@
}
+/**
+ * offchannel_cancel_remain_on_channel_cb - Remain-on-channel stopped callback
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @freq: Frequency (in MHz) of the selected channel
+ *
+ * This function is called whenever the driver notifies termination of a
+ * remain-on-channel operation.
+ */
void offchannel_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
unsigned int freq)
{
@@ -300,9 +356,42 @@
}
-void offchannel_deinit(struct wpa_supplicant *wpa_s)
+/**
+ * offchannel_pending_action_tx - Check whether there is a pending Action TX
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: Pointer to pending frame or %NULL if no pending operation
+ *
+ * This function can be used to check whether there is a pending Action frame TX
+ * operation. The returned pointer should be used only for checking whether it
+ * is %NULL (no pending frame) or to print the pointer value in debug
+ * information (i.e., the pointer should not be dereferenced).
+ */
+const void * offchannel_pending_action_tx(struct wpa_supplicant *wpa_s)
+{
+ return wpa_s->pending_action_tx;
+}
+
+
+/**
+ * offchannel_clear_pending_action_tx - Clear pending Action frame TX
+ * @wpa_s: Pointer to wpa_supplicant data
+ */
+void offchannel_clear_pending_action_tx(struct wpa_supplicant *wpa_s)
{
wpabuf_free(wpa_s->pending_action_tx);
wpa_s->pending_action_tx = NULL;
+}
+
+
+/**
+ * offchannel_deinit - Deinit off-channel operations
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function is used to free up any allocated resources for off-channel
+ * operations.
+ */
+void offchannel_deinit(struct wpa_supplicant *wpa_s)
+{
+ offchannel_clear_pending_action_tx(wpa_s);
eloop_cancel_timeout(wpas_send_action_cb, wpa_s, NULL);
}
diff --git a/wpa_supplicant/offchannel.h b/wpa_supplicant/offchannel.h
index 1d3948c..0ad7e18 100644
--- a/wpa_supplicant/offchannel.h
+++ b/wpa_supplicant/offchannel.h
@@ -29,5 +29,7 @@
void offchannel_send_action_tx_status(
struct wpa_supplicant *wpa_s, const u8 *dst, const u8 *data,
size_t data_len, enum offchannel_send_action_result result);
+const void * offchannel_pending_action_tx(struct wpa_supplicant *wpa_s);
+void offchannel_clear_pending_action_tx(struct wpa_supplicant *wpa_s);
#endif /* OFFCHANNEL_H */
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index ca110dc..4b505b5 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -89,14 +89,28 @@
static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr,
const u8 *dev_addr, enum p2p_wps_method wps_method,
int auto_join);
-static void wpas_p2p_pd_before_join_timeout(void *eloop_ctx,
- void *timeout_ctx);
static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s);
static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s);
static void wpas_p2p_group_idle_timeout(void *eloop_ctx, void *timeout_ctx);
static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s);
+static void wpas_p2p_group_formation_timeout(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_set_own_freq_preference(struct wpa_supplicant *wpa_s,
+ int freq)
+{
+ if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+ return;
+ if (freq > 0 &&
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) &&
+ wpa_s->parent->conf->p2p_ignore_shared_freq)
+ freq = 0;
+ p2p_set_own_freq_preference(wpa_s->global->p2p, freq);
+}
static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
@@ -112,8 +126,12 @@
for (i = 0; i < scan_res->num; i++) {
struct wpa_scan_res *bss = scan_res->res[i];
+ struct os_time time_tmp_age, entry_ts;
+ time_tmp_age.sec = bss->age / 1000;
+ time_tmp_age.usec = (bss->age % 1000) * 1000;
+ os_time_sub(&scan_res->fetch_time, &time_tmp_age, &entry_ts);
if (p2p_scan_res_handler(wpa_s->global->p2p, bss->bssid,
- bss->freq, bss->level,
+ bss->freq, &entry_ts, bss->level,
(const u8 *) (bss + 1),
bss->ie_len) > 0)
break;
@@ -140,6 +158,7 @@
for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
if (ifs->sta_scan_pending &&
+ (wpas_scan_scheduled(ifs) || ifs->scanning) &&
wpas_p2p_in_progress(wpa_s) == 2) {
wpa_printf(MSG_DEBUG, "Delaying P2P scan to allow "
"pending station mode scan to be "
@@ -209,8 +228,10 @@
break;
}
}
- } else
+ } else {
+ os_get_time(&wpa_s->scan_trigger_time);
wpa_s->scan_res_handler = wpas_p2p_scan_res_handler;
+ }
return ret;
}
@@ -334,6 +355,12 @@
if (eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL) > 0)
wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group idle timeout");
+ if (eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+ wpa_s->parent, NULL) > 0) {
+ wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group formation "
+ "timeout");
+ wpa_s->p2p_in_provisioning = 0;
+ }
if (removal_reason != P2P_GROUP_REMOVAL_SILENT && ssid)
wpas_notify_p2p_group_removed(wpa_s, ssid, gtype);
@@ -746,19 +773,13 @@
if (result != OFFCHANNEL_SEND_ACTION_SUCCESS &&
wpa_s->pending_pd_before_join &&
(os_memcmp(dst, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 ||
- os_memcmp(dst, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0)) {
+ os_memcmp(dst, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0) &&
+ wpa_s->p2p_fallback_to_go_neg) {
wpa_s->pending_pd_before_join = 0;
- if (wpa_s->p2p_fallback_to_go_neg) {
- wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No ACK for PD Req "
- "during p2p_connect-auto");
- wpas_p2p_fallback_to_go_neg(wpa_s, 0);
- return;
- }
-
- wpa_printf(MSG_DEBUG, "P2P: Starting pending "
- "join-existing-group operation (no ACK for PD "
- "Req)");
- wpas_p2p_join_start(wpa_s);
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No ACK for PD Req "
+ "during p2p_connect-auto");
+ wpas_p2p_fallback_to_go_neg(wpa_s, 0);
+ return;
}
}
@@ -827,15 +848,28 @@
wpa_printf(MSG_DEBUG, "P2P: Group setup without provisioning");
if (wpa_s->global->p2p_group_formation == wpa_s)
wpa_s->global->p2p_group_formation = NULL;
- wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
- "%s GO ssid=\"%s\" freq=%d passphrase=\"%s\" "
- "go_dev_addr=" MACSTR "%s",
- wpa_s->ifname,
- wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
- ssid->frequency,
- params->passphrase ? params->passphrase : "",
- MAC2STR(wpa_s->global->p2p_dev_addr),
- params->persistent_group ? " [PERSISTENT]" : "");
+ if (os_strlen(params->passphrase) > 0) {
+ wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
+ "%s GO ssid=\"%s\" freq=%d passphrase=\"%s\" "
+ "go_dev_addr=" MACSTR "%s", wpa_s->ifname,
+ wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
+ ssid->frequency, params->passphrase,
+ MAC2STR(wpa_s->global->p2p_dev_addr),
+ params->persistent_group ? " [PERSISTENT]" :
+ "");
+ } else {
+ char psk[65];
+ wpa_snprintf_hex(psk, sizeof(psk), params->psk,
+ sizeof(params->psk));
+ wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
+ "%s GO ssid=\"%s\" freq=%d psk=%s "
+ "go_dev_addr=" MACSTR "%s", wpa_s->ifname,
+ wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
+ ssid->frequency, psk,
+ MAC2STR(wpa_s->global->p2p_dev_addr),
+ params->persistent_group ? " [PERSISTENT]" :
+ "");
+ }
if (params->persistent_group)
network_id = wpas_p2p_store_persistent_group(
@@ -861,7 +895,7 @@
params->peer_device_addr);
else if (wpa_s->p2p_pin[0])
wpa_supplicant_ap_wps_pin(wpa_s, params->peer_interface_addr,
- wpa_s->p2p_pin, NULL, 0);
+ wpa_s->p2p_pin, NULL, 0, 0);
os_free(wpa_s->go_params);
wpa_s->go_params = NULL;
}
@@ -905,14 +939,21 @@
ssid->key_mgmt = WPA_KEY_MGMT_PSK;
ssid->proto = WPA_PROTO_RSN;
ssid->pairwise_cipher = WPA_CIPHER_CCMP;
- ssid->passphrase = os_strdup(params->passphrase);
- if (ssid->passphrase == NULL) {
- wpa_msg(wpa_s, MSG_ERROR, "P2P: Failed to copy passphrase for "
- "GO");
- wpa_config_remove_network(wpa_s->conf, ssid->id);
- return;
- }
- wpa_config_update_psk(ssid);
+ if (os_strlen(params->passphrase) > 0) {
+ ssid->passphrase = os_strdup(params->passphrase);
+ if (ssid->passphrase == NULL) {
+ wpa_msg(wpa_s, MSG_ERROR, "P2P: Failed to copy "
+ "passphrase for GO");
+ wpa_config_remove_network(wpa_s->conf, ssid->id);
+ return;
+ }
+ } else
+ ssid->passphrase = NULL;
+ ssid->psk_set = params->psk_set;
+ if (ssid->psk_set)
+ os_memcpy(ssid->psk, params->psk, sizeof(ssid->psk));
+ else if (ssid->passphrase)
+ wpa_config_update_psk(ssid);
ssid->ap_max_inactivity = wpa_s->parent->conf->p2p_go_max_inactivity;
wpa_s->ap_configured_cb = p2p_go_configured;
@@ -955,6 +996,7 @@
d->persistent_reconnect = s->persistent_reconnect;
d->max_num_sta = s->max_num_sta;
d->pbc_in_m1 = s->pbc_in_m1;
+ d->ignore_old_scan_res = s->ignore_old_scan_res;
}
@@ -1268,6 +1310,135 @@
}
+/*
+ * DNS Header section is used only to calculate compression pointers, so the
+ * contents of this data does not matter, but the length needs to be reserved
+ * in the virtual packet.
+ */
+#define DNS_HEADER_LEN 12
+
+/*
+ * 27-octet in-memory packet from P2P specification containing two implied
+ * queries for _tcp.lcoal. PTR IN and _udp.local. PTR IN
+ */
+#define P2P_SD_IN_MEMORY_LEN 27
+
+static int p2p_sd_dns_uncompress_label(char **upos, char *uend, u8 *start,
+ u8 **spos, const u8 *end)
+{
+ while (*spos < end) {
+ u8 val = ((*spos)[0] & 0xc0) >> 6;
+ int len;
+
+ if (val == 1 || val == 2) {
+ /* These are reserved values in RFC 1035 */
+ wpa_printf(MSG_DEBUG, "P2P: Invalid domain name "
+ "sequence starting with 0x%x", val);
+ return -1;
+ }
+
+ if (val == 3) {
+ u16 offset;
+ u8 *spos_tmp;
+
+ /* Offset */
+ if (*spos + 2 > end) {
+ wpa_printf(MSG_DEBUG, "P2P: No room for full "
+ "DNS offset field");
+ return -1;
+ }
+
+ offset = (((*spos)[0] & 0x3f) << 8) | (*spos)[1];
+ if (offset >= *spos - start) {
+ wpa_printf(MSG_DEBUG, "P2P: Invalid DNS "
+ "pointer offset %u", offset);
+ return -1;
+ }
+
+ (*spos) += 2;
+ spos_tmp = start + offset;
+ return p2p_sd_dns_uncompress_label(upos, uend, start,
+ &spos_tmp,
+ *spos - 2);
+ }
+
+ /* Label */
+ len = (*spos)[0] & 0x3f;
+ if (len == 0)
+ return 0;
+
+ (*spos)++;
+ if (*spos + len > end) {
+ wpa_printf(MSG_DEBUG, "P2P: Invalid domain name "
+ "sequence - no room for label with length "
+ "%u", len);
+ return -1;
+ }
+
+ if (*upos + len + 2 > uend)
+ return -2;
+
+ os_memcpy(*upos, *spos, len);
+ *spos += len;
+ *upos += len;
+ (*upos)[0] = '.';
+ (*upos)++;
+ (*upos)[0] = '\0';
+ }
+
+ return 0;
+}
+
+
+/* Uncompress domain names per RFC 1035 using the P2P SD in-memory packet.
+ * Returns -1 on parsing error (invalid input sequence), -2 if output buffer is
+ * not large enough */
+static int p2p_sd_dns_uncompress(char *buf, size_t buf_len, const u8 *msg,
+ size_t msg_len, size_t offset)
+{
+ /* 27-octet in-memory packet from P2P specification */
+ const char *prefix = "\x04_tcp\x05local\x00\x00\x0C\x00\x01"
+ "\x04_udp\xC0\x11\x00\x0C\x00\x01";
+ u8 *tmp, *end, *spos;
+ char *upos, *uend;
+ int ret = 0;
+
+ if (buf_len < 2)
+ return -1;
+ if (offset > msg_len)
+ return -1;
+
+ tmp = os_malloc(DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN + msg_len);
+ if (tmp == NULL)
+ return -1;
+ spos = tmp + DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN;
+ end = spos + msg_len;
+ spos += offset;
+
+ os_memset(tmp, 0, DNS_HEADER_LEN);
+ os_memcpy(tmp + DNS_HEADER_LEN, prefix, P2P_SD_IN_MEMORY_LEN);
+ os_memcpy(tmp + DNS_HEADER_LEN + P2P_SD_IN_MEMORY_LEN, msg, msg_len);
+
+ upos = buf;
+ uend = buf + buf_len;
+
+ ret = p2p_sd_dns_uncompress_label(&upos, uend, tmp, &spos, end);
+ if (ret) {
+ os_free(tmp);
+ return ret;
+ }
+
+ if (upos == buf) {
+ upos[0] = '.';
+ upos[1] = '\0';
+ } else if (upos[-1] == '.')
+ upos[-1] = '\0';
+
+ os_free(tmp);
+ return 0;
+}
+
+
static struct p2p_srv_bonjour *
wpas_p2p_service_get_bonjour(struct wpa_supplicant *wpa_s,
const struct wpabuf *query)
@@ -1358,13 +1529,40 @@
}
+static int match_bonjour_query(struct p2p_srv_bonjour *bsrv, const u8 *query,
+ size_t query_len)
+{
+ char str_rx[256], str_srv[256];
+
+ if (query_len < 3 || wpabuf_len(bsrv->query) < 3)
+ return 0; /* Too short to include DNS Type and Version */
+ if (os_memcmp(query + query_len - 3,
+ wpabuf_head_u8(bsrv->query) + wpabuf_len(bsrv->query) - 3,
+ 3) != 0)
+ return 0; /* Mismatch in DNS Type or Version */
+ if (query_len == wpabuf_len(bsrv->query) &&
+ os_memcmp(query, wpabuf_head(bsrv->query), query_len - 3) == 0)
+ return 1; /* Binary match */
+
+ if (p2p_sd_dns_uncompress(str_rx, sizeof(str_rx), query, query_len - 3,
+ 0))
+ return 0; /* Failed to uncompress query */
+ if (p2p_sd_dns_uncompress(str_srv, sizeof(str_srv),
+ wpabuf_head(bsrv->query),
+ wpabuf_len(bsrv->query) - 3, 0))
+ return 0; /* Failed to uncompress service */
+
+ return os_strcmp(str_rx, str_srv) == 0;
+}
+
+
static void wpas_sd_req_bonjour(struct wpa_supplicant *wpa_s,
struct wpabuf *resp, u8 srv_trans_id,
const u8 *query, size_t query_len)
{
struct p2p_srv_bonjour *bsrv;
- struct wpabuf buf;
u8 *len_pos;
+ int matches = 0;
wpa_hexdump_ascii(MSG_DEBUG, "P2P: SD Request for Bonjour",
query, query_len);
@@ -1380,39 +1578,52 @@
return;
}
- if (wpabuf_tailroom(resp) < 5)
- return;
- /* Length (to be filled) */
- len_pos = wpabuf_put(resp, 2);
- wpabuf_put_u8(resp, P2P_SERV_BONJOUR);
- wpabuf_put_u8(resp, srv_trans_id);
+ dl_list_for_each(bsrv, &wpa_s->global->p2p_srv_bonjour,
+ struct p2p_srv_bonjour, list) {
+ if (!match_bonjour_query(bsrv, query, query_len))
+ continue;
- wpabuf_set(&buf, query, query_len);
- bsrv = wpas_p2p_service_get_bonjour(wpa_s, &buf);
- if (bsrv == NULL) {
+ if (wpabuf_tailroom(resp) <
+ 5 + query_len + wpabuf_len(bsrv->resp))
+ return;
+
+ matches++;
+
+ /* Length (to be filled) */
+ len_pos = wpabuf_put(resp, 2);
+ wpabuf_put_u8(resp, P2P_SERV_BONJOUR);
+ wpabuf_put_u8(resp, srv_trans_id);
+
+ /* Status Code */
+ wpabuf_put_u8(resp, P2P_SD_SUCCESS);
+ wpa_hexdump_ascii(MSG_DEBUG, "P2P: Matching Bonjour service",
+ wpabuf_head(bsrv->resp),
+ wpabuf_len(bsrv->resp));
+
+ /* Response Data */
+ wpabuf_put_data(resp, query, query_len); /* Key */
+ wpabuf_put_buf(resp, bsrv->resp); /* Value */
+
+ WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
+ }
+
+ if (matches == 0) {
wpa_printf(MSG_DEBUG, "P2P: Requested Bonjour service not "
"available");
+ if (wpabuf_tailroom(resp) < 5)
+ return;
+
+ /* Length (to be filled) */
+ len_pos = wpabuf_put(resp, 2);
+ wpabuf_put_u8(resp, P2P_SERV_BONJOUR);
+ wpabuf_put_u8(resp, srv_trans_id);
/* Status Code */
wpabuf_put_u8(resp, P2P_SD_REQUESTED_INFO_NOT_AVAILABLE);
/* Response Data: empty */
WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos -
2);
- return;
}
-
- /* Status Code */
- wpabuf_put_u8(resp, P2P_SD_SUCCESS);
- wpa_hexdump_ascii(MSG_DEBUG, "P2P: Matching Bonjour service",
- wpabuf_head(bsrv->resp), wpabuf_len(bsrv->resp));
-
- if (wpabuf_tailroom(resp) >=
- wpabuf_len(bsrv->query) + wpabuf_len(bsrv->resp)) {
- /* Response Data */
- wpabuf_put_buf(resp, bsrv->query); /* Key */
- wpabuf_put_buf(resp, bsrv->resp); /* Value */
- }
- WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
}
@@ -1973,14 +2184,6 @@
{
struct p2p_srv_bonjour *bsrv;
- bsrv = wpas_p2p_service_get_bonjour(wpa_s, query);
- if (bsrv) {
- wpabuf_free(query);
- wpabuf_free(bsrv->resp);
- bsrv->resp = resp;
- return 0;
- }
-
bsrv = os_zalloc(sizeof(*bsrv));
if (bsrv == NULL)
return -1;
@@ -2185,18 +2388,15 @@
return;
}
-#ifdef ANDROID_P2P
- /* If provision discovery failed it is safe to cancel the timer here and
- * also do not start the join */
- if (wpa_s->pending_pd_before_join &&
- (os_memcmp(peer, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 ||
- os_memcmp(peer, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0)) {
+ if (status == P2P_PROV_DISC_TIMEOUT_JOIN) {
wpa_s->pending_pd_before_join = 0;
- wpa_printf(MSG_DEBUG, "P2P: Do not Start pending "
- "join-existing-group operation");
- eloop_cancel_timeout(wpas_p2p_pd_before_join_timeout, wpa_s, NULL);
+ wpa_printf(MSG_DEBUG, "P2P: Starting pending "
+ "join-existing-group operation (no ACK for PD "
+ "Req attempts)");
+ wpas_p2p_join_start(wpa_s);
+ return;
}
-#endif /* ANDROID_P2P */
+
wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
" p2p_dev_addr=" MACSTR " status=%d",
MAC2STR(peer), status);
@@ -2244,7 +2444,11 @@
goto accept_inv;
}
- if (!wpa_s->conf->persistent_reconnect)
+ if (!is_zero_ether_addr(wpa_s->p2p_auth_invite) &&
+ os_memcmp(sa, wpa_s->p2p_auth_invite, ETH_ALEN) == 0) {
+ wpa_printf(MSG_DEBUG, "P2P: Accept previously initiated "
+ "invitation to re-invoke a persistent group");
+ } else if (!wpa_s->conf->persistent_reconnect)
return P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
for (s = wpa_s->conf->ssid; s; s = s->next) {
@@ -2284,11 +2488,14 @@
}
accept_inv:
+ wpas_p2p_set_own_freq_preference(wpa_s, 0);
+
if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, cur_bssid) == 0 &&
wpa_s->assoc_freq) {
wpa_printf(MSG_DEBUG, "P2P: Trying to force channel to match "
"the channel we are already using");
*force_freq = wpa_s->assoc_freq;
+ wpas_p2p_set_own_freq_preference(wpa_s, wpa_s->assoc_freq);
}
res = wpa_drv_shared_freq(wpa_s);
@@ -2297,6 +2504,7 @@
"with the channel we are already using on a "
"shared interface");
*force_freq = res;
+ wpas_p2p_set_own_freq_preference(wpa_s, res);
}
return P2P_SC_SUCCESS;
@@ -2325,8 +2533,9 @@
if (s) {
int go = s->mode == WPAS_MODE_P2P_GO;
wpas_p2p_group_add_persistent(
- wpa_s, s, go, go ? op_freq : 0, 0);
+ wpa_s, s, go, go ? op_freq : 0, 0, NULL);
} else if (bssid) {
+ wpa_s->user_initiated_pd = 0;
wpas_p2p_join(wpa_s, bssid, go_dev_addr,
wpa_s->p2p_wps_method, 0);
}
@@ -2355,12 +2564,79 @@
return;
}
- wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RECEIVED "sa=" MACSTR
- " persistent=%d", MAC2STR(sa), s->id);
+ if (s->mode == WPAS_MODE_P2P_GO && op_freq) {
+ wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RECEIVED "sa="
+ MACSTR " persistent=%d freq=%d",
+ MAC2STR(sa), s->id, op_freq);
+ } else {
+ wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RECEIVED "sa="
+ MACSTR " persistent=%d", MAC2STR(sa), s->id);
+ }
}
-static void wpas_invitation_result(void *ctx, int status, const u8 *bssid)
+static void wpas_remove_persistent_peer(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ const u8 *peer)
+{
+ size_t i;
+
+ if (ssid == NULL)
+ return;
+
+ for (i = 0; ssid->p2p_client_list && i < ssid->num_p2p_clients; i++) {
+ if (os_memcmp(ssid->p2p_client_list + i * ETH_ALEN, peer,
+ ETH_ALEN) == 0)
+ break;
+ }
+ if (i >= ssid->num_p2p_clients) {
+ if (ssid->mode != WPAS_MODE_P2P_GO &&
+ os_memcmp(ssid->bssid, peer, ETH_ALEN) == 0) {
+ wpa_printf(MSG_DEBUG, "P2P: Remove persistent group %d "
+ "due to invitation result", ssid->id);
+ wpas_notify_network_removed(wpa_s, ssid);
+ wpa_config_remove_network(wpa_s->conf, ssid->id);
+ return;
+ }
+ return; /* Peer not found in client list */
+ }
+
+ wpa_printf(MSG_DEBUG, "P2P: Remove peer " MACSTR " from persistent "
+ "group %d client list due to invitation result",
+ MAC2STR(peer), ssid->id);
+ os_memmove(ssid->p2p_client_list + i * ETH_ALEN,
+ ssid->p2p_client_list + (i + 1) * ETH_ALEN,
+ (ssid->num_p2p_clients - i - 1) * ETH_ALEN);
+ ssid->num_p2p_clients--;
+#ifndef CONFIG_NO_CONFIG_WRITE
+ if (wpa_s->parent->conf->update_config &&
+ wpa_config_write(wpa_s->parent->confname, wpa_s->parent->conf))
+ wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
+#endif /* CONFIG_NO_CONFIG_WRITE */
+}
+
+
+static void wpas_remove_persistent_client(struct wpa_supplicant *wpa_s,
+ const u8 *peer)
+{
+ struct wpa_ssid *ssid;
+
+ wpa_s = wpa_s->global->p2p_invite_group;
+ if (wpa_s == NULL)
+ return; /* No known invitation group */
+ ssid = wpa_s->current_ssid;
+ if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO ||
+ !ssid->p2p_persistent_group)
+ return; /* Not operating as a GO in persistent group */
+ ssid = wpas_p2p_get_persistent(wpa_s->parent, peer,
+ ssid->ssid, ssid->ssid_len);
+ wpas_remove_persistent_peer(wpa_s, ssid, peer);
+}
+
+
+static void wpas_invitation_result(void *ctx, int status, const u8 *bssid,
+ const struct p2p_channels *channels,
+ const u8 *peer)
{
struct wpa_supplicant *wpa_s = ctx;
struct wpa_ssid *ssid;
@@ -2375,10 +2651,26 @@
}
wpas_notify_p2p_invitation_result(wpa_s, status, bssid);
- if (wpa_s->pending_invite_ssid_id == -1)
+ wpa_printf(MSG_DEBUG, "P2P: Invitation result - status=%d peer=" MACSTR,
+ status, MAC2STR(peer));
+ if (wpa_s->pending_invite_ssid_id == -1) {
+ if (status == P2P_SC_FAIL_UNKNOWN_GROUP)
+ wpas_remove_persistent_client(wpa_s, peer);
return; /* Invitation to active group */
+ }
+
+ if (status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
+ wpa_printf(MSG_DEBUG, "P2P: Waiting for peer to start another "
+ "invitation exchange to indicate readiness for "
+ "re-invocation");
+ }
if (status != P2P_SC_SUCCESS) {
+ if (status == P2P_SC_FAIL_UNKNOWN_GROUP) {
+ ssid = wpa_config_get_network(
+ wpa_s->conf, wpa_s->pending_invite_ssid_id);
+ wpas_remove_persistent_peer(wpa_s, ssid, peer);
+ }
wpas_p2p_remove_pending_group_interface(wpa_s);
return;
}
@@ -2412,7 +2704,7 @@
wpas_p2p_group_add_persistent(wpa_s, ssid,
ssid->mode == WPAS_MODE_P2P_GO,
wpa_s->p2p_persistent_go_freq,
- wpa_s->p2p_go_ht40);
+ wpa_s->p2p_go_ht40, channels);
}
@@ -2839,6 +3131,8 @@
p2p.p2p_intra_bss = wpa_s->conf->p2p_intra_bss;
+ p2p.max_listen = wpa_s->max_remain_on_chan;
+
#ifdef ANDROID_P2P
if(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) {
p2p.p2p_concurrency = P2P_MULTI_CHANNEL_CONCURRENT;
@@ -2888,7 +3182,6 @@
wpa_s->go_params = NULL;
eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
- eloop_cancel_timeout(wpas_p2p_pd_before_join_timeout, wpa_s, NULL);
wpa_s->p2p_long_listen = 0;
eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
@@ -2949,6 +3242,8 @@
static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s)
{
+ if (wpa_s->conf->p2p_no_group_iface)
+ return 0; /* separate interface disabled per configuration */
if (wpa_s->drv_flags &
(WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE |
WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P))
@@ -2969,7 +3264,7 @@
enum p2p_wps_method wps_method,
int go_intent, const u8 *own_interface_addr,
unsigned int force_freq, int persistent_group,
- struct wpa_ssid *ssid)
+ struct wpa_ssid *ssid, unsigned int pref_freq)
{
if (persistent_group && wpa_s->conf->persistent_reconnect)
persistent_group = 2;
@@ -2991,7 +3286,7 @@
go_intent, own_interface_addr, force_freq,
persistent_group, ssid ? ssid->ssid : NULL,
ssid ? ssid->ssid_len : 0,
- wpa_s->p2p_pd_before_go_neg);
+ wpa_s->p2p_pd_before_go_neg, pref_freq);
}
@@ -3000,7 +3295,7 @@
enum p2p_wps_method wps_method,
int go_intent, const u8 *own_interface_addr,
unsigned int force_freq, int persistent_group,
- struct wpa_ssid *ssid)
+ struct wpa_ssid *ssid, unsigned int pref_freq)
{
if (persistent_group && wpa_s->conf->persistent_reconnect)
persistent_group = 2;
@@ -3011,7 +3306,7 @@
return p2p_authorize(wpa_s->global->p2p, peer_addr, wps_method,
go_intent, own_interface_addr, force_freq,
persistent_group, ssid ? ssid->ssid : NULL,
- ssid ? ssid->ssid_len : 0);
+ ssid ? ssid->ssid_len : 0, pref_freq);
}
@@ -3038,21 +3333,6 @@
}
-static void wpas_p2p_pd_before_join_timeout(void *eloop_ctx, void *timeout_ctx)
-{
- struct wpa_supplicant *wpa_s = eloop_ctx;
- if (!wpa_s->pending_pd_before_join)
- return;
- /*
- * Provision Discovery Response may have been lost - try to connect
- * anyway since we do not need any information from this PD.
- */
- wpa_printf(MSG_DEBUG, "P2P: PD timeout for join-existing-group - "
- "try to connect anyway");
- wpas_p2p_join_start(wpa_s);
-}
-
-
static int wpas_check_freq_conflict(struct wpa_supplicant *wpa_s, int freq)
{
struct wpa_supplicant *iface;
@@ -3145,8 +3425,8 @@
if (join == 0 &&
wpa_s->auto_pd_scan_retry < P2P_AUTO_PD_SCAN_ATTEMPTS) {
wpa_s->auto_pd_scan_retry++;
- bss = wpa_bss_get_bssid(wpa_s,
- wpa_s->pending_join_dev_addr);
+ bss = wpa_bss_get_bssid_latest(
+ wpa_s, wpa_s->pending_join_dev_addr);
if (bss) {
freq = bss->freq;
wpa_printf(MSG_DEBUG, "P2P: Scan retry %d for "
@@ -3170,7 +3450,7 @@
if (p2p_prov_disc_req(wpa_s->global->p2p,
wpa_s->pending_join_dev_addr,
wpa_s->pending_pd_config_methods, join,
- 0) < 0) {
+ 0, wpa_s->user_initiated_pd) < 0) {
wpa_s->p2p_auto_pd = 0;
wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
" p2p_dev_addr=" MACSTR " status=N/A",
@@ -3226,7 +3506,7 @@
wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
"from P2P peer table: %d MHz", freq);
}
- bss = wpa_bss_get_bssid(wpa_s, wpa_s->pending_join_iface_addr);
+ bss = wpa_bss_get_bssid_latest(wpa_s, wpa_s->pending_join_iface_addr);
if (bss) {
freq = bss->freq;
wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
@@ -3280,25 +3560,13 @@
if (p2p_prov_disc_req(wpa_s->global->p2p,
wpa_s->pending_join_dev_addr, method, 1,
- freq) < 0) {
+ freq, wpa_s->user_initiated_pd) < 0) {
wpa_printf(MSG_DEBUG, "P2P: Failed to send Provision "
"Discovery Request before joining an "
"existing group");
wpa_s->pending_pd_before_join = 0;
goto start;
}
-
- /*
- * Actual join operation will be started from the Action frame
- * TX status callback (if no ACK is received) or when the
- * Provision Discovery Response is received. Use a short
- * timeout as a backup mechanism should the Provision Discovery
- * Response be lost for any reason.
- */
- eloop_cancel_timeout(wpas_p2p_pd_before_join_timeout, wpa_s,
- NULL);
- eloop_register_timeout(2, 0, wpas_p2p_pd_before_join_timeout,
- wpa_s, NULL);
return;
}
@@ -3373,8 +3641,10 @@
* the new scan results become available.
*/
ret = wpa_drv_scan(wpa_s, ¶ms);
- if (!ret)
+ if (!ret) {
+ os_get_time(&wpa_s->scan_trigger_time);
wpa_s->scan_res_handler = wpas_p2p_scan_res_join;
+ }
wpabuf_free(ies);
@@ -3425,7 +3695,6 @@
struct p2p_go_neg_results res;
struct wpa_bss *bss;
- eloop_cancel_timeout(wpas_p2p_pd_before_join_timeout, wpa_s, NULL);
group = wpas_p2p_get_group_iface(wpa_s, 0, 0);
if (group == NULL)
return -1;
@@ -3433,6 +3702,15 @@
os_memcpy(group->p2p_pin, wpa_s->p2p_pin,
sizeof(group->p2p_pin));
group->p2p_wps_method = wpa_s->p2p_wps_method;
+ } else {
+ /*
+ * Need to mark the current interface for p2p_group_formation
+ * when a separate group interface is not used. This is needed
+ * to allow p2p_cancel stop a pending p2p_connect-join.
+ * wpas_p2p_init_group_interface() addresses this for the case
+ * where a separate group interface is used.
+ */
+ wpa_s->global->p2p_group_formation = wpa_s;
}
group->p2p_in_provisioning = 1;
@@ -3442,7 +3720,7 @@
os_memcpy(res.peer_interface_addr, wpa_s->pending_join_iface_addr,
ETH_ALEN);
res.wps_method = wpa_s->pending_join_wps_method;
- bss = wpa_bss_get_bssid(wpa_s, wpa_s->pending_join_iface_addr);
+ bss = wpa_bss_get_bssid_latest(wpa_s, wpa_s->pending_join_iface_addr);
if (bss) {
res.freq = bss->freq;
res.ssid_len = bss->ssid_len;
@@ -3471,6 +3749,60 @@
}
+static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq,
+ int *force_freq, int *pref_freq,
+ int *oper_freq)
+{
+ if (freq > 0) {
+ if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
+ wpa_printf(MSG_DEBUG, "P2P: The forced channel "
+ "(%u MHz) is not supported for P2P uses",
+ freq);
+ return -3;
+ }
+
+ if (*oper_freq > 0 && freq != *oper_freq &&
+ !(wpa_s->drv_flags &
+ WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
+ wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group "
+ "on %u MHz while connected on another "
+ "channel (%u MHz)", freq, *oper_freq);
+ return -2;
+ }
+ wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
+ "requested channel (%u MHz)", freq);
+ *force_freq = freq;
+ } else if (*oper_freq > 0 &&
+ !p2p_supported_freq(wpa_s->global->p2p, *oper_freq)) {
+ if (!(wpa_s->drv_flags &
+ WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
+ wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group "
+ "while connected on non-P2P supported "
+ "channel (%u MHz)", *oper_freq);
+ return -2;
+ }
+ wpa_printf(MSG_DEBUG, "P2P: Current operating channel "
+ "(%u MHz) not available for P2P - try to use "
+ "another channel", *oper_freq);
+ *force_freq = 0;
+ } else if (*oper_freq > 0 && *pref_freq == 0 &&
+ (wpa_s->drv_flags &
+ WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
+ wpa_printf(MSG_DEBUG, "P2P: Trying to prefer the channel we "
+ "are already using (%u MHz) on another interface",
+ *oper_freq);
+ *pref_freq = *oper_freq;
+ } else if (*oper_freq > 0) {
+ wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
+ "channel we are already using (%u MHz) on another "
+ "interface", *oper_freq);
+ *force_freq = *oper_freq;
+ }
+
+ return 0;
+}
+
+
/**
* wpas_p2p_connect - Request P2P Group Formation to be started
* @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface()
@@ -3499,9 +3831,9 @@
int go_intent, int freq, int persistent_id, int pd,
int ht40)
{
- int force_freq = 0, oper_freq = 0;
+ int force_freq = 0, pref_freq = 0, oper_freq = 0;
u8 bssid[ETH_ALEN];
- int ret = 0;
+ int ret = 0, res;
enum wpa_driver_if_type iftype;
const u8 *if_addr;
struct wpa_ssid *ssid = NULL;
@@ -3565,6 +3897,7 @@
wpa_s->p2p_auto_started.sec,
wpa_s->p2p_auto_started.usec);
}
+ wpa_s->user_initiated_pd = 1;
if (wpas_p2p_join(wpa_s, iface_addr, dev_addr, wps_method,
auto_join) < 0)
return -1;
@@ -3572,52 +3905,19 @@
}
if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid) == 0 &&
- wpa_s->assoc_freq)
+ wpa_s->assoc_freq) {
oper_freq = wpa_s->assoc_freq;
- else {
+ } else {
oper_freq = wpa_drv_shared_freq(wpa_s);
if (oper_freq < 0)
oper_freq = 0;
}
- if (freq > 0) {
- if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
- wpa_printf(MSG_DEBUG, "P2P: The forced channel "
- "(%u MHz) is not supported for P2P uses",
- freq);
- return -3;
- }
-
- if (oper_freq > 0 && freq != oper_freq &&
- !(wpa_s->drv_flags &
- WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
- wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group "
- "on %u MHz while connected on another "
- "channel (%u MHz)", freq, oper_freq);
- return -2;
- }
- wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
- "requested channel (%u MHz)", freq);
- force_freq = freq;
- } else if (oper_freq > 0 &&
- !p2p_supported_freq(wpa_s->global->p2p, oper_freq)) {
- if (!(wpa_s->drv_flags &
- WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
- wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group "
- "while connected on non-P2P supported "
- "channel (%u MHz)", oper_freq);
- return -2;
- }
- wpa_printf(MSG_DEBUG, "P2P: Current operating channel "
- "(%u MHz) not available for P2P - try to use "
- "another channel", oper_freq);
- force_freq = 0;
- } else if (oper_freq > 0) {
- wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
- "channel we are already using (%u MHz) on another "
- "interface", oper_freq);
- force_freq = oper_freq;
- }
+ res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq,
+ &oper_freq);
+ if (res)
+ return res;
+ wpas_p2p_set_own_freq_preference(wpa_s, oper_freq);
wpa_s->create_p2p_iface = wpas_p2p_create_iface(wpa_s);
@@ -3639,15 +3939,15 @@
if (auth) {
if (wpas_p2p_auth_go_neg(wpa_s, peer_addr, wps_method,
go_intent, if_addr,
- force_freq, persistent_group, ssid) <
- 0)
+ force_freq, persistent_group, ssid,
+ pref_freq) < 0)
return -1;
return ret;
}
if (wpas_p2p_start_go_neg(wpa_s, peer_addr, wps_method,
go_intent, if_addr, force_freq,
- persistent_group, ssid) < 0) {
+ persistent_group, ssid, pref_freq) < 0) {
if (wpa_s->create_p2p_iface)
wpas_p2p_remove_pending_group_interface(wpa_s);
return -1;
@@ -3706,12 +4006,12 @@
{
wpa_printf(MSG_DEBUG, "P2P: Cancel remain-on-channel callback "
"(p2p_long_listen=%d ms pending_action_tx=%p)",
- wpa_s->p2p_long_listen, wpa_s->pending_action_tx);
+ wpa_s->p2p_long_listen, offchannel_pending_action_tx(wpa_s));
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return;
if (p2p_listen_end(wpa_s->global->p2p, freq) > 0)
return; /* P2P module started a new operation */
- if (wpa_s->pending_action_tx)
+ if (offchannel_pending_action_tx(wpa_s))
return;
if (wpa_s->p2p_long_listen > 0)
wpa_s->p2p_long_listen -= wpa_s->max_remain_on_chan;
@@ -3759,9 +4059,18 @@
}
+static int freq_included(const struct p2p_channels *channels, unsigned int freq)
+{
+ if (channels == NULL)
+ return 1; /* Assume no restrictions */
+ return p2p_channels_includes_freq(channels, freq);
+}
+
+
static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
struct p2p_go_neg_results *params,
- int freq, int ht40)
+ int freq, int ht40,
+ const struct p2p_channels *channels)
{
u8 bssid[ETH_ALEN];
int res;
@@ -3770,38 +4079,54 @@
params->role_go = 1;
params->ht40 = ht40;
if (freq) {
+ if (!freq_included(channels, freq)) {
+ wpa_printf(MSG_DEBUG, "P2P: Forced GO freq %d MHz not "
+ "accepted", freq);
+ return -1;
+ }
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on forced "
"frequency %d MHz", freq);
params->freq = freq;
} else if (wpa_s->conf->p2p_oper_reg_class == 81 &&
wpa_s->conf->p2p_oper_channel >= 1 &&
- wpa_s->conf->p2p_oper_channel <= 11) {
+ wpa_s->conf->p2p_oper_channel <= 11 &&
+ freq_included(channels,
+ 2407 + 5 * wpa_s->conf->p2p_oper_channel)) {
params->freq = 2407 + 5 * wpa_s->conf->p2p_oper_channel;
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on configured "
"frequency %d MHz", params->freq);
- } else if (wpa_s->conf->p2p_oper_reg_class == 115 ||
- wpa_s->conf->p2p_oper_reg_class == 124) {
+ } else if ((wpa_s->conf->p2p_oper_reg_class == 115 ||
+ wpa_s->conf->p2p_oper_reg_class == 116 ||
+ wpa_s->conf->p2p_oper_reg_class == 117 ||
+ wpa_s->conf->p2p_oper_reg_class == 124 ||
+ wpa_s->conf->p2p_oper_reg_class == 126 ||
+ wpa_s->conf->p2p_oper_reg_class == 127) &&
+ freq_included(channels,
+ 5000 + 5 * wpa_s->conf->p2p_oper_channel)) {
params->freq = 5000 + 5 * wpa_s->conf->p2p_oper_channel;
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on configured "
"frequency %d MHz", params->freq);
} else if (wpa_s->conf->p2p_oper_channel == 0 &&
wpa_s->best_overall_freq > 0 &&
p2p_supported_freq(wpa_s->global->p2p,
- wpa_s->best_overall_freq)) {
+ wpa_s->best_overall_freq) &&
+ freq_included(channels, wpa_s->best_overall_freq)) {
params->freq = wpa_s->best_overall_freq;
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best overall "
"channel %d MHz", params->freq);
} else if (wpa_s->conf->p2p_oper_channel == 0 &&
wpa_s->best_24_freq > 0 &&
p2p_supported_freq(wpa_s->global->p2p,
- wpa_s->best_24_freq)) {
+ wpa_s->best_24_freq) &&
+ freq_included(channels, wpa_s->best_24_freq)) {
params->freq = wpa_s->best_24_freq;
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 2.4 GHz "
"channel %d MHz", params->freq);
} else if (wpa_s->conf->p2p_oper_channel == 0 &&
wpa_s->best_5_freq > 0 &&
p2p_supported_freq(wpa_s->global->p2p,
- wpa_s->best_5_freq)) {
+ wpa_s->best_5_freq) &&
+ freq_included(channels, wpa_s->best_5_freq)) {
params->freq = wpa_s->best_5_freq;
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 5 GHz "
"channel %d MHz", params->freq);
@@ -3810,7 +4135,8 @@
for (chan = 0; chan < 11; chan++) {
params->freq = 2412 + chan * 5;
if (!wpas_p2p_disallowed_freq(wpa_s->global,
- params->freq))
+ params->freq) &&
+ freq_included(channels, params->freq))
break;
}
if (chan == 11) {
@@ -3824,16 +4150,53 @@
if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid) == 0 &&
wpa_s->assoc_freq && !freq) {
- wpa_printf(MSG_DEBUG, "P2P: Force GO on the channel we are "
- "already using");
- params->freq = wpa_s->assoc_freq;
+ if (!p2p_supported_freq(wpa_s->global->p2p, wpa_s->assoc_freq)
+ || !freq_included(channels, wpa_s->assoc_freq)) {
+ if (wpa_s->drv_flags &
+ WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) {
+ wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on "
+ "the channel we are already using "
+ "(%u MHz) - allow multi-channel "
+ "concurrency", wpa_s->assoc_freq);
+ } else {
+ wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on "
+ "the channel we are already using "
+ "(%u MHz)", wpa_s->assoc_freq);
+ return -1;
+ }
+ } else {
+ wpa_printf(MSG_DEBUG, "P2P: Force GO on the channel we "
+ "are already using (%u MHz)",
+ wpa_s->assoc_freq);
+ params->freq = wpa_s->assoc_freq;
+ }
}
res = wpa_drv_shared_freq(wpa_s);
- if (res > 0 && !freq) {
+ if (res > 0 && !freq &&
+ (!p2p_supported_freq(wpa_s->global->p2p, res) ||
+ !freq_included(channels, res))) {
+ if (wpa_s->drv_flags &
+ WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) {
+ wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on the "
+ "channel we are already using on a shared "
+ "interface (%u MHz) - allow multi-channel "
+ "concurrency", res);
+ } else {
+ wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on the "
+ "channel we are already using on a shared "
+ "interface (%u MHz)", res);
+ return -1;
+ }
+ } else if (res > 0 && !freq) {
wpa_printf(MSG_DEBUG, "P2P: Force GO on the channel we are "
"already using on a shared interface");
params->freq = res;
+ if (!freq_included(channels, params->freq)) {
+ wpa_printf(MSG_DEBUG, "P2P: Forced GO freq %d MHz not "
+ "accepted", params->freq);
+ return -1;
+ }
} else if (res > 0 && freq != res &&
!(wpa_s->drv_flags &
WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
@@ -3899,7 +4262,7 @@
/* Make sure we are not running find during connection establishment */
wpa_printf(MSG_DEBUG, "P2P: Stop any on-going P2P FIND");
- wpas_p2p_stop_find(wpa_s);
+ wpas_p2p_stop_find_oper(wpa_s);
if (freq == 2) {
wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 2.4 GHz "
@@ -3947,7 +4310,7 @@
return -1;
}
- if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq, ht40))
+ if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq, ht40, NULL))
return -1;
if (params.freq &&
!p2p_supported_freq(wpa_s->global->p2p, params.freq)) {
@@ -4014,7 +4377,8 @@
int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, int addr_allocated,
- int freq, int ht40)
+ int freq, int ht40,
+ const struct p2p_channels *channels)
{
struct p2p_go_neg_results params;
int go = 0;
@@ -4030,7 +4394,7 @@
}
/* Make sure we are not running find during connection establishment */
- wpas_p2p_stop_find(wpa_s);
+ wpas_p2p_stop_find_oper(wpa_s);
wpa_s->p2p_fallback_to_go_neg = 0;
@@ -4040,18 +4404,22 @@
if (ssid->mode != WPAS_MODE_P2P_GO)
return -1;
- if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq, ht40))
+ if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq, ht40, channels))
return -1;
params.role_go = 1;
- if (ssid->passphrase == NULL ||
- os_strlen(ssid->passphrase) >= sizeof(params.passphrase)) {
- wpa_printf(MSG_DEBUG, "P2P: Invalid passphrase in persistent "
- "group");
- return -1;
+ params.psk_set = ssid->psk_set;
+ if (params.psk_set)
+ os_memcpy(params.psk, ssid->psk, sizeof(params.psk));
+ if (ssid->passphrase) {
+ if (os_strlen(ssid->passphrase) >= sizeof(params.passphrase)) {
+ wpa_printf(MSG_ERROR, "P2P: Invalid passphrase in "
+ "persistent group");
+ return -1;
+ }
+ os_strlcpy(params.passphrase, ssid->passphrase,
+ sizeof(params.passphrase));
}
- os_strlcpy(params.passphrase, ssid->passphrase,
- sizeof(params.passphrase));
os_memcpy(params.ssid, ssid->ssid, ssid->ssid_len);
params.ssid_len = ssid->ssid_len;
params.persistent_group = 1;
@@ -4253,7 +4621,7 @@
return p2p_prov_disc_req(wpa_s->global->p2p, peer_addr,
config_methods, use == WPAS_P2P_PD_FOR_JOIN,
- 0);
+ 0, 1);
}
@@ -4266,13 +4634,12 @@
static void wpas_p2p_clear_pending_action_tx(struct wpa_supplicant *wpa_s)
{
- if (!wpa_s->pending_action_tx)
+ if (!offchannel_pending_action_tx(wpa_s))
return;
wpa_printf(MSG_DEBUG, "P2P: Drop pending Action TX due to new "
"operation request");
- wpabuf_free(wpa_s->pending_action_tx);
- wpa_s->pending_action_tx = NULL;
+ offchannel_clear_pending_action_tx(wpa_s);
}
@@ -4299,7 +4666,7 @@
}
-void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s)
+static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s)
{
wpas_p2p_clear_pending_action_tx(wpa_s);
wpa_s->p2p_long_listen = 0;
@@ -4309,12 +4676,20 @@
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
wpa_drv_p2p_stop_find(wpa_s);
- return;
+ return 1;
}
if (wpa_s->global->p2p)
p2p_stop_find(wpa_s->global->p2p);
+ return 0;
+}
+
+
+void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s)
+{
+ if (wpas_p2p_stop_find_oper(wpa_s) > 0)
+ return;
wpas_p2p_remove_pending_group_interface(wpa_s);
}
@@ -4469,13 +4844,18 @@
/* Invite to reinvoke a persistent group */
int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
- int ht40)
+ int ht40, int pref_freq)
{
enum p2p_invite_role role;
- u8 *bssid = NULL;
-#ifdef ANDROID_P2P
+ u8 *bssid = NULL, bssid_buf[ETH_ALEN];
int force_freq = 0, oper_freq = 0;
-#endif
+ int res;
+
+ wpa_s->global->p2p_invite_group = NULL;
+ if (peer_addr)
+ os_memcpy(wpa_s->p2p_auth_invite, peer_addr, ETH_ALEN);
+ else
+ os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
wpa_s->p2p_persistent_go_freq = freq;
wpa_s->p2p_go_ht40 = !!ht40;
@@ -4503,55 +4883,22 @@
}
wpa_s->pending_invite_ssid_id = ssid->id;
-#ifdef ANDROID_P2P
- if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid) == 0 &&
- wpa_s->assoc_freq)
+ if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid_buf) == 0 &&
+ wpa_s->assoc_freq) {
oper_freq = wpa_s->assoc_freq;
- else {
+ if (bssid == NULL)
+ bssid = bssid_buf;
+ } else {
oper_freq = wpa_drv_shared_freq(wpa_s);
if (oper_freq < 0)
oper_freq = 0;
}
- if (freq > 0) {
- if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
- wpa_printf(MSG_DEBUG, "P2P: The forced channel "
- "(%u MHz) is not supported for P2P uses",
- freq);
- return -3;
- }
+ res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq,
+ &oper_freq);
+ if (res)
+ return res;
- if (oper_freq > 0 && freq != oper_freq &&
- !(wpa_s->drv_flags &
- WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
- wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group "
- "on %u MHz while connected on another "
- "channel (%u MHz)", freq, oper_freq);
- return -2;
- }
- wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
- "requested channel (%u MHz)", freq);
- force_freq = freq;
- } else if (oper_freq > 0 &&
- !p2p_supported_freq(wpa_s->global->p2p, oper_freq)) {
- if (!(wpa_s->drv_flags &
- WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
- wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group "
- "while connected on non-P2P supported "
- "channel (%u MHz)", oper_freq);
- return -2;
- }
- wpa_printf(MSG_DEBUG, "P2P: Current operating channel "
- "(%u MHz) not available for P2P - try to use "
- "another channel", oper_freq);
- force_freq = 0;
- } else if (oper_freq > 0) {
- wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
- "channel we are already using (%u MHz) on another "
- "interface", oper_freq);
- force_freq = oper_freq;
- }
-#endif
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
return wpa_drv_p2p_invite(wpa_s, peer_addr, role, bssid,
ssid->ssid, ssid->ssid_len,
@@ -4560,13 +4907,9 @@
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
-#ifdef ANDROID_P2P
return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
- ssid->ssid, ssid->ssid_len, force_freq, go_dev_addr, 1);
-#else
- return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
- ssid->ssid, ssid->ssid_len, freq, go_dev_addr, 1);
-#endif
+ ssid->ssid, ssid->ssid_len, force_freq, go_dev_addr,
+ 1, pref_freq);
}
@@ -4576,9 +4919,11 @@
{
struct wpa_global *global = wpa_s->global;
enum p2p_invite_role role;
- u8 *bssid = NULL;
+ u8 *bssid = NULL, bssid_buf[ETH_ALEN];
struct wpa_ssid *ssid;
int persistent;
+ int force_freq = 0, oper_freq = 0, pref_freq = 0;
+ int res;
wpa_s->p2p_persistent_go_freq = 0;
wpa_s->p2p_go_ht40 = 0;
@@ -4599,6 +4944,7 @@
return -1;
}
+ wpa_s->global->p2p_invite_group = wpa_s;
persistent = ssid->p2p_persistent_group &&
wpas_p2p_get_persistent(wpa_s->parent, peer_addr,
ssid->ssid, ssid->ssid_len);
@@ -4630,9 +4976,26 @@
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
+ if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid_buf) == 0 &&
+ wpa_s->assoc_freq) {
+ oper_freq = wpa_s->assoc_freq;
+ if (bssid == NULL)
+ bssid = bssid_buf;
+ } else {
+ oper_freq = wpa_drv_shared_freq(wpa_s);
+ if (oper_freq < 0)
+ oper_freq = 0;
+ }
+
+ res = wpas_p2p_setup_freqs(wpa_s, 0, &force_freq, &pref_freq,
+ &oper_freq);
+ if (res)
+ return res;
+ wpas_p2p_set_own_freq_preference(wpa_s, oper_freq);
+
return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
- ssid->ssid, ssid->ssid_len, wpa_s->assoc_freq,
- go_dev_addr, persistent);
+ ssid->ssid, ssid->ssid_len, force_freq,
+ go_dev_addr, persistent, pref_freq);
}
@@ -4695,17 +5058,7 @@
wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 1);
done:
- if (wpa_s->global->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled &&
- wpa_s->global->p2p != NULL) {
- wpa_s->global->p2p_cb_on_scan_complete = 0;
- if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
- wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
- "continued after successful connection");
- p2p_increase_search_delay(
- wpa_s->global->p2p,
- wpas_p2p_search_delay(wpa_s));
- }
- }
+ wpas_p2p_continue_after_scan(wpa_s);
}
@@ -4743,8 +5096,15 @@
static int wpas_p2p_is_client(struct wpa_supplicant *wpa_s)
{
- return wpa_s->current_ssid != NULL &&
- wpa_s->current_ssid->p2p_group &&
+ if (wpa_s->current_ssid == NULL) {
+ /*
+ * current_ssid can be cleared when P2P client interface gets
+ * disconnected, so assume this interface was used as P2P
+ * client.
+ */
+ return 1;
+ }
+ return wpa_s->current_ssid->p2p_group &&
wpa_s->current_ssid->mode == WPAS_MODE_INFRA;
}
@@ -5178,6 +5538,13 @@
}
+static void wpas_p2p_scan_res_ignore(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
+{
+ wpa_printf(MSG_DEBUG, "P2P: Ignore scan results");
+}
+
+
int wpas_p2p_cancel(struct wpa_supplicant *wpa_s)
{
struct wpa_global *global = wpa_s->global;
@@ -5201,6 +5568,18 @@
found = 1;
}
+ if (wpa_s->scan_res_handler == wpas_p2p_scan_res_join) {
+ wpa_printf(MSG_DEBUG, "P2P: Stop pending scan for join");
+ wpa_s->scan_res_handler = wpas_p2p_scan_res_ignore;
+ found = 1;
+ }
+
+ if (wpa_s->pending_pd_before_join) {
+ wpa_printf(MSG_DEBUG, "P2P: Stop pending PD before join");
+ wpa_s->pending_pd_before_join = 0;
+ found = 1;
+ }
+
wpas_p2p_stop_find(wpa_s);
for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
@@ -5293,10 +5672,29 @@
int wpas_p2p_in_progress(struct wpa_supplicant *wpa_s)
{
+ int ret;
+
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return 0;
- return p2p_in_progress(wpa_s->global->p2p);
+ ret = p2p_in_progress(wpa_s->global->p2p);
+ if (ret == 0) {
+ /*
+ * Check whether there is an ongoing WPS provisioning step (or
+ * other parts of group formation) on another interface since
+ * p2p_in_progress() does not report this to avoid issues for
+ * scans during such provisioning step.
+ */
+ if (wpa_s->global->p2p_group_formation &&
+ wpa_s->global->p2p_group_formation != wpa_s) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Another interface (%s) "
+ "in group formation",
+ wpa_s->global->p2p_group_formation->ifname);
+ ret = 1;
+ }
+ }
+
+ return ret;
}
@@ -5365,7 +5763,6 @@
int group_added)
{
struct wpa_supplicant *group = wpa_s;
- eloop_cancel_timeout(wpas_p2p_pd_before_join_timeout, wpa_s, NULL);
if (wpa_s->global->p2p_group_formation)
group = wpa_s->global->p2p_group_formation;
wpa_s = wpa_s->parent;
@@ -5436,8 +5833,33 @@
return 0;
}
+
+void wpas_p2p_continue_after_scan(struct wpa_supplicant *wpa_s)
+{
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Station mode scan operation not "
+ "pending anymore (sta_scan_pending=%d "
+ "p2p_cb_on_scan_complete=%d)", wpa_s->sta_scan_pending,
+ wpa_s->global->p2p_cb_on_scan_complete);
+ wpa_s->sta_scan_pending = 0;
+
+ if (!wpa_s->global->p2p_cb_on_scan_complete)
+ return;
+ wpa_s->global->p2p_cb_on_scan_complete = 0;
+
+ if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+ return;
+
+ if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
+ "continued after successful connection");
+ p2p_increase_search_delay(wpa_s->global->p2p,
+ wpas_p2p_search_delay(wpa_s));
+ }
+}
+
#ifdef ANDROID_P2P
-int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq)
+int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq,
+ struct wpa_ssid *ssid)
{
struct wpa_supplicant *iface = NULL;
struct p2p_data *p2p = wpa_s->global->p2p;
@@ -5463,17 +5885,32 @@
/* If GO cannot be moved or if the conflicting interface is a
* P2P Client, remove the interface depending up on the connection
* priority */
- if (!wpas_is_p2p_prioritized(wpa_s)) {
+ if(!wpas_is_p2p_prioritized(iface)) {
/* STA connection has priority over existing
* P2P connection. So remove the interface */
- wpa_printf(MSG_DEBUG, "P2P: Removing P2P connection due to Single channel "
+ wpa_printf(MSG_DEBUG, "P2P: Removing P2P connection due to Single channel"
"concurrent mode frequency conflict");
wpas_p2p_group_delete(iface, P2P_GROUP_REMOVAL_FREQ_CONFLICT);
+ /* If connection in progress is p2p connection, do not proceed for the connection */
+ if (wpa_s == iface)
+ return -1;
+ else
+ /* If connection in progress is STA connection, proceed for the connection */
+ return 0;
} else {
- /* Existing connection has the priority. Disable the newly
- * selected network and let the application know about it.
- */
- return -1;
+ /* P2p connection has priority, disable the STA network*/
+ wpa_supplicant_disable_network(wpa_s->global->ifaces, ssid);
+ wpa_msg(wpa_s->global->ifaces, MSG_INFO, WPA_EVENT_FREQ_CONFLICT
+ " id=%d", ssid->id);
+ os_memset(wpa_s->global->ifaces->pending_bssid, 0, ETH_ALEN);
+ if (wpa_s == iface) {
+ /* p2p connection is in progress, continue connecting...*/
+ return 0;
+ }
+ else {
+ /* STA connection is in progress, do not allow to continue */
+ return -1;
+ }
}
}
}
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 6e4cc1d..04ba9b2 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -13,6 +13,7 @@
struct p2p_go_neg_results;
enum p2p_send_action_result;
struct p2p_peer_info;
+struct p2p_channels;
int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s);
void wpas_p2p_deinit(struct wpa_supplicant *wpa_s);
@@ -28,14 +29,15 @@
unsigned int freq);
#ifdef ANDROID_P2P
int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s,
- int freq);
+ int freq, struct wpa_ssid *ssid);
#endif
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 wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, int addr_allocated,
- int freq, int ht40);
+ int freq, int ht40,
+ const struct p2p_channels *channels);
struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
@@ -113,7 +115,7 @@
int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr);
int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
- int ht40);
+ int ht40, int pref_freq);
int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
const u8 *peer_addr, const u8 *go_dev_addr);
void wpas_p2p_completed(struct wpa_supplicant *wpa_s);
@@ -156,4 +158,12 @@
struct hostapd_hw_modes *mode, u8 channel);
unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s);
+#ifdef CONFIG_P2P
+void wpas_p2p_continue_after_scan(struct wpa_supplicant *wpa_s);
+#else /* CONFIG_P2P */
+static inline void wpas_p2p_continue_after_scan(struct wpa_supplicant *wpa_s)
+{
+}
+#endif /* CONFIG_P2P */
+
#endif /* P2P_SUPPLICANT_H */
diff --git a/wpa_supplicant/preauth_test.c b/wpa_supplicant/preauth_test.c
index 62b7538..ff2ae74 100644
--- a/wpa_supplicant/preauth_test.c
+++ b/wpa_supplicant/preauth_test.c
@@ -38,12 +38,6 @@
};
-static void _wpa_supplicant_disassociate(void *wpa_s, int reason_code)
-{
- wpa_supplicant_disassociate(wpa_s, reason_code);
-}
-
-
static void _wpa_supplicant_deauthenticate(void *wpa_s, int reason_code)
{
wpa_supplicant_deauthenticate(wpa_s, reason_code);
@@ -238,7 +232,6 @@
ctx->set_state = _wpa_supplicant_set_state;
ctx->get_state = _wpa_supplicant_get_state;
ctx->deauthenticate = _wpa_supplicant_deauthenticate;
- ctx->disassociate = _wpa_supplicant_disassociate;
ctx->set_key = wpa_supplicant_set_key;
ctx->get_network_ctx = wpa_supplicant_get_network_ctx;
ctx->get_bssid = wpa_supplicant_get_bssid;
@@ -316,7 +309,7 @@
}
os_memset(&wpa_s, 0, sizeof(wpa_s));
- wpa_s.conf = wpa_config_read(argv[1]);
+ wpa_s.conf = wpa_config_read(argv[1], NULL);
if (wpa_s.conf == NULL) {
printf("Failed to parse configuration file '%s'.\n", argv[1]);
return -1;
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 0f6433b..db73a18 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - Scanning
- * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, 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,7 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
#include "config.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
@@ -66,7 +67,8 @@
}
#ifdef CONFIG_P2P
- if (!wpa_s->global->p2p_disabled && wpa_s->global->p2p) {
+ if (!wpa_s->global->p2p_disabled && wpa_s->global->p2p &&
+ !wpa_s->conf->p2p_disabled) {
wpa_s->wps->dev.p2p = 1;
if (!wps) {
wps = 1;
@@ -80,6 +82,15 @@
#endif /* CONFIG_WPS */
+/**
+ * wpa_supplicant_enabled_networks - Check whether there are enabled networks
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: 0 if no networks are enabled, >0 if networks are enabled
+ *
+ * This function is used to figure out whether any networks (or Interworking
+ * with enabled credentials and auto_interworking) are present in the current
+ * configuration.
+ */
int wpa_supplicant_enabled_networks(struct wpa_supplicant *wpa_s)
{
struct wpa_ssid *ssid = wpa_s->conf->ssid;
@@ -198,6 +209,12 @@
}
+/**
+ * wpa_supplicant_trigger_scan - Request driver to start a scan
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @params: Scan parameters
+ * Returns: 0 on success, -1 on failure
+ */
int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
struct wpa_driver_scan_params *params)
{
@@ -210,6 +227,7 @@
wpa_supplicant_notify_scanning(wpa_s, 0);
wpas_notify_scan_done(wpa_s, 0);
} else {
+ os_get_time(&wpa_s->scan_trigger_time);
wpa_s->scan_runs++;
wpa_s->normal_scans++;
}
@@ -439,11 +457,78 @@
}
+#ifdef CONFIG_P2P
+
+/*
+ * Check whether there are any enabled networks or credentials that could be
+ * used for a non-P2P connection.
+ */
+static int non_p2p_network_enabled(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_ssid *ssid;
+
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ if (wpas_network_disabled(wpa_s, ssid))
+ continue;
+ if (!ssid->p2p_group)
+ return 1;
+ }
+
+ if (wpa_s->conf->cred && wpa_s->conf->interworking &&
+ wpa_s->conf->auto_interworking)
+ return 1;
+
+ return 0;
+}
+
+
+/*
+ * Find the operating frequency of any other virtual interface that is using
+ * the same radio concurrently.
+ */
+static int shared_vif_oper_freq(struct wpa_supplicant *wpa_s)
+{
+ const char *rn, *rn2;
+ struct wpa_supplicant *ifs;
+ u8 bssid[ETH_ALEN];
+
+ if (!wpa_s->driver->get_radio_name)
+ return -1;
+
+ rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
+ if (rn == NULL || rn[0] == '\0')
+ return -1;
+
+ for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
+ if (ifs == wpa_s || !ifs->driver->get_radio_name)
+ continue;
+
+ rn2 = ifs->driver->get_radio_name(ifs->drv_priv);
+ if (!rn2 || os_strcmp(rn, rn2) != 0)
+ continue;
+
+ if (ifs->current_ssid == NULL || ifs->assoc_freq == 0)
+ continue;
+
+ if (ifs->current_ssid->mode == WPAS_MODE_AP ||
+ ifs->current_ssid->mode == WPAS_MODE_P2P_GO)
+ return ifs->current_ssid->frequency;
+ if (wpa_drv_get_bssid(ifs, bssid) == 0)
+ return ifs->assoc_freq;
+ }
+
+ return 0;
+}
+
+#endif /* CONFIG_P2P */
+
+
static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
struct wpa_ssid *ssid;
- int scan_req = 0, ret;
+ enum scan_req_type scan_req = NORMAL_SCAN_REQ;
+ int ret;
struct wpabuf *extra_ie = NULL;
struct wpa_driver_scan_params params;
struct wpa_driver_scan_params *scan_params;
@@ -452,12 +537,14 @@
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - interface disabled");
+ wpas_p2p_continue_after_scan(wpa_s);
return;
}
- if (wpa_s->disconnected && !wpa_s->scan_req) {
+ if (wpa_s->disconnected && wpa_s->scan_req == NORMAL_SCAN_REQ) {
wpa_dbg(wpa_s, MSG_DEBUG, "Disconnected - do not scan");
wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+ wpas_p2p_continue_after_scan(wpa_s);
return;
}
#ifdef ANDROID
@@ -468,12 +555,10 @@
}
#endif
if (!wpa_supplicant_enabled_networks(wpa_s) &&
- !wpa_s->scan_req) {
+ wpa_s->scan_req == NORMAL_SCAN_REQ) {
wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks - do not scan");
wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
-#ifdef CONFIG_P2P
- wpa_s->sta_scan_pending = 0;
-#endif /* CONFIG_P2P */
+ wpas_p2p_continue_after_scan(wpa_s);
return;
}
@@ -516,7 +601,7 @@
}
scan_req = wpa_s->scan_req;
- wpa_s->scan_req = 0;
+ wpa_s->scan_req = NORMAL_SCAN_REQ;
os_memset(¶ms, 0, sizeof(params));
@@ -533,7 +618,7 @@
goto scan;
}
- if (scan_req != 2 && wpa_s->connect_without_scan) {
+ if (scan_req != MANUAL_SCAN_REQ && wpa_s->connect_without_scan) {
for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
if (ssid == wpa_s->connect_without_scan)
break;
@@ -571,7 +656,7 @@
}
}
- if (scan_req != 2 && wpa_s->conf->ap_scan == 2) {
+ if (scan_req != MANUAL_SCAN_REQ && wpa_s->conf->ap_scan == 2) {
wpa_s->connect_without_scan = NULL;
wpa_s->prev_scan_wildcard = 0;
wpa_supplicant_assoc_try(wpa_s, ssid);
@@ -665,7 +750,7 @@
extra_ie = wpa_supplicant_extra_ies(wpa_s);
#ifdef CONFIG_HS20
- if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 6) == 0)
+ if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 7) == 0)
wpas_hs20_add_indication(extra_ie);
#endif /* CONFIG_HS20 */
@@ -698,6 +783,35 @@
scan_params = ¶ms;
scan:
+#ifdef CONFIG_P2P
+ /*
+ * If the driver does not support multi-channel concurrency and a
+ * virtual interface that shares the same radio with the wpa_s interface
+ * is operating there may not be need to scan other channels apart from
+ * the current operating channel on the other virtual interface. Filter
+ * out other channels in case we are trying to find a connection for a
+ * station interface when we are not configured to prefer station
+ * connection and a concurrent operation is already in process.
+ */
+ if (wpa_s->scan_for_connection && scan_req == NORMAL_SCAN_REQ &&
+ !scan_params->freqs && !params.freqs &&
+ wpas_is_p2p_prioritized(wpa_s) &&
+ !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) &&
+ wpa_s->p2p_group_interface == NOT_P2P_GROUP_INTERFACE &&
+ non_p2p_network_enabled(wpa_s)) {
+ int freq = shared_vif_oper_freq(wpa_s);
+ if (freq > 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only the current "
+ "operating channel (%d MHz) since driver does "
+ "not support multi-channel concurrency", freq);
+ params.freqs = os_zalloc(sizeof(int) * 2);
+ if (params.freqs)
+ params.freqs[0] = freq;
+ scan_params->freqs = params.freqs;
+ }
+ }
+#endif /* CONFIG_P2P */
+
ret = wpa_supplicant_trigger_scan(wpa_s, scan_params);
wpabuf_free(extra_ie);
@@ -706,19 +820,38 @@
if (ret) {
wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate AP scan");
-#ifdef ANDROID_P2P
- /* Restore back the wpa_s->scan_req if we failed the scan because of any reason */
- wpa_msg(wpa_s, MSG_DEBUG, "Restoring back the wpa_s->scan_req "
- "to the original value %d", scan_req);
- wpa_s->scan_req = scan_req;
-#endif
if (prev_state != wpa_s->wpa_state)
wpa_supplicant_set_state(wpa_s, prev_state);
+ /* Restore scan_req since we will try to scan again */
+ wpa_s->scan_req = scan_req;
wpa_supplicant_req_scan(wpa_s, 1, 0);
+ } else {
+ wpa_s->scan_for_connection = 0;
}
}
+void wpa_supplicant_update_scan_int(struct wpa_supplicant *wpa_s, int sec)
+{
+ struct os_time remaining, new_int;
+ int cancelled;
+
+ cancelled = eloop_cancel_timeout_one(wpa_supplicant_scan, wpa_s, NULL,
+ &remaining);
+
+ new_int.sec = sec;
+ new_int.usec = 0;
+ if (cancelled && os_time_before(&remaining, &new_int)) {
+ new_int.sec = remaining.sec;
+ new_int.usec = remaining.usec;
+ }
+
+ eloop_register_timeout(new_int.sec, new_int.usec, wpa_supplicant_scan,
+ wpa_s, NULL);
+ wpa_s->scan_interval = sec;
+}
+
+
/**
* wpa_supplicant_req_scan - Schedule a scan for neighboring access points
* @wpa_s: Pointer to wpa_supplicant data
@@ -766,6 +899,7 @@
* @wpa_s: Pointer to wpa_supplicant data
* @sec: Number of seconds after which to scan
* @usec: Number of microseconds after which to scan
+ * Returns: 0 on success or -1 otherwise
*
* This function is used to schedule periodic scans for neighboring
* access points after the specified time.
@@ -787,6 +921,7 @@
/**
* wpa_supplicant_req_sched_scan - Start a periodic scheduled scan
* @wpa_s: Pointer to wpa_supplicant data
+ * Returns: 0 is sched_scan was started or -1 otherwise
*
* This function is used to schedule periodic scans for neighboring
* access points repeating the scan continuously.
@@ -1000,8 +1135,16 @@
wpa_s->first_sched_scan = 0;
wpa_s->sched_scan_timeout /= 2;
wpa_s->sched_scan_interval *= 2;
+ if (wpa_s->sched_scan_timeout < wpa_s->sched_scan_interval) {
+ wpa_s->sched_scan_interval = 10;
+ wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2;
+ }
}
+ /* If there is no more ssids, start next time from the beginning */
+ if (!ssid)
+ wpa_s->prev_sched_ssid = NULL;
+
return 0;
}
@@ -1017,6 +1160,7 @@
{
wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling scan request");
eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
+ wpas_p2p_continue_after_scan(wpa_s);
#ifdef ANDROID
wpa_supplicant_notify_scanning(wpa_s, 0);
#endif
@@ -1040,6 +1184,16 @@
}
+/**
+ * wpa_supplicant_notify_scanning - Indicate possible scan state change
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @scanning: Whether scanning is currently in progress
+ *
+ * This function is to generate scanning notifycations. It is called whenever
+ * there may have been a change in scanning (scan started, completed, stopped).
+ * wpas_notify_scanning() is called whenever the scanning state changed from the
+ * previously notified state.
+ */
void wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s,
int scanning)
{
@@ -1077,6 +1231,15 @@
}
+/**
+ * wpa_scan_get_ie - Fetch a specified information element from a scan result
+ * @res: Scan result entry
+ * @ie: Information element identitifier (WLAN_EID_*)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the first matching information element in the scan
+ * result.
+ */
const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie)
{
const u8 *end, *pos;
@@ -1096,6 +1259,15 @@
}
+/**
+ * wpa_scan_get_vendor_ie - Fetch vendor information element from a scan result
+ * @res: Scan result entry
+ * @vendor_type: Vendor type (four octets starting the IE payload)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the first matching information element in the scan
+ * result.
+ */
const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res,
u32 vendor_type)
{
@@ -1117,6 +1289,16 @@
}
+/**
+ * wpa_scan_get_vendor_ie_multi - Fetch vendor IE data from a scan result
+ * @res: Scan result entry
+ * @vendor_type: Vendor type (four octets starting the IE payload)
+ * Returns: Pointer to the information element payload or %NULL if not found
+ *
+ * This function returns concatenated payload of possibly fragmented vendor
+ * specific information elements in the scan result. The caller is responsible
+ * for freeing the returned buffer.
+ */
struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
u32 vendor_type)
{
@@ -1148,40 +1330,6 @@
}
-struct wpabuf * wpa_scan_get_vendor_ie_multi_beacon(
- const struct wpa_scan_res *res, u32 vendor_type)
-{
- struct wpabuf *buf;
- const u8 *end, *pos;
-
- if (res->beacon_ie_len == 0)
- return NULL;
- buf = wpabuf_alloc(res->beacon_ie_len);
- if (buf == NULL)
- return NULL;
-
- pos = (const u8 *) (res + 1);
- pos += res->ie_len;
- end = pos + res->beacon_ie_len;
-
- while (pos + 1 < end) {
- if (pos + 2 + pos[1] > end)
- break;
- if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
- vendor_type == WPA_GET_BE32(&pos[2]))
- wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
- pos += 2 + pos[1];
- }
-
- if (wpabuf_len(buf) == 0) {
- wpabuf_free(buf);
- buf = NULL;
- }
-
- return buf;
-}
-
-
/*
* Channels with a great SNR can operate at full rate. What is a great SNR?
* This doc https://supportforums.cisco.com/docs/DOC-12954 says, "the general
@@ -1323,15 +1471,17 @@
== WPA_SCAN_LEVEL_DBM) {
int snr = r->level - r->noise;
wpa_printf(MSG_EXCESSIVE, MACSTR " freq=%d qual=%d "
- "noise=%d level=%d snr=%d%s flags=0x%x",
+ "noise=%d level=%d snr=%d%s flags=0x%x "
+ "age=%u",
MAC2STR(r->bssid), r->freq, r->qual,
r->noise, r->level, snr,
- snr >= GREAT_SNR ? "*" : "", r->flags);
+ snr >= GREAT_SNR ? "*" : "", r->flags,
+ r->age);
} else {
wpa_printf(MSG_EXCESSIVE, MACSTR " freq=%d qual=%d "
- "noise=%d level=%d flags=0x%x",
+ "noise=%d level=%d flags=0x%x age=%u",
MAC2STR(r->bssid), r->freq, r->qual,
- r->noise, r->level, r->flags);
+ r->noise, r->level, r->flags, r->age);
}
pos = (u8 *) (r + 1);
if (r->ie_len)
@@ -1345,6 +1495,15 @@
}
+/**
+ * wpa_supplicant_filter_bssid_match - Is the specified BSSID allowed
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID to check
+ * Returns: 0 if the BSSID is filtered or 1 if not
+ *
+ * This function is used to filter out specific BSSIDs from scan reslts mainly
+ * for testing purposes (SET bssid_filter ctrl_iface command).
+ */
int wpa_supplicant_filter_bssid_match(struct wpa_supplicant *wpa_s,
const u8 *bssid)
{
@@ -1413,6 +1572,13 @@
wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results");
return NULL;
}
+ if (scan_res->fetch_time.sec == 0) {
+ /*
+ * Make sure we have a valid timestamp if the driver wrapper
+ * does not set this.
+ */
+ os_get_time(&scan_res->fetch_time);
+ }
filter_scan_res(wpa_s, scan_res);
#ifdef CONFIG_WPS
@@ -1429,13 +1595,26 @@
wpa_bss_update_start(wpa_s);
for (i = 0; i < scan_res->num; i++)
- wpa_bss_update_scan_res(wpa_s, scan_res->res[i]);
+ wpa_bss_update_scan_res(wpa_s, scan_res->res[i],
+ &scan_res->fetch_time);
wpa_bss_update_end(wpa_s, info, new_scan);
return scan_res;
}
+/**
+ * wpa_supplicant_update_scan_results - Update scan results from the driver
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function updates the BSS table within wpa_supplicant based on the
+ * currently available scan results from the driver without requesting a new
+ * scan. This is used in cases where the driver indicates an association
+ * (including roaming within ESS) and wpa_supplicant does not yet have the
+ * needed information to complete the connection (e.g., to perform validation
+ * steps in 4-way handshake).
+ */
int wpa_supplicant_update_scan_results(struct wpa_supplicant *wpa_s)
{
struct wpa_scan_results *scan_res;
@@ -1446,3 +1625,22 @@
return 0;
}
+
+
+/**
+ * scan_only_handler - Reports scan results
+ */
+void scan_only_handler(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
+{
+ wpa_dbg(wpa_s, MSG_DEBUG, "Scan-only results received");
+ wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS);
+ wpas_notify_scan_results(wpa_s);
+ wpas_notify_scan_done(wpa_s, 1);
+}
+
+
+int wpas_scan_scheduled(struct wpa_supplicant *wpa_s)
+{
+ return eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL);
+}
diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
index b0ddf97..e892479 100644
--- a/wpa_supplicant/scan.h
+++ b/wpa_supplicant/scan.h
@@ -30,9 +30,11 @@
u32 vendor_type);
struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
u32 vendor_type);
-struct wpabuf * wpa_scan_get_vendor_ie_multi_beacon(
- const struct wpa_scan_res *res, u32 vendor_type);
int wpa_supplicant_filter_bssid_match(struct wpa_supplicant *wpa_s,
const u8 *bssid);
+void wpa_supplicant_update_scan_int(struct wpa_supplicant *wpa_s, int sec);
+void scan_only_handler(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res);
+int wpas_scan_scheduled(struct wpa_supplicant *wpa_s);
#endif /* SCAN_H */
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index b09e5f1..4c78161 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -1,6 +1,6 @@
/*
* wpa_supplicant - SME
- * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -14,6 +14,7 @@
#include "common/ieee802_11_common.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "common/wpa_common.h"
+#include "common/sae.h"
#include "rsn_supp/wpa.h"
#include "rsn_supp/pmksa_cache.h"
#include "config.h"
@@ -39,8 +40,106 @@
#endif /* CONFIG_IEEE80211W */
-void sme_authenticate(struct wpa_supplicant *wpa_s,
- struct wpa_bss *bss, struct wpa_ssid *ssid)
+#ifdef CONFIG_SAE
+
+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 sme_set_sae_group(struct wpa_supplicant *wpa_s)
+{
+ int *groups = wpa_s->conf->sae_groups;
+ int default_groups[] = { 19, 20, 21, 25, 26 };
+
+ if (!groups)
+ groups = default_groups;
+
+ /* Configuration may have changed, so validate current index */
+ if (!index_within_array(groups, wpa_s->sme.sae_group_index))
+ return -1;
+
+ for (;;) {
+ int group = groups[wpa_s->sme.sae_group_index];
+ if (group < 0)
+ break;
+ if (sae_set_group(&wpa_s->sme.sae, group) == 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "SME: Selected SAE group %d",
+ wpa_s->sme.sae.group);
+ return 0;
+ }
+ wpa_s->sme.sae_group_index++;
+ }
+
+ return -1;
+}
+
+
+static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ const u8 *bssid)
+{
+ struct wpabuf *buf;
+ size_t len;
+
+ if (ssid->passphrase == NULL) {
+ wpa_printf(MSG_DEBUG, "SAE: No password available");
+ return NULL;
+ }
+
+ if (sme_set_sae_group(wpa_s) < 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Failed to select group");
+ return NULL;
+ }
+
+ if (sae_prepare_commit(wpa_s->own_addr, bssid,
+ (u8 *) ssid->passphrase,
+ os_strlen(ssid->passphrase),
+ &wpa_s->sme.sae) < 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
+ return NULL;
+ }
+
+ len = wpa_s->sme.sae_token ? wpabuf_len(wpa_s->sme.sae_token) : 0;
+ buf = wpabuf_alloc(4 + SAE_COMMIT_MAX_LEN + len);
+ if (buf == NULL)
+ return NULL;
+
+ wpabuf_put_le16(buf, 1); /* Transaction seq# */
+ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+ sae_write_commit(&wpa_s->sme.sae, buf, wpa_s->sme.sae_token);
+
+ return buf;
+}
+
+
+static struct wpabuf * sme_auth_build_sae_confirm(struct wpa_supplicant *wpa_s)
+{
+ struct wpabuf *buf;
+
+ buf = wpabuf_alloc(4 + SAE_CONFIRM_MAX_LEN);
+ if (buf == NULL)
+ return NULL;
+
+ wpabuf_put_le16(buf, 2); /* Transaction seq# */
+ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+ sae_write_confirm(&wpa_s->sme.sae, buf);
+
+ return buf;
+}
+
+#endif /* CONFIG_SAE */
+
+
+static void sme_send_authentication(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss, struct wpa_ssid *ssid,
+ int start)
{
struct wpa_driver_auth_params params;
struct wpa_ssid *old_ssid;
@@ -51,6 +150,9 @@
const u8 *md = NULL;
#endif /* CONFIG_IEEE80211R */
int i, bssid_changed;
+ struct wpabuf *resp = NULL;
+ u8 ext_capab[10];
+ int ext_capab_len;
if (bss == NULL) {
wpa_msg(wpa_s, MSG_ERROR, "SME: No scan result available for "
@@ -95,6 +197,21 @@
wpa_dbg(wpa_s, MSG_DEBUG, "Overriding auth_alg selection: "
"0x%x", params.auth_alg);
}
+#ifdef CONFIG_SAE
+ 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;
+ }
+ }
+ }
+#endif /* CONFIG_SAE */
for (i = 0; i < NUM_WEP_KEYS; i++) {
if (ssid->wep_key_len[i])
@@ -113,7 +230,9 @@
wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
wpa_key_mgmt_wpa(ssid->key_mgmt)) {
int try_opportunistic;
- try_opportunistic = ssid->proactive_key_caching &&
+ try_opportunistic = (ssid->proactive_key_caching < 0 ?
+ wpa_s->conf->okc :
+ ssid->proactive_key_caching) &&
(ssid->proto & WPA_PROTO_RSN);
if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
wpa_s->current_ssid,
@@ -203,8 +322,9 @@
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211W
- wpa_s->sme.mfp = ssid->ieee80211w;
- if (ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ wpa_s->sme.mfp = ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+ wpa_s->conf->pmf : ssid->ieee80211w;
+ if (wpa_s->sme.mfp != NO_MGMT_FRAME_PROTECTION) {
const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
struct wpa_ie_data _ie;
if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &_ie) == 0 &&
@@ -247,23 +367,32 @@
}
#endif /* CONFIG_HS20 */
-#ifdef CONFIG_INTERWORKING
- if (wpa_s->conf->interworking) {
+ ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab);
+ if (ext_capab_len > 0) {
u8 *pos = wpa_s->sme.assoc_req_ie;
if (wpa_s->sme.assoc_req_ie_len > 0 && pos[0] == WLAN_EID_RSN)
pos += 2 + pos[1];
- os_memmove(pos + 6, pos,
+ os_memmove(pos + ext_capab_len, pos,
wpa_s->sme.assoc_req_ie_len -
(pos - wpa_s->sme.assoc_req_ie));
- wpa_s->sme.assoc_req_ie_len += 6;
- *pos++ = WLAN_EID_EXT_CAPAB;
- *pos++ = 4;
- *pos++ = 0x00;
- *pos++ = 0x00;
- *pos++ = 0x00;
- *pos++ = 0x80; /* Bit 31 - Interworking */
+ wpa_s->sme.assoc_req_ie_len += ext_capab_len;
+ os_memcpy(pos, ext_capab, ext_capab_len);
}
-#endif /* CONFIG_INTERWORKING */
+
+#ifdef CONFIG_SAE
+ if (params.auth_alg == WPA_AUTH_ALG_SAE) {
+ if (start)
+ resp = sme_auth_build_sae_commit(wpa_s, ssid,
+ bss->bssid);
+ else
+ resp = sme_auth_build_sae_confirm(wpa_s);
+ if (resp == NULL)
+ return;
+ params.sae_data = wpabuf_head(resp);
+ params.sae_data_len = wpabuf_len(resp);
+ wpa_s->sme.sae.state = start ? SAE_COMMITTED : SAE_CONFIRMED;
+ }
+#endif /* CONFIG_SAE */
wpa_supplicant_cancel_sched_scan(wpa_s);
wpa_supplicant_cancel_scan(wpa_s);
@@ -287,6 +416,7 @@
"driver failed");
wpas_connection_failed(wpa_s, bss->bssid);
wpa_supplicant_mark_disassoc(wpa_s);
+ wpabuf_free(resp);
return;
}
@@ -297,9 +427,99 @@
* Association will be started based on the authentication event from
* the driver.
*/
+
+ wpabuf_free(resp);
}
+void sme_authenticate(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss, struct wpa_ssid *ssid)
+{
+#ifdef CONFIG_SAE
+ wpa_s->sme.sae.state = SAE_NOTHING;
+ wpa_s->sme.sae.send_confirm = 0;
+#endif /* CONFIG_SAE */
+ sme_send_authentication(wpa_s, bss, ssid, 1);
+}
+
+
+#ifdef CONFIG_SAE
+
+static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
+ u16 status_code, const u8 *data, size_t len)
+{
+ wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE authentication transaction %u "
+ "status code %u", auth_transaction, status_code);
+
+ if (auth_transaction == 1 &&
+ 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");
+ wpabuf_free(wpa_s->sme.sae_token);
+ wpa_s->sme.sae_token = wpabuf_alloc_copy(data, len);
+ sme_send_authentication(wpa_s, wpa_s->current_bss,
+ wpa_s->current_ssid, 1);
+ return 0;
+ }
+
+ if (auth_transaction == 1 &&
+ status_code == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
+ wpa_s->sme.sae.state == SAE_COMMITTED &&
+ wpa_s->current_bss && wpa_s->current_ssid) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE group not supported");
+ wpa_s->sme.sae_group_index++;
+ if (sme_set_sae_group(wpa_s) < 0)
+ return -1; /* no other groups enabled */
+ wpa_dbg(wpa_s, MSG_DEBUG, "SME: Try next enabled SAE group");
+ sme_send_authentication(wpa_s, wpa_s->current_bss,
+ wpa_s->current_ssid, 1);
+ return 0;
+ }
+
+ if (status_code != WLAN_STATUS_SUCCESS)
+ return -1;
+
+ if (auth_transaction == 1) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE commit");
+ if (wpa_s->current_bss == NULL ||
+ wpa_s->current_ssid == NULL)
+ return -1;
+ if (wpa_s->sme.sae.state != SAE_COMMITTED)
+ return -1;
+ if (sae_parse_commit(&wpa_s->sme.sae, data, len, NULL, NULL,
+ wpa_s->conf->sae_groups) !=
+ WLAN_STATUS_SUCCESS)
+ return -1;
+
+ if (sae_process_commit(&wpa_s->sme.sae) < 0) {
+ wpa_printf(MSG_DEBUG, "SAE: Failed to process peer "
+ "commit");
+ return -1;
+ }
+
+ wpabuf_free(wpa_s->sme.sae_token);
+ wpa_s->sme.sae_token = NULL;
+ sme_send_authentication(wpa_s, wpa_s->current_bss,
+ wpa_s->current_ssid, 0);
+ return 0;
+ } else if (auth_transaction == 2) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE confirm");
+ if (wpa_s->sme.sae.state != SAE_CONFIRMED)
+ return -1;
+ if (sae_check_confirm(&wpa_s->sme.sae, data, len) < 0)
+ return -1;
+ wpa_s->sme.sae.state = SAE_ACCEPTED;
+ sae_clear_temp_data(&wpa_s->sme.sae);
+ return 1;
+ }
+
+ return -1;
+}
+#endif /* CONFIG_SAE */
+
+
void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
{
struct wpa_ssid *ssid = wpa_s->current_ssid;
@@ -324,14 +544,34 @@
}
wpa_dbg(wpa_s, MSG_DEBUG, "SME: Authentication response: peer=" MACSTR
- " auth_type=%d status_code=%d",
+ " auth_type=%d auth_transaction=%d status_code=%d",
MAC2STR(data->auth.peer), data->auth.auth_type,
- data->auth.status_code);
+ data->auth.auth_transaction, data->auth.status_code);
wpa_hexdump(MSG_MSGDUMP, "SME: Authentication response IEs",
data->auth.ies, data->auth.ies_len);
eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
+#ifdef CONFIG_SAE
+ if (data->auth.auth_type == WLAN_AUTH_SAE) {
+ int res;
+ res = sme_sae_auth(wpa_s, data->auth.auth_transaction,
+ data->auth.status_code, data->auth.ies,
+ data->auth.ies_len);
+ if (res < 0) {
+ wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+ wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+
+ }
+ if (res != 1)
+ return;
+
+ 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);
+ }
+#endif /* CONFIG_SAE */
+
if (data->auth.status_code != WLAN_STATUS_SUCCESS) {
wpa_dbg(wpa_s, MSG_DEBUG, "SME: Authentication failed (status "
"code %d)", data->auth.status_code);
@@ -392,6 +632,10 @@
struct ieee80211_ht_capabilities htcaps;
struct ieee80211_ht_capabilities htcaps_mask;
#endif /* CONFIG_HT_OVERRIDES */
+#ifdef CONFIG_VHT_OVERRIDES
+ struct ieee80211_vht_capabilities vhtcaps;
+ struct ieee80211_vht_capabilities vhtcaps_mask;
+#endif /* CONFIG_VHT_OVERRIDES */
os_memset(¶ms, 0, sizeof(params));
params.bssid = bssid;
@@ -403,8 +647,9 @@
params.wpa_ie = wpa_s->sme.assoc_req_ie_len ?
wpa_s->sme.assoc_req_ie : NULL;
params.wpa_ie_len = wpa_s->sme.assoc_req_ie_len;
- params.pairwise_suite = cipher_suite2driver(wpa_s->pairwise_cipher);
- params.group_suite = cipher_suite2driver(wpa_s->group_cipher);
+ params.pairwise_suite =
+ wpa_cipher_to_suite_driver(wpa_s->pairwise_cipher);
+ params.group_suite = wpa_cipher_to_suite_driver(wpa_s->group_cipher);
#ifdef CONFIG_HT_OVERRIDES
os_memset(&htcaps, 0, sizeof(htcaps));
os_memset(&htcaps_mask, 0, sizeof(htcaps_mask));
@@ -412,6 +657,13 @@
params.htcaps_mask = (u8 *) &htcaps_mask;
wpa_supplicant_apply_ht_overrides(wpa_s, wpa_s->current_ssid, ¶ms);
#endif /* CONFIG_HT_OVERRIDES */
+#ifdef CONFIG_VHT_OVERRIDES
+ os_memset(&vhtcaps, 0, sizeof(vhtcaps));
+ os_memset(&vhtcaps_mask, 0, sizeof(vhtcaps_mask));
+ params.vhtcaps = &vhtcaps;
+ params.vhtcaps_mask = &vhtcaps_mask;
+ wpa_supplicant_apply_vht_overrides(wpa_s, wpa_s->current_ssid, ¶ms);
+#endif /* CONFIG_VHT_OVERRIDES */
#ifdef CONFIG_IEEE80211R
if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies) {
params.wpa_ie = wpa_s->sme.ft_ies;
@@ -631,6 +883,11 @@
#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 */
eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL);
eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
@@ -860,9 +1117,14 @@
if (!enable)
return;
- if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) || ssid == NULL ||
- ssid->mode != IEEE80211_MODE_INFRA)
- return; /* Not using station SME in wpa_supplicant */
+ /*
+ * Schedule OBSS scan if driver is using station SME in wpa_supplicant
+ * or it expects OBSS scan to be performed by wpa_supplicant.
+ */
+ if (!((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) ||
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OBSS_SCAN)) ||
+ ssid == NULL || ssid->mode != IEEE80211_MODE_INFRA)
+ return;
if (!wpa_s->hw.modes)
return;
@@ -1007,12 +1269,12 @@
{
struct wpa_ssid *ssid;
- if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME))
- return;
if (wpa_s->wpa_state != WPA_COMPLETED)
return;
ssid = wpa_s->current_ssid;
- if (ssid == NULL || ssid->ieee80211w == 0)
+ if (ssid == NULL ||
+ (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+ wpa_s->conf->pmf : ssid->ieee80211w) == NO_MGMT_FRAME_PROTECTION)
return;
if (os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0)
return;
diff --git a/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in b/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in
new file mode 100644
index 0000000..76aba12
--- /dev/null
+++ b/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in
@@ -0,0 +1,13 @@
+[Unit]
+Description=WPA supplicant daemon (interface- and nl80211 driver-specific version)
+Requires=sys-subsystem-net-devices-%i.device
+After=sys-subsystem-net-devices-%i.device
+
+# NetworkManager users will probably want the dbus version instead.
+
+[Service]
+Type=simple
+ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-nl80211-%I.conf -Dnl80211 -i%I
+
+[Install]
+Alias=multi-user.target.wants/wpa_supplicant-nl80211@wlan0.service
diff --git a/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in b/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in
new file mode 100644
index 0000000..ff384ae
--- /dev/null
+++ b/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in
@@ -0,0 +1,13 @@
+[Unit]
+Description=WPA supplicant daemon (interface- and wired driver-specific version)
+Requires=sys-subsystem-net-devices-%i.device
+After=sys-subsystem-net-devices-%i.device
+
+# NetworkManager users will probably want the dbus version instead.
+
+[Service]
+Type=simple
+ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-wired-%I.conf -Dwired -i%I
+
+[Install]
+Alias=multi-user.target.wants/wpa_supplicant-wired@wlan0.service
diff --git a/wpa_supplicant/systemd/wpa_supplicant.service.arg.in b/wpa_supplicant/systemd/wpa_supplicant.service.arg.in
new file mode 100644
index 0000000..c215567
--- /dev/null
+++ b/wpa_supplicant/systemd/wpa_supplicant.service.arg.in
@@ -0,0 +1,13 @@
+[Unit]
+Description=WPA supplicant daemon (interface-specific version)
+Requires=sys-subsystem-net-devices-%i.device
+After=sys-subsystem-net-devices-%i.device
+
+# NetworkManager users will probably want the dbus version instead.
+
+[Service]
+Type=simple
+ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-%I.conf -i%I
+
+[Install]
+Alias=multi-user.target.wants/wpa_supplicant@wlan0.service
diff --git a/wpa_supplicant/systemd/wpa_supplicant.service.in b/wpa_supplicant/systemd/wpa_supplicant.service.in
new file mode 100644
index 0000000..4351ad8
--- /dev/null
+++ b/wpa_supplicant/systemd/wpa_supplicant.service.in
@@ -0,0 +1,11 @@
+[Unit]
+Description=WPA supplicant
+
+[Service]
+Type=dbus
+BusName=fi.epitest.hostap.WPASupplicant
+ExecStart=@BINDIR@/wpa_supplicant -u
+
+[Install]
+WantedBy=multi-user.target
+Alias=dbus-fi.epitest.hostap.WPASupplicant.service
diff --git a/wpa_supplicant/tests/test_wpa.c b/wpa_supplicant/tests/test_wpa.c
index 0d659ad..ba2be6f 100644
--- a/wpa_supplicant/tests/test_wpa.c
+++ b/wpa_supplicant/tests/test_wpa.c
@@ -14,7 +14,7 @@
#include "../config.h"
#include "rsn_supp/wpa.h"
#include "rsn_supp/wpa_ie.h"
-#include "../hostapd/wpa.h"
+#include "ap/wpa_auth.h"
extern int wpa_debug_level;
diff --git a/wpa_supplicant/utils/log2pcap.py b/wpa_supplicant/utils/log2pcap.py
new file mode 100755
index 0000000..65e2fa1
--- /dev/null
+++ b/wpa_supplicant/utils/log2pcap.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2012, Intel Corporation
+#
+# Author: Johannes Berg <johannes@sipsolutions.net>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import sys, struct, re
+
+def write_pcap_header(pcap_file):
+ pcap_file.write(
+ struct.pack('<IHHIIII',
+ 0xa1b2c3d4, 2, 4, 0, 0, 65535,
+ 105 # raw 802.11 format
+ ))
+
+def pcap_addpacket(pcap_file, ts, data):
+ # ts in seconds, float
+ pcap_file.write(struct.pack('<IIII',
+ int(ts), int(1000000 * ts) % 1000000,
+ len(data), len(data)))
+ pcap_file.write(data)
+
+if __name__ == "__main__":
+ try:
+ input = sys.argv[1]
+ pcap = sys.argv[2]
+ except IndexError:
+ print "Usage: %s <log file> <pcap file>" % sys.argv[0]
+ sys.exit(2)
+
+ input_file = open(input, 'r')
+ pcap_file = open(pcap, 'w')
+ frame_re = re.compile(r'(([0-9]+.[0-9]{6}):\s*)?nl80211: MLME event frame - hexdump\(len=[0-9]*\):((\s*[0-9a-fA-F]{2})*)')
+
+ write_pcap_header(pcap_file)
+
+ for line in input_file:
+ m = frame_re.match(line)
+ if m is None:
+ continue
+ if m.group(2):
+ ts = float(m.group(2))
+ else:
+ ts = 0
+ hexdata = m.group(3)
+ hexdata = hexdata.split()
+ data = ''.join([chr(int(x, 16)) for x in hexdata])
+ pcap_addpacket(pcap_file, ts, data)
+
+ input_file.close()
+ pcap_file.close()
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index 98ce966..4d9e453 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -11,12 +11,12 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "rsn_supp/wpa.h"
-#include "../wpa_supplicant/wpa_supplicant_i.h"
-#include "../wpa_supplicant/driver_i.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "scan.h"
#define MAX_TFS_IE_LEN 1024
-#ifdef CONFIG_IEEE80211V
/* get the TFS IE from driver */
static int ieee80211_11_get_tfs_ie(struct wpa_supplicant *wpa_s, u8 *buf,
@@ -41,7 +41,7 @@
/* MLME-SLEEPMODE.request */
int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
- u8 action, u8 intval)
+ u8 action, u16 intval, struct wpabuf *tfs_req)
{
struct ieee80211_mgmt *mgmt;
int res;
@@ -53,6 +53,11 @@
enum wnm_oper tfs_oper = action == 0 ? WNM_SLEEP_TFS_REQ_IE_ADD :
WNM_SLEEP_TFS_REQ_IE_NONE;
+ wpa_printf(MSG_DEBUG, "WNM: Request to send WNM-Sleep Mode Request "
+ "action=%s to " MACSTR,
+ action == 0 ? "enter" : "exit",
+ MAC2STR(wpa_s->bssid));
+
/* WNM-Sleep Mode IE */
wnmsleep_ie_len = sizeof(struct wnm_sleep_element);
wnmsleep_ie = os_zalloc(sizeof(struct wnm_sleep_element));
@@ -62,25 +67,41 @@
wnmsleep_ie->len = wnmsleep_ie_len - 2;
wnmsleep_ie->action_type = action;
wnmsleep_ie->status = WNM_STATUS_SLEEP_ACCEPT;
- wnmsleep_ie->intval = intval;
+ wnmsleep_ie->intval = host_to_le16(intval);
+ wpa_hexdump(MSG_DEBUG, "WNM: WNM-Sleep Mode element",
+ (u8 *) wnmsleep_ie, wnmsleep_ie_len);
/* TFS IE(s) */
- wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN);
- if (wnmtfs_ie == NULL) {
- os_free(wnmsleep_ie);
- return -1;
+ if (tfs_req) {
+ wnmtfs_ie_len = wpabuf_len(tfs_req);
+ wnmtfs_ie = os_malloc(wnmtfs_ie_len);
+ if (wnmtfs_ie == NULL) {
+ os_free(wnmsleep_ie);
+ return -1;
+ }
+ os_memcpy(wnmtfs_ie, wpabuf_head(tfs_req), wnmtfs_ie_len);
+ } else {
+ wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN);
+ if (wnmtfs_ie == NULL) {
+ os_free(wnmsleep_ie);
+ return -1;
+ }
+ if (ieee80211_11_get_tfs_ie(wpa_s, wnmtfs_ie, &wnmtfs_ie_len,
+ tfs_oper)) {
+ wnmtfs_ie_len = 0;
+ os_free(wnmtfs_ie);
+ wnmtfs_ie = NULL;
+ }
}
- if (ieee80211_11_get_tfs_ie(wpa_s, wnmtfs_ie, &wnmtfs_ie_len,
- tfs_oper)) {
- wnmtfs_ie_len = 0;
- os_free(wnmtfs_ie);
- wnmtfs_ie = NULL;
- }
+ wpa_hexdump(MSG_DEBUG, "WNM: TFS Request element",
+ (u8 *) wnmtfs_ie, wnmtfs_ie_len);
mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + wnmtfs_ie_len);
if (mgmt == NULL) {
wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
"WNM-Sleep Request action frame");
+ os_free(wnmsleep_ie);
+ os_free(wnmtfs_ie);
return -1;
}
@@ -91,6 +112,7 @@
WLAN_FC_STYPE_ACTION);
mgmt->u.action.category = WLAN_ACTION_WNM;
mgmt->u.action.u.wnm_sleep_req.action = WNM_SLEEP_MODE_REQ;
+ mgmt->u.action.u.wnm_sleep_req.dialogtoken = 1;
os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable, wnmsleep_ie,
wnmsleep_ie_len);
/* copy TFS IE here */
@@ -117,6 +139,92 @@
}
+static void wnm_sleep_mode_enter_success(struct wpa_supplicant *wpa_s,
+ u8 *tfsresp_ie_start,
+ u8 *tfsresp_ie_end)
+{
+ wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_CONFIRM,
+ wpa_s->bssid, NULL, NULL);
+ /* remove GTK/IGTK ?? */
+
+ /* set the TFS Resp IE(s) */
+ if (tfsresp_ie_start && tfsresp_ie_end &&
+ tfsresp_ie_end - tfsresp_ie_start >= 0) {
+ u16 tfsresp_ie_len;
+ tfsresp_ie_len = (tfsresp_ie_end + tfsresp_ie_end[1] + 2) -
+ tfsresp_ie_start;
+ wpa_printf(MSG_DEBUG, "TFS Resp IE(s) found");
+ /* pass the TFS Resp IE(s) to driver for processing */
+ if (ieee80211_11_set_tfs_ie(wpa_s, wpa_s->bssid,
+ tfsresp_ie_start,
+ &tfsresp_ie_len,
+ WNM_SLEEP_TFS_RESP_IE_SET))
+ wpa_printf(MSG_DEBUG, "WNM: Fail to set TFS Resp IE");
+ }
+}
+
+
+static void wnm_sleep_mode_exit_success(struct wpa_supplicant *wpa_s,
+ const u8 *frm, u16 key_len_total)
+{
+ u8 *ptr, *end;
+ u8 gtk_len;
+
+ wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_CONFIRM, wpa_s->bssid,
+ NULL, NULL);
+
+ /* Install GTK/IGTK */
+
+ /* point to key data field */
+ ptr = (u8 *) frm + 1 + 1 + 2;
+ end = ptr + key_len_total;
+ wpa_hexdump_key(MSG_DEBUG, "WNM: Key Data", ptr, key_len_total);
+
+ while (ptr + 1 < end) {
+ if (ptr + 2 + ptr[1] > end) {
+ wpa_printf(MSG_DEBUG, "WNM: Invalid Key Data element "
+ "length");
+ if (end > ptr) {
+ wpa_hexdump(MSG_DEBUG, "WNM: Remaining data",
+ ptr, end - ptr);
+ }
+ break;
+ }
+ if (*ptr == WNM_SLEEP_SUBELEM_GTK) {
+ if (ptr[1] < 11 + 5) {
+ wpa_printf(MSG_DEBUG, "WNM: Too short GTK "
+ "subelem");
+ break;
+ }
+ gtk_len = *(ptr + 4);
+ if (ptr[1] < 11 + gtk_len ||
+ gtk_len < 5 || gtk_len > 32) {
+ wpa_printf(MSG_DEBUG, "WNM: Invalid GTK "
+ "subelem");
+ break;
+ }
+ wpa_wnmsleep_install_key(
+ wpa_s->wpa,
+ WNM_SLEEP_SUBELEM_GTK,
+ ptr);
+ ptr += 13 + gtk_len;
+#ifdef CONFIG_IEEE80211W
+ } else if (*ptr == WNM_SLEEP_SUBELEM_IGTK) {
+ if (ptr[1] < 2 + 6 + WPA_IGTK_LEN) {
+ wpa_printf(MSG_DEBUG, "WNM: Too short IGTK "
+ "subelem");
+ break;
+ }
+ wpa_wnmsleep_install_key(wpa_s->wpa,
+ WNM_SLEEP_SUBELEM_IGTK, ptr);
+ ptr += 10 + WPA_IGTK_LEN;
+#endif /* CONFIG_IEEE80211W */
+ } else
+ break; /* skip the loop */
+ }
+}
+
+
static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
const u8 *frm, int len)
{
@@ -126,21 +234,25 @@
*/
u8 *pos = (u8 *) frm; /* point to action field */
u16 key_len_total = le_to_host16(*((u16 *)(frm+2)));
- u8 gtk_len;
-#ifdef CONFIG_IEEE80211W
- u8 igtk_len;
-#endif /* CONFIG_IEEE80211W */
struct wnm_sleep_element *wnmsleep_ie = NULL;
/* multiple TFS Resp IE (assuming consecutive) */
u8 *tfsresp_ie_start = NULL;
u8 *tfsresp_ie_end = NULL;
- u16 tfsresp_ie_len = 0;
wpa_printf(MSG_DEBUG, "action=%d token = %d key_len_total = %d",
frm[0], frm[1], key_len_total);
pos += 4 + key_len_total;
+ if (pos > frm + len) {
+ wpa_printf(MSG_INFO, "WNM: Too short frame for Key Data field");
+ return;
+ }
while (pos - frm < len) {
u8 ie_len = *(pos + 1);
+ if (pos + 2 + ie_len > frm + len) {
+ wpa_printf(MSG_INFO, "WNM: Invalid IE len %u", ie_len);
+ break;
+ }
+ wpa_hexdump(MSG_DEBUG, "WNM: Element", pos, 2 + ie_len);
if (*pos == WLAN_EID_WNMSLEEP)
wnmsleep_ie = (struct wnm_sleep_element *) pos;
else if (*pos == WLAN_EID_TFS_RESP) {
@@ -157,86 +269,151 @@
return;
}
- if (wnmsleep_ie->status == WNM_STATUS_SLEEP_ACCEPT) {
+ if (wnmsleep_ie->status == WNM_STATUS_SLEEP_ACCEPT ||
+ wnmsleep_ie->status == WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) {
wpa_printf(MSG_DEBUG, "Successfully recv WNM-Sleep Response "
"frame (action=%d, intval=%d)",
wnmsleep_ie->action_type, wnmsleep_ie->intval);
- if (wnmsleep_ie->action_type == 0) {
- wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_CONFIRM,
- wpa_s->bssid, NULL, NULL);
- /* remove GTK/IGTK ?? */
-
- /* set the TFS Resp IE(s) */
- if (tfsresp_ie_start && tfsresp_ie_end &&
- tfsresp_ie_end - tfsresp_ie_start >= 0) {
- tfsresp_ie_len = (tfsresp_ie_end +
- tfsresp_ie_end[1] + 2) -
- tfsresp_ie_start;
- wpa_printf(MSG_DEBUG, "TFS Resp IE(s) found");
- /*
- * pass the TFS Resp IE(s) to driver for
- * processing
- */
- if (ieee80211_11_set_tfs_ie(
- wpa_s, wpa_s->bssid,
- tfsresp_ie_start,
- &tfsresp_ie_len,
- WNM_SLEEP_TFS_RESP_IE_SET))
- wpa_printf(MSG_DEBUG, "Fail to set "
- "TFS Resp IE");
- }
- } else if (wnmsleep_ie->action_type == 1) {
- wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_CONFIRM,
- wpa_s->bssid, NULL, NULL);
- /* Install GTK/IGTK */
- do {
- /* point to key data field */
- u8 *ptr = (u8 *) frm + 1 + 1 + 2;
- while (ptr < (u8 *) frm + 4 + key_len_total) {
- if (*ptr == WNM_SLEEP_SUBELEM_GTK) {
- gtk_len = *(ptr + 4);
- wpa_wnmsleep_install_key(
- wpa_s->wpa,
- WNM_SLEEP_SUBELEM_GTK,
- ptr);
- ptr += 13 + gtk_len;
-#ifdef CONFIG_IEEE80211W
- } else if (*ptr ==
- WNM_SLEEP_SUBELEM_IGTK) {
- igtk_len = WPA_IGTK_LEN;
- wpa_wnmsleep_install_key(
- wpa_s->wpa,
- WNM_SLEEP_SUBELEM_IGTK,
- ptr);
- ptr += 10 + WPA_IGTK_LEN;
-#endif /* CONFIG_IEEE80211W */
- } else
- break; /* skip the loop */
- }
- } while(0);
+ if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER) {
+ wnm_sleep_mode_enter_success(wpa_s, tfsresp_ie_start,
+ tfsresp_ie_end);
+ } else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) {
+ wnm_sleep_mode_exit_success(wpa_s, frm, key_len_total);
}
} else {
wpa_printf(MSG_DEBUG, "Reject recv WNM-Sleep Response frame "
"(action=%d, intval=%d)",
wnmsleep_ie->action_type, wnmsleep_ie->intval);
- if (wnmsleep_ie->action_type == 0)
+ if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER)
wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_FAIL,
wpa_s->bssid, NULL, NULL);
- else if (wnmsleep_ie->action_type == 1)
+ else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT)
wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_FAIL,
wpa_s->bssid, NULL, NULL);
}
}
+static void wnm_send_bss_transition_mgmt_resp(struct wpa_supplicant *wpa_s,
+ u8 dialog_token, u8 status,
+ u8 delay, const u8 *target_bssid)
+{
+ u8 buf[1000], *pos;
+ struct ieee80211_mgmt *mgmt;
+ size_t len;
+
+ 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);
+
+ mgmt = (struct ieee80211_mgmt *) buf;
+ os_memset(&buf, 0, sizeof(buf));
+ os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
+ os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
+ os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
+ mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_ACTION);
+ mgmt->u.action.category = WLAN_ACTION_WNM;
+ mgmt->u.action.u.bss_tm_resp.action = WNM_BSS_TRANS_MGMT_RESP;
+ mgmt->u.action.u.bss_tm_resp.dialog_token = dialog_token;
+ mgmt->u.action.u.bss_tm_resp.status_code = status;
+ mgmt->u.action.u.bss_tm_resp.bss_termination_delay = delay;
+ pos = mgmt->u.action.u.bss_tm_resp.variable;
+ if (target_bssid) {
+ os_memcpy(pos, target_bssid, ETH_ALEN);
+ pos += ETH_ALEN;
+ }
+
+ 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);
+}
+
+
+static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
+ const u8 *pos, const u8 *end,
+ int reply)
+{
+ u8 dialog_token;
+ u8 mode;
+ u16 disassoc_timer;
+
+ if (pos + 5 > end)
+ return;
+
+ dialog_token = pos[0];
+ mode = pos[1];
+ disassoc_timer = WPA_GET_LE16(pos + 2);
+
+ wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Request: "
+ "dialog_token=%u request_mode=0x%x "
+ "disassoc_timer=%u validity_interval=%u",
+ dialog_token, mode, disassoc_timer, pos[4]);
+ pos += 5;
+ if (mode & 0x08)
+ pos += 12; /* BSS Termination Duration */
+ if (mode & 0x10) {
+ char url[256];
+ if (pos + 1 > end || pos + 1 + pos[0] > end) {
+ wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition "
+ "Management Request (URL)");
+ return;
+ }
+ os_memcpy(url, pos + 1, pos[0]);
+ url[pos[0]] = '\0';
+ wpa_msg(wpa_s, MSG_INFO, "WNM: ESS Disassociation Imminent - "
+ "session_info_url=%s", url);
+ }
+
+ if (mode & 0x04) {
+ wpa_msg(wpa_s, MSG_INFO, "WNM: Disassociation Imminent - "
+ "Disassociation Timer %u", disassoc_timer);
+ if (disassoc_timer && !wpa_s->scanning) {
+ /* TODO: mark current BSS less preferred for
+ * selection */
+ wpa_printf(MSG_DEBUG, "Trying to find another BSS");
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ }
+ }
+
+ if (reply) {
+ /* TODO: add support for reporting Accept */
+ wnm_send_bss_transition_mgmt_resp(wpa_s, dialog_token,
+ 1 /* Reject - unspecified */,
+ 0, NULL);
+ }
+}
+
+
void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
struct rx_action *action)
{
- u8 *pos = (u8 *) action->data; /* point to action field */
- u8 act = *pos++;
- /* u8 dialog_token = *pos++; */
+ const u8 *pos, *end;
+ u8 act;
+
+ if (action->data == NULL || action->len == 0)
+ return;
+
+ pos = action->data;
+ end = pos + action->len;
+ act = *pos++;
+
+ wpa_printf(MSG_DEBUG, "WNM: RX action %u from " MACSTR,
+ act, MAC2STR(action->sa));
+ if (wpa_s->wpa_state < WPA_ASSOCIATED ||
+ os_memcmp(action->sa, wpa_s->bssid, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "WNM: Ignore unexpected WNM Action "
+ "frame");
+ return;
+ }
switch (act) {
+ case WNM_BSS_TRANS_MGMT_REQ:
+ ieee802_11_rx_bss_trans_mgmt_req(wpa_s, pos, end,
+ !(action->da[0] & 0x01));
+ break;
case WNM_SLEEP_MODE_RESP:
ieee802_11_rx_wnmsleep_resp(wpa_s, action->data, action->len);
break;
@@ -244,5 +421,3 @@
break;
}
}
-
-#endif /* CONFIG_IEEE80211V */
diff --git a/wpa_supplicant/wnm_sta.h b/wpa_supplicant/wnm_sta.h
index ba2535b..3f9d88b 100644
--- a/wpa_supplicant/wnm_sta.h
+++ b/wpa_supplicant/wnm_sta.h
@@ -13,7 +13,7 @@
struct wpa_supplicant;
int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
- u8 action, u8 intval);
+ u8 action, u16 intval, struct wpabuf *tfs_req);
void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
struct rx_action *action);
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 3986b9b..cdbe011 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -28,7 +28,7 @@
static const char *wpa_cli_version =
"wpa_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi> and contributors";
static const char *wpa_cli_license =
@@ -403,11 +403,7 @@
static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
{
-#ifdef ANDROID
char buf[4096];
-#else
- char buf[2048];
-#endif
#if defined(CONFIG_P2P) && defined(ANDROID_P2P)
char _cmd[256];
#endif
@@ -762,26 +758,6 @@
}
-#ifdef CONFIG_WPS_OOB
-static int wpa_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc, char *argv[])
-{
- if (argc != 3 && argc != 4) {
- printf("Invalid WPS_OOB command: need three or four "
- "arguments:\n"
- "- DEV_TYPE: use 'ufd' or 'nfc'\n"
- "- PATH: path of OOB device like '/mnt'\n"
- "- METHOD: OOB method 'pin-e' or 'pin-r', "
- "'cred'\n"
- "- DEV_NAME: (only for NFC) device name like "
- "'pn531'\n");
- return -1;
- }
-
- return wpa_cli_cmd(ctrl, "WPS_OOB", 3, argc, argv);
-}
-#endif /* CONFIG_WPS_OOB */
-
-
#ifdef CONFIG_WPS_NFC
static int wpa_cli_cmd_wps_nfc(struct wpa_ctrl *ctrl, int argc, char *argv[])
@@ -790,6 +766,13 @@
}
+static int wpa_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "WPS_NFC_CONFIG_TOKEN", 1, argc, argv);
+}
+
+
static int wpa_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -822,6 +805,79 @@
return ret;
}
+
+static int wpa_cli_cmd_nfc_get_handover_req(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "NFC_GET_HANDOVER_REQ", 2, argc, argv);
+}
+
+
+static int wpa_cli_cmd_nfc_get_handover_sel(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "NFC_GET_HANDOVER_SEL", 2, argc, argv);
+}
+
+
+static int wpa_cli_cmd_nfc_rx_handover_req(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ int ret;
+ char *buf;
+ size_t buflen;
+
+ if (argc != 1) {
+ printf("Invalid 'nfc_rx_handover_req' command - one argument "
+ "is required.\n");
+ return -1;
+ }
+
+ buflen = 21 + os_strlen(argv[0]);
+ buf = os_malloc(buflen);
+ if (buf == NULL)
+ return -1;
+ os_snprintf(buf, buflen, "NFC_RX_HANDOVER_REQ %s", argv[0]);
+
+ ret = wpa_ctrl_command(ctrl, buf);
+ os_free(buf);
+
+ return ret;
+}
+
+
+static int wpa_cli_cmd_nfc_rx_handover_sel(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ int ret;
+ char *buf;
+ size_t buflen;
+
+ if (argc != 1) {
+ printf("Invalid 'nfc_rx_handover_sel' command - one argument "
+ "is required.\n");
+ return -1;
+ }
+
+ buflen = 21 + os_strlen(argv[0]);
+ buf = os_malloc(buflen);
+ if (buf == NULL)
+ return -1;
+ os_snprintf(buf, buflen, "NFC_RX_HANDOVER_SEL %s", argv[0]);
+
+ ret = wpa_ctrl_command(ctrl, buf);
+ os_free(buf);
+
+ return ret;
+}
+
+
+static int wpa_cli_cmd_nfc_report_handover(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "NFC_REPORT_HANDOVER", 4, argc, argv);
+}
+
#endif /* CONFIG_WPS_NFC */
@@ -1330,7 +1386,7 @@
return 0;
}
- if (argc != 3) {
+ if (argc < 3) {
printf("Invalid SET_NETWORK command: needs three arguments\n"
"(network id, variable name, and value)\n");
return -1;
@@ -1413,7 +1469,7 @@
static int wpa_cli_cmd_scan(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- return wpa_ctrl_command(ctrl, "SCAN");
+ return wpa_cli_cmd(ctrl, "SCAN", 0, argc, argv);
}
@@ -2227,6 +2283,16 @@
#endif /* CONFIG_AUTOSCAN */
+#ifdef CONFIG_WNM
+
+static int wpa_cli_cmd_wnm_sleep(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "WNM_SLEEP", 0, argc, argv);
+}
+
+#endif /* CONFIG_WNM */
+
+
static int wpa_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
if (argc == 0)
@@ -2257,6 +2323,12 @@
#endif
+static int wpa_cli_cmd_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "FLUSH");
+}
+
+
enum wpa_cli_cmd_flags {
cli_cmd_flag_none = 0x00,
cli_cmd_flag_sensitive = 0x01
@@ -2417,7 +2489,7 @@
"<<idx> | <bssid>> = get detailed scan result info" },
{ "get_capability", wpa_cli_cmd_get_capability, NULL,
cli_cmd_flag_none,
- "<eap/pairwise/group/key_mgmt/proto/auth_alg/channels> "
+ "<eap/pairwise/group/key_mgmt/proto/auth_alg/channels/modes> "
"= get capabilies" },
{ "reconfigure", wpa_cli_cmd_reconfigure, NULL,
cli_cmd_flag_none,
@@ -2469,21 +2541,35 @@
"<PIN> = verify PIN checksum" },
{ "wps_cancel", wpa_cli_cmd_wps_cancel, NULL, cli_cmd_flag_none,
"Cancels the pending WPS operation" },
-#ifdef CONFIG_WPS_OOB
- { "wps_oob", wpa_cli_cmd_wps_oob, NULL,
- cli_cmd_flag_sensitive,
- "<DEV_TYPE> <PATH> <METHOD> [DEV_NAME] = start WPS OOB" },
-#endif /* CONFIG_WPS_OOB */
#ifdef CONFIG_WPS_NFC
{ "wps_nfc", wpa_cli_cmd_wps_nfc, wpa_cli_complete_bss,
cli_cmd_flag_none,
"[BSSID] = start Wi-Fi Protected Setup: NFC" },
+ { "wps_nfc_config_token", wpa_cli_cmd_wps_nfc_config_token, NULL,
+ cli_cmd_flag_none,
+ "<WPS|NDEF> = build configuration token" },
{ "wps_nfc_token", wpa_cli_cmd_wps_nfc_token, NULL,
cli_cmd_flag_none,
"<WPS|NDEF> = create password token" },
{ "wps_nfc_tag_read", wpa_cli_cmd_wps_nfc_tag_read, NULL,
cli_cmd_flag_sensitive,
"<hexdump of payload> = report read NFC tag with WPS data" },
+ { "nfc_get_handover_req", wpa_cli_cmd_nfc_get_handover_req, NULL,
+ cli_cmd_flag_none,
+ "<NDEF> <WPS> = create NFC handover request" },
+ { "nfc_get_handover_sel", wpa_cli_cmd_nfc_get_handover_sel, NULL,
+ cli_cmd_flag_none,
+ "<NDEF> <WPS> = create NFC handover select" },
+ { "nfc_rx_handover_req", wpa_cli_cmd_nfc_rx_handover_req, NULL,
+ cli_cmd_flag_none,
+ "<hexdump of payload> = report received NFC handover request" },
+ { "nfc_rx_handover_sel", wpa_cli_cmd_nfc_rx_handover_sel, NULL,
+ cli_cmd_flag_none,
+ "<hexdump of payload> = report received NFC handover select" },
+ { "nfc_report_handover", wpa_cli_cmd_nfc_report_handover, NULL,
+ cli_cmd_flag_none,
+ "<role> <type> <hexdump of req> <hexdump of sel> = report completed "
+ "NFC handover" },
#endif /* CONFIG_WPS_NFC */
{ "wps_reg", wpa_cli_cmd_wps_reg, wpa_cli_complete_bss,
cli_cmd_flag_sensitive,
@@ -2684,8 +2770,14 @@
{ "autoscan", wpa_cli_cmd_autoscan, NULL, cli_cmd_flag_none,
"[params] = Set or unset (if none) autoscan parameters" },
#endif /* CONFIG_AUTOSCAN */
+#ifdef CONFIG_WNM
+ { "wnm_sleep", wpa_cli_cmd_wnm_sleep, NULL, cli_cmd_flag_none,
+ "<enter/exit> [interval=#] = enter/exit WNM-Sleep mode" },
+#endif /* CONFIG_WNM */
{ "raw", wpa_cli_cmd_raw, NULL, cli_cmd_flag_sensitive,
"<params..> = Sent unprocessed command" },
+ { "flush", wpa_cli_cmd_flush, NULL, cli_cmd_flag_none,
+ "= flush wpa_supplicant state" },
#ifdef ANDROID
{ "driver", wpa_cli_cmd_driver, NULL,
cli_cmd_flag_none,
@@ -3367,11 +3459,7 @@
#endif /* CONFIG_CTRL_IFACE_UNIX */
#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
-#ifdef ANDROID
- char buf[4096], *pos;
-#else
char buf[2048], *pos;
-#endif
size_t len;
struct wpa_ctrl *ctrl;
int ret;
diff --git a/wpa_supplicant/wpa_gui-qt4/wpagui.cpp b/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
index 42e14f0..6bba8d2 100644
--- a/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
+++ b/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
@@ -709,7 +709,7 @@
void WpaGui::helpAbout()
{
QMessageBox::about(this, "wpa_gui for wpa_supplicant",
- "Copyright (c) 2003-2012,\n"
+ "Copyright (c) 2003-2013,\n"
"Jouni Malinen <j@w1.fi>\n"
"and contributors.\n"
"\n"
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index d8f3c44..4483173 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -52,7 +52,7 @@
const char *wpa_supplicant_version =
"wpa_supplicant v" VERSION_STR "\n"
-"Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi> and contributors";
const char *wpa_supplicant_license =
"This software may be distributed under the terms of the BSD license.\n"
@@ -190,7 +190,7 @@
MAC2STR(bssid));
wpa_blacklist_add(wpa_s, bssid);
wpa_sm_notify_disassoc(wpa_s->wpa);
- wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
wpa_s->reassociate = 1;
/*
@@ -199,16 +199,7 @@
*/
wpa_supplicant_req_scan(wpa_s, 1, 0);
-#ifdef CONFIG_P2P
- if (wpa_s->global->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled &&
- wpa_s->global->p2p != NULL) {
- wpa_s->global->p2p_cb_on_scan_complete = 0;
- if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
- wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
- "continued after timed out authentication");
- }
- }
-#endif /* CONFIG_P2P */
+ wpas_p2p_continue_after_scan(wpa_s);
}
@@ -408,6 +399,9 @@
os_free(wpa_s->confname);
wpa_s->confname = NULL;
+ os_free(wpa_s->confanother);
+ wpa_s->confanother = NULL;
+
wpa_sm_set_eapol(wpa_s->wpa, NULL);
eapol_sm_deinit(wpa_s->eapol);
wpa_s->eapol = NULL;
@@ -470,6 +464,11 @@
os_free(wpa_s->bssid_filter);
wpa_s->bssid_filter = NULL;
+ os_free(wpa_s->disallow_aps_bssid);
+ wpa_s->disallow_aps_bssid = NULL;
+ os_free(wpa_s->disallow_aps_ssid);
+ wpa_s->disallow_aps_ssid = NULL;
+
wnm_bss_keep_alive_deinit(wpa_s);
ext_password_deinit(wpa_s->ext_pw);
@@ -656,18 +655,17 @@
wpa_supplicant_notify_scanning(wpa_s, 0);
if (state == WPA_COMPLETED && wpa_s->new_connection) {
-#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
struct wpa_ssid *ssid = wpa_s->current_ssid;
+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED "- Connection to "
- MACSTR " completed %s [id=%d id_str=%s]",
- MAC2STR(wpa_s->bssid), wpa_s->reassociated_connection ?
- "(reauth)" : "(auth)",
+ MACSTR " completed (auth) [id=%d id_str=%s]",
+ MAC2STR(wpa_s->bssid),
ssid ? ssid->id : -1,
ssid && ssid->id_str ? ssid->id_str : "");
#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
wpas_clear_temp_disabled(wpa_s, ssid, 1);
+ wpa_s->extra_blacklist_count = 0;
wpa_s->new_connection = 0;
- wpa_s->reassociated_connection = 1;
wpa_drv_set_operstate(wpa_s, 1);
#ifndef IEEE8021X_EAPOL
wpa_drv_set_supp_port(wpa_s, 1);
@@ -771,12 +769,14 @@
if (wpa_s->confname == NULL)
return -1;
- conf = wpa_config_read(wpa_s->confname);
+ conf = wpa_config_read(wpa_s->confname, NULL);
if (conf == NULL) {
wpa_msg(wpa_s, MSG_ERROR, "Failed to parse the configuration "
"file '%s' - exiting", wpa_s->confname);
return -1;
}
+ wpa_config_read(wpa_s->confanother, conf);
+
conf->changed_parameters = (unsigned int) -1;
reconf_ctrl = !!conf->ctrl_interface != !!wpa_s->conf->ctrl_interface
@@ -847,26 +847,6 @@
}
-enum wpa_cipher cipher_suite2driver(int cipher)
-{
- switch (cipher) {
- case WPA_CIPHER_NONE:
- return CIPHER_NONE;
- case WPA_CIPHER_WEP40:
- return CIPHER_WEP40;
- case WPA_CIPHER_WEP104:
- return CIPHER_WEP104;
- case WPA_CIPHER_CCMP:
- return CIPHER_CCMP;
- case WPA_CIPHER_GCMP:
- return CIPHER_GCMP;
- case WPA_CIPHER_TKIP:
- default:
- return CIPHER_TKIP;
- }
-}
-
-
enum wpa_key_mgmt key_mgmt2driver(int key_mgmt)
{
switch (key_mgmt) {
@@ -931,7 +911,9 @@
#ifdef CONFIG_IEEE80211W
if (!(ie->capabilities & WPA_CAPABILITY_MFPC) &&
- ssid->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) {
+ (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+ wpa_s->conf->pmf : ssid->ieee80211w) ==
+ MGMT_FRAME_PROTECTION_REQUIRED) {
wpa_msg(wpa_s, MSG_INFO, "WPA: Driver associated with an AP "
"that does not support management frame protection - "
"reject");
@@ -1033,47 +1015,30 @@
}
sel = ie.group_cipher & ssid->group_cipher;
- if (sel & WPA_CIPHER_CCMP) {
- wpa_s->group_cipher = WPA_CIPHER_CCMP;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK CCMP");
- } else if (sel & WPA_CIPHER_GCMP) {
- wpa_s->group_cipher = WPA_CIPHER_GCMP;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK GCMP");
- } else if (sel & WPA_CIPHER_TKIP) {
- wpa_s->group_cipher = WPA_CIPHER_TKIP;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK TKIP");
- } else if (sel & WPA_CIPHER_WEP104) {
- wpa_s->group_cipher = WPA_CIPHER_WEP104;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK WEP104");
- } else if (sel & WPA_CIPHER_WEP40) {
- wpa_s->group_cipher = WPA_CIPHER_WEP40;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK WEP40");
- } else {
+ wpa_s->group_cipher = wpa_pick_group_cipher(sel);
+ if (wpa_s->group_cipher < 0) {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select group "
"cipher");
return -1;
}
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK %s",
+ wpa_cipher_txt(wpa_s->group_cipher));
sel = ie.pairwise_cipher & ssid->pairwise_cipher;
- if (sel & WPA_CIPHER_CCMP) {
- wpa_s->pairwise_cipher = WPA_CIPHER_CCMP;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK CCMP");
- } else if (sel & WPA_CIPHER_GCMP) {
- wpa_s->pairwise_cipher = WPA_CIPHER_GCMP;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK GCMP");
- } else if (sel & WPA_CIPHER_TKIP) {
- wpa_s->pairwise_cipher = WPA_CIPHER_TKIP;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK TKIP");
- } else if (sel & WPA_CIPHER_NONE) {
- wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK NONE");
- } else {
+ wpa_s->pairwise_cipher = wpa_pick_pairwise_cipher(sel, 1);
+ if (wpa_s->pairwise_cipher < 0) {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select pairwise "
"cipher");
return -1;
}
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK %s",
+ wpa_cipher_txt(wpa_s->pairwise_cipher));
sel = ie.key_mgmt & ssid->key_mgmt;
+#ifdef CONFIG_SAE
+ if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE))
+ sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE);
+#endif /* CONFIG_SAE */
if (0) {
#ifdef CONFIG_IEEE80211R
} else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) {
@@ -1083,6 +1048,14 @@
wpa_s->key_mgmt = WPA_KEY_MGMT_FT_PSK;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK");
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SAE
+ } else if (sel & WPA_KEY_MGMT_SAE) {
+ wpa_s->key_mgmt = WPA_KEY_MGMT_SAE;
+ wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT SAE");
+ } else if (sel & WPA_KEY_MGMT_FT_SAE) {
+ wpa_s->key_mgmt = WPA_KEY_MGMT_FT_SAE;
+ wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT FT/SAE");
+#endif /* CONFIG_SAE */
#ifdef CONFIG_IEEE80211W
} else if (sel & WPA_KEY_MGMT_IEEE8021X_SHA256) {
wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
@@ -1115,7 +1088,8 @@
#ifdef CONFIG_IEEE80211W
sel = ie.mgmt_group_cipher;
- if (ssid->ieee80211w == NO_MGMT_FRAME_PROTECTION ||
+ if ((ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+ wpa_s->conf->pmf : ssid->ieee80211w) == NO_MGMT_FRAME_PROTECTION ||
!(ie.capabilities & WPA_CAPABILITY_MFPC))
sel = 0;
if (sel & WPA_CIPHER_AES_128_CMAC) {
@@ -1128,7 +1102,9 @@
}
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
wpa_s->mgmt_group_cipher);
- wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP, ssid->ieee80211w);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP,
+ (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+ wpa_s->conf->pmf : ssid->ieee80211w));
#endif /* CONFIG_IEEE80211W */
if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) {
@@ -1213,6 +1189,70 @@
}
+static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
+{
+ *pos = 0x00;
+
+ switch (idx) {
+ case 0: /* Bits 0-7 */
+ break;
+ case 1: /* Bits 8-15 */
+ break;
+ case 2: /* Bits 16-23 */
+#ifdef CONFIG_WNM
+ *pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
+ *pos |= 0x08; /* Bit 19 - BSS Transition */
+#endif /* CONFIG_WNM */
+ break;
+ case 3: /* Bits 24-31 */
+#ifdef CONFIG_WNM
+ *pos |= 0x02; /* Bit 25 - SSID List */
+#endif /* CONFIG_WNM */
+#ifdef CONFIG_INTERWORKING
+ if (wpa_s->conf->interworking)
+ *pos |= 0x80; /* Bit 31 - Interworking */
+#endif /* CONFIG_INTERWORKING */
+ break;
+ case 4: /* Bits 32-39 */
+ break;
+ case 5: /* Bits 40-47 */
+ break;
+ case 6: /* Bits 48-55 */
+ break;
+ }
+}
+
+
+int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf)
+{
+ u8 *pos = buf;
+ u8 len = 4, i;
+
+ if (len < wpa_s->extended_capa_len)
+ len = wpa_s->extended_capa_len;
+
+ *pos++ = WLAN_EID_EXT_CAPAB;
+ *pos++ = len;
+ for (i = 0; i < len; i++, pos++) {
+ wpas_ext_capab_byte(wpa_s, pos, i);
+
+ if (i < wpa_s->extended_capa_len) {
+ *pos &= ~wpa_s->extended_capa_mask[i];
+ *pos |= wpa_s->extended_capa[i];
+ }
+ }
+
+ while (len > 0 && buf[1 + len] == 0) {
+ len--;
+ buf[1] = len;
+ }
+ if (len == 0)
+ return 0;
+
+ return 2 + len;
+}
+
+
/**
* wpa_supplicant_associate - Request association
* @wpa_s: Pointer to wpa_supplicant data
@@ -1234,6 +1274,8 @@
struct wpa_driver_capa capa;
int assoc_failed = 0;
struct wpa_ssid *old_ssid;
+ u8 ext_capab[10];
+ int ext_capab_len;
#ifdef CONFIG_HT_OVERRIDES
struct ieee80211_ht_capabilities htcaps;
struct ieee80211_ht_capabilities htcaps_mask;
@@ -1309,7 +1351,7 @@
(ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
/* Use ap_scan==1 style network selection to find the network
*/
- wpa_s->scan_req = 2;
+ wpa_s->scan_req = MANUAL_SCAN_REQ;
wpa_s->reassociate = 1;
wpa_supplicant_req_scan(wpa_s, 0, 0);
return;
@@ -1347,11 +1389,12 @@
wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
wpa_key_mgmt_wpa(ssid->key_mgmt)) {
int try_opportunistic;
- try_opportunistic = ssid->proactive_key_caching &&
+ try_opportunistic = (ssid->proactive_key_caching < 0 ?
+ wpa_s->conf->okc :
+ ssid->proactive_key_caching) &&
(ssid->proto & WPA_PROTO_RSN);
if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
- wpa_s->current_ssid,
- try_opportunistic) == 0)
+ ssid, try_opportunistic) == 0)
eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1);
wpa_ie_len = sizeof(wpa_ie);
if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
@@ -1445,26 +1488,21 @@
}
#endif /* CONFIG_HS20 */
-#ifdef CONFIG_INTERWORKING
- if (wpa_s->conf->interworking) {
+ ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab);
+ if (ext_capab_len > 0) {
u8 *pos = wpa_ie;
if (wpa_ie_len > 0 && pos[0] == WLAN_EID_RSN)
pos += 2 + pos[1];
- os_memmove(pos + 6, pos, wpa_ie_len - (pos - wpa_ie));
- wpa_ie_len += 6;
- *pos++ = WLAN_EID_EXT_CAPAB;
- *pos++ = 4;
- *pos++ = 0x00;
- *pos++ = 0x00;
- *pos++ = 0x00;
- *pos++ = 0x80; /* Bit 31 - Interworking */
+ os_memmove(pos + ext_capab_len, pos,
+ wpa_ie_len - (pos - wpa_ie));
+ wpa_ie_len += ext_capab_len;
+ os_memcpy(pos, ext_capab, ext_capab_len);
}
-#endif /* CONFIG_INTERWORKING */
wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
use_crypt = 1;
- cipher_pairwise = cipher_suite2driver(wpa_s->pairwise_cipher);
- cipher_group = cipher_suite2driver(wpa_s->group_cipher);
+ cipher_pairwise = wpa_cipher_to_suite_driver(wpa_s->pairwise_cipher);
+ cipher_group = wpa_cipher_to_suite_driver(wpa_s->group_cipher);
if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE)
@@ -1552,8 +1590,10 @@
params.drop_unencrypted = use_crypt;
#ifdef CONFIG_IEEE80211W
- params.mgmt_frame_protection = ssid->ieee80211w;
- if (ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION && bss) {
+ params.mgmt_frame_protection =
+ ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+ wpa_s->conf->pmf : ssid->ieee80211w;
+ if (params.mgmt_frame_protection != NO_MGMT_FRAME_PROTECTION && bss) {
const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
struct wpa_ie_data ie;
if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie) == 0 &&
@@ -1590,16 +1630,8 @@
((freq = wpa_drv_shared_freq(wpa_s)) > 0) && (freq != params.freq)) {
wpa_printf(MSG_DEBUG, "Shared interface with conflicting frequency found (%d != %d)"
, freq, params.freq);
- if (wpas_p2p_handle_frequency_conflicts(wpa_s, params.freq) < 0) {
- /* Handling conflicts failed. Disable the current connect req and
- * notify the userspace to take appropriate action */
- wpa_printf(MSG_DEBUG, "proiritize is not set. Notifying user space to handle the case");
- wpa_supplicant_disable_network(wpa_s, ssid);
- wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_FREQ_CONFLICT
- " id=%d", ssid->id);
- os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
+ if (wpas_p2p_handle_frequency_conflicts(wpa_s, params.freq, ssid) < 0)
return;
- }
}
#endif
ret = wpa_drv_associate(wpa_s, ¶ms);
@@ -1694,33 +1726,6 @@
/**
- * wpa_supplicant_disassociate - Disassociate the current connection
- * @wpa_s: Pointer to wpa_supplicant data
- * @reason_code: IEEE 802.11 reason code for the disassociate frame
- *
- * This function is used to request %wpa_supplicant to disassociate with the
- * current AP.
- */
-void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
- int reason_code)
-{
- u8 *addr = NULL;
- union wpa_event_data event;
-
- if (!is_zero_ether_addr(wpa_s->bssid)) {
- wpa_drv_disassociate(wpa_s, wpa_s->bssid, reason_code);
- addr = wpa_s->bssid;
- os_memset(&event, 0, sizeof(event));
- event.disassoc_info.reason_code = (u16) reason_code;
- event.disassoc_info.locally_generated = 1;
- wpa_supplicant_event(wpa_s, EVENT_DISASSOC, &event);
- }
-
- wpa_supplicant_clear_connection(wpa_s, addr);
-}
-
-
-/**
* wpa_supplicant_deauthenticate - Deauthenticate the current connection
* @wpa_s: Pointer to wpa_supplicant data
* @reason_code: IEEE 802.11 reason code for the deauthenticate frame
@@ -1733,19 +1738,65 @@
{
u8 *addr = NULL;
union wpa_event_data event;
+ int zero_addr = 0;
- if (!is_zero_ether_addr(wpa_s->bssid)) {
- wpa_drv_deauthenticate(wpa_s, wpa_s->bssid, reason_code);
+ wpa_dbg(wpa_s, MSG_DEBUG, "Request to deauthenticate - bssid=" MACSTR
+ " pending_bssid=" MACSTR " reason=%d state=%s",
+ MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
+ reason_code, wpa_supplicant_state_txt(wpa_s->wpa_state));
+
+ if (!is_zero_ether_addr(wpa_s->bssid))
addr = wpa_s->bssid;
+ else if (!is_zero_ether_addr(wpa_s->pending_bssid) &&
+ (wpa_s->wpa_state == WPA_AUTHENTICATING ||
+ wpa_s->wpa_state == WPA_ASSOCIATING))
+ addr = wpa_s->pending_bssid;
+ else if (wpa_s->wpa_state == WPA_ASSOCIATING) {
+ /*
+ * When using driver-based BSS selection, we may not know the
+ * BSSID with which we are currently trying to associate. We
+ * need to notify the driver of this disconnection even in such
+ * a case, so use the all zeros address here.
+ */
+ addr = wpa_s->bssid;
+ zero_addr = 1;
+ }
+
+#ifdef CONFIG_TDLS
+ wpa_tdls_teardown_peers(wpa_s->wpa);
+#endif /* CONFIG_TDLS */
+
+ if (addr) {
+ wpa_drv_deauthenticate(wpa_s, addr, reason_code);
os_memset(&event, 0, sizeof(event));
event.deauth_info.reason_code = (u16) reason_code;
event.deauth_info.locally_generated = 1;
wpa_supplicant_event(wpa_s, EVENT_DEAUTH, &event);
+ if (zero_addr)
+ addr = NULL;
}
wpa_supplicant_clear_connection(wpa_s, addr);
}
+static void wpa_supplicant_enable_one_network(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ if (!ssid || !ssid->disabled || ssid->disabled == 2)
+ return;
+
+ ssid->disabled = 0;
+ wpas_clear_temp_disabled(wpa_s, ssid, 1);
+ wpas_notify_network_enabled_changed(wpa_s, ssid);
+
+ /*
+ * Try to reassociate since there is no current configuration and a new
+ * network was made available.
+ */
+ if (!wpa_s->current_ssid)
+ wpa_s->reassociate = 1;
+}
+
/**
* wpa_supplicant_enable_network - Mark a configured network as enabled
@@ -1757,48 +1808,20 @@
void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
- struct wpa_ssid *other_ssid;
- int was_disabled;
-
if (ssid == NULL) {
- for (other_ssid = wpa_s->conf->ssid; other_ssid;
- other_ssid = other_ssid->next) {
- if (other_ssid->disabled == 2)
- continue; /* do not change persistent P2P group
- * data */
- if (other_ssid == wpa_s->current_ssid &&
- other_ssid->disabled)
- wpa_s->reassociate = 1;
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
+ wpa_supplicant_enable_one_network(wpa_s, ssid);
+ } else
+ wpa_supplicant_enable_one_network(wpa_s, ssid);
- was_disabled = other_ssid->disabled;
-
- other_ssid->disabled = 0;
- if (was_disabled)
- wpas_clear_temp_disabled(wpa_s, other_ssid, 0);
-
- if (was_disabled != other_ssid->disabled)
- wpas_notify_network_enabled_changed(
- wpa_s, other_ssid);
- }
- if (wpa_s->reassociate)
- wpa_supplicant_req_scan(wpa_s, 0, 0);
- } else if (ssid->disabled && ssid->disabled != 2) {
- if (wpa_s->current_ssid == NULL) {
- /*
- * Try to reassociate since there is no current
- * configuration and a new network was made available.
- */
- wpa_s->reassociate = 1;
- wpa_supplicant_req_scan(wpa_s, 0, 0);
+ if (wpa_s->reassociate) {
+ if (wpa_s->sched_scanning) {
+ wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to add "
+ "new network to scan filters");
+ wpa_supplicant_cancel_sched_scan(wpa_s);
}
- was_disabled = ssid->disabled;
-
- ssid->disabled = 0;
- wpas_clear_temp_disabled(wpa_s, ssid, 1);
-
- if (was_disabled != ssid->disabled)
- wpas_notify_network_enabled_changed(wpa_s, ssid);
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
}
}
@@ -1817,6 +1840,9 @@
int was_disabled;
if (ssid == NULL) {
+ if (wpa_s->sched_scanning)
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+
for (other_ssid = wpa_s->conf->ssid; other_ssid;
other_ssid = other_ssid->next) {
was_disabled = other_ssid->disabled;
@@ -1831,19 +1857,26 @@
wpa_s, other_ssid);
}
if (wpa_s->current_ssid)
- wpa_supplicant_disassociate(
+ wpa_supplicant_deauthenticate(
wpa_s, WLAN_REASON_DEAUTH_LEAVING);
} else if (ssid->disabled != 2) {
if (ssid == wpa_s->current_ssid)
- wpa_supplicant_disassociate(
+ wpa_supplicant_deauthenticate(
wpa_s, WLAN_REASON_DEAUTH_LEAVING);
was_disabled = ssid->disabled;
ssid->disabled = 1;
- if (was_disabled != ssid->disabled)
+ if (was_disabled != ssid->disabled) {
wpas_notify_network_enabled_changed(wpa_s, ssid);
+ if (wpa_s->sched_scanning) {
+ 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);
+ }
+ }
}
}
@@ -1861,7 +1894,7 @@
int disconnected = 0;
if (ssid && ssid != wpa_s->current_ssid && wpa_s->current_ssid) {
- wpa_supplicant_disassociate(
+ wpa_supplicant_deauthenticate(
wpa_s, WLAN_REASON_DEAUTH_LEAVING);
disconnected = 1;
}
@@ -1899,7 +1932,9 @@
wpa_s->connect_without_scan = NULL;
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
- wpa_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0);
+
+ if (wpa_supplicant_fast_associate(wpa_s) != 1)
+ wpa_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0);
if (ssid)
wpas_notify_network_selected(wpa_s, ssid);
@@ -2004,7 +2039,7 @@
}
wpa_msg(wpa_s, MSG_DEBUG, "Setting scan interval: %d sec",
scan_interval);
- wpa_s->scan_interval = scan_interval;
+ wpa_supplicant_update_scan_int(wpa_s, scan_interval);
return 0;
}
@@ -2200,17 +2235,28 @@
wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);
- if (wpa_s->wpa_state < WPA_ASSOCIATED) {
+ if (wpa_s->wpa_state < WPA_ASSOCIATED ||
+ (wpa_s->last_eapol_matches_bssid &&
+#ifdef CONFIG_AP
+ !wpa_s->ap_iface &&
+#endif /* CONFIG_AP */
+ os_memcmp(src_addr, wpa_s->bssid, ETH_ALEN) != 0)) {
/*
* There is possible race condition between receiving the
* association event and the EAPOL frame since they are coming
* through different paths from the driver. In order to avoid
* issues in trying to process the EAPOL frame before receiving
* association information, lets queue it for processing until
- * the association event is received.
+ * the association event is received. This may also be needed in
+ * driver-based roaming case, so also use src_addr != BSSID as a
+ * trigger if we have previously confirmed that the
+ * Authenticator uses BSSID as the src_addr (which is not the
+ * case with wired IEEE 802.1X).
*/
wpa_dbg(wpa_s, MSG_DEBUG, "Not associated - Delay processing "
- "of received EAPOL frame");
+ "of received EAPOL frame (state=%s bssid=" MACSTR ")",
+ wpa_supplicant_state_txt(wpa_s->wpa_state),
+ MAC2STR(wpa_s->bssid));
wpabuf_free(wpa_s->pending_eapol_rx);
wpa_s->pending_eapol_rx = wpabuf_alloc_copy(buf, len);
if (wpa_s->pending_eapol_rx) {
@@ -2221,6 +2267,9 @@
return;
}
+ wpa_s->last_eapol_matches_bssid =
+ os_memcmp(src_addr, wpa_s->bssid, ETH_ALEN) == 0;
+
#ifdef CONFIG_AP
if (wpa_s->ap_iface) {
wpa_supplicant_ap_rx_eapol(wpa_s, src_addr, buf, len);
@@ -2419,7 +2468,7 @@
wpa_s = os_zalloc(sizeof(*wpa_s));
if (wpa_s == NULL)
return NULL;
- wpa_s->scan_req = 1;
+ wpa_s->scan_req = INITIAL_SCAN_REQ;
wpa_s->scan_interval = 5;
wpa_s->new_connection = 1;
wpa_s->parent = wpa_s;
@@ -2579,6 +2628,28 @@
}
+static int wpa_set_disable_sgi(struct wpa_supplicant *wpa_s,
+ struct ieee80211_ht_capabilities *htcaps,
+ struct ieee80211_ht_capabilities *htcaps_mask,
+ int disabled)
+{
+ /* Masking these out disables SGI */
+ u16 msk = host_to_le16(HT_CAP_INFO_SHORT_GI20MHZ |
+ HT_CAP_INFO_SHORT_GI40MHZ);
+
+ wpa_msg(wpa_s, MSG_DEBUG, "set_disable_sgi: %d", disabled);
+
+ if (disabled)
+ htcaps->ht_capabilities_info &= ~msk;
+ else
+ htcaps->ht_capabilities_info |= msk;
+
+ htcaps_mask->ht_capabilities_info |= msk;
+
+ return 0;
+}
+
+
void wpa_supplicant_apply_ht_overrides(
struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
struct wpa_driver_associate_params *params)
@@ -2601,11 +2672,60 @@
wpa_set_ampdu_factor(wpa_s, htcaps, htcaps_mask, ssid->ampdu_factor);
wpa_set_ampdu_density(wpa_s, htcaps, htcaps_mask, ssid->ampdu_density);
wpa_set_disable_ht40(wpa_s, htcaps, htcaps_mask, ssid->disable_ht40);
+ wpa_set_disable_sgi(wpa_s, htcaps, htcaps_mask, ssid->disable_sgi);
}
#endif /* CONFIG_HT_OVERRIDES */
+#ifdef CONFIG_VHT_OVERRIDES
+void wpa_supplicant_apply_vht_overrides(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ struct wpa_driver_associate_params *params)
+{
+ struct ieee80211_vht_capabilities *vhtcaps;
+ struct ieee80211_vht_capabilities *vhtcaps_mask;
+
+ if (!ssid)
+ return;
+
+ params->disable_vht = ssid->disable_vht;
+
+ vhtcaps = (void *) params->vhtcaps;
+ vhtcaps_mask = (void *) params->vhtcaps_mask;
+
+ if (!vhtcaps || !vhtcaps_mask)
+ return;
+
+ vhtcaps->vht_capabilities_info = ssid->vht_capa;
+ vhtcaps_mask->vht_capabilities_info = ssid->vht_capa_mask;
+
+#define OVERRIDE_MCS(i) \
+ if (ssid->vht_tx_mcs_nss_ ##i >= 0) { \
+ vhtcaps_mask->vht_supported_mcs_set.tx_map |= \
+ 3 << 2 * (i - 1); \
+ vhtcaps->vht_supported_mcs_set.tx_map |= \
+ ssid->vht_tx_mcs_nss_ ##i << 2 * (i - 1); \
+ } \
+ if (ssid->vht_rx_mcs_nss_ ##i >= 0) { \
+ vhtcaps_mask->vht_supported_mcs_set.rx_map |= \
+ 3 << 2 * (i - 1); \
+ vhtcaps->vht_supported_mcs_set.rx_map |= \
+ ssid->vht_rx_mcs_nss_ ##i << 2 * (i - 1); \
+ }
+
+ OVERRIDE_MCS(1);
+ OVERRIDE_MCS(2);
+ OVERRIDE_MCS(3);
+ OVERRIDE_MCS(4);
+ OVERRIDE_MCS(5);
+ OVERRIDE_MCS(6);
+ OVERRIDE_MCS(7);
+ OVERRIDE_MCS(8);
+}
+#endif /* CONFIG_VHT_OVERRIDES */
+
+
static int pcsc_reader_init(struct wpa_supplicant *wpa_s)
{
#ifdef PCSC_FUNCS
@@ -2707,12 +2827,14 @@
#else /* CONFIG_BACKEND_FILE */
wpa_s->confname = os_strdup(iface->confname);
#endif /* CONFIG_BACKEND_FILE */
- wpa_s->conf = wpa_config_read(wpa_s->confname);
+ wpa_s->conf = wpa_config_read(wpa_s->confname, NULL);
if (wpa_s->conf == NULL) {
wpa_printf(MSG_ERROR, "Failed to read or parse "
"configuration '%s'.", wpa_s->confname);
return -1;
}
+ wpa_s->confanother = os_rel2abs_path(iface->confanother);
+ wpa_config_read(wpa_s->confanother, wpa_s->conf);
/*
* Override ctrl_interface and driver_param if set on command
@@ -2847,6 +2969,9 @@
wpa_s->max_match_sets = capa.max_match_sets;
wpa_s->max_remain_on_chan = capa.max_remain_on_chan;
wpa_s->max_stations = capa.max_stations;
+ wpa_s->extended_capa = capa.extended_capa;
+ wpa_s->extended_capa_mask = capa.extended_capa_mask;
+ wpa_s->extended_capa_len = capa.extended_capa_len;
}
if (wpa_s->max_remain_on_chan == 0)
wpa_s->max_remain_on_chan = 1000;
@@ -3058,6 +3183,8 @@
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);
os_free(wpa_s);
@@ -3452,6 +3579,12 @@
}
}
+ /*
+ * Add previous failure count in case the temporary blacklist was
+ * cleared due to no other BSSes being available.
+ */
+ count += wpa_s->extra_blacklist_count;
+
switch (count) {
case 1:
timeout = 100;
@@ -3462,10 +3595,17 @@
case 3:
timeout = 1000;
break;
- default:
+ case 4:
timeout = 5000;
+ break;
+ default:
+ timeout = 10000;
+ break;
}
+ wpa_dbg(wpa_s, MSG_DEBUG, "Blacklist count %d --> request scan in %d "
+ "ms", count, timeout);
+
/*
* TODO: if more than one possible AP is available in scan results,
* could try the other ones before requesting a new scan.
@@ -3473,16 +3613,7 @@
wpa_supplicant_req_scan(wpa_s, timeout / 1000,
1000 * (timeout % 1000));
-#ifdef CONFIG_P2P
- if (wpa_s->global->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled &&
- wpa_s->global->p2p != NULL) {
- wpa_s->global->p2p_cb_on_scan_complete = 0;
- if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
- wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
- "continued after failed association");
- }
- }
-#endif /* CONFIG_P2P */
+ wpas_p2p_continue_after_scan(wpa_s);
}
@@ -3672,3 +3803,60 @@
if (clear_failures)
ssid->auth_failures = 0;
}
+
+
+int disallowed_bssid(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+ size_t i;
+
+ if (wpa_s->disallow_aps_bssid == NULL)
+ return 0;
+
+ for (i = 0; i < wpa_s->disallow_aps_bssid_count; i++) {
+ if (os_memcmp(wpa_s->disallow_aps_bssid + i * ETH_ALEN,
+ bssid, ETH_ALEN) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid,
+ size_t ssid_len)
+{
+ size_t i;
+
+ if (wpa_s->disallow_aps_ssid == NULL || ssid == NULL)
+ return 0;
+
+ for (i = 0; i < wpa_s->disallow_aps_ssid_count; i++) {
+ struct wpa_ssid_value *s = &wpa_s->disallow_aps_ssid[i];
+ if (ssid_len == s->ssid_len &&
+ os_memcmp(ssid, s->ssid, ssid_len) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * wpas_request_connection - Request a new connection
+ * @wpa_s: Pointer to the network interface
+ *
+ * This function is used to request a new connection to be found. It will mark
+ * the interface to allow reassociation and request a new scan to find a
+ * suitable network to connect to.
+ */
+void wpas_request_connection(struct wpa_supplicant *wpa_s)
+{
+ wpa_s->normal_scans = 0;
+ wpa_supplicant_reinit_autoscan(wpa_s);
+ wpa_s->extra_blacklist_count = 0;
+ wpa_s->disconnected = 0;
+ wpa_s->reassociate = 1;
+
+ if (wpa_supplicant_fast_associate(wpa_s) != 1)
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+}
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 0b0ea88..0935a06 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -265,6 +265,51 @@
# inactive stations.
#p2p_go_max_inactivity=300
+# Opportunistic Key Caching (also known as Proactive Key Caching) default
+# This parameter can be used to set the default behavior for the
+# proactive_key_caching parameter. By default, OKC is disabled unless enabled
+# with the global okc=1 parameter or with the per-network
+# proactive_key_caching=1 parameter. With okc=1, OKC is enabled by default, but
+# can be disabled with per-network proactive_key_caching=0 parameter.
+#okc=0
+
+# Protected Management Frames default
+# This parameter can be used to set the default behavior for the ieee80211w
+# parameter. By default, PMF is disabled unless enabled with the global pmf=1/2
+# parameter or with the per-network ieee80211w=1/2 parameter. With pmf=1/2, PMF
+# is enabled/required by default, but can be disabled with the per-network
+# ieee80211w parameter.
+#pmf=0
+
+# Enabled SAE finite cyclic groups in preference order
+# By default (if this parameter is not set), the mandatory group 19 (ECC group
+# defined over a 256-bit prime order field) is preferred, but other groups are
+# also enabled. If this parameter is set, the groups will be tried in the
+# indicated order. The group values are listed in the IANA registry:
+# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-9
+#sae_groups=21 20 19 26 25
+
+# Default value for DTIM period (if not overridden in network block)
+#dtim_period=2
+
+# Default value for Beacon interval (if not overridden in network block)
+#beacon_int=100
+
+# Additional vendor specific elements for Beacon and Probe Response frames
+# This parameter can be used to add additional vendor specific element(s) into
+# the end of the Beacon and Probe Response frames. The format for these
+# element(s) is a hexdump of the raw information elements (id+len+payload for
+# one or more elements). This is used in AP and P2P GO modes.
+#ap_vendor_elements=dd0411223301
+
+# Ignore scan results older than request
+#
+# The driver may have a cache of scan results that makes it return
+# information that is older than our scan trigger. This parameter can
+# be used to configure such old information to be ignored instead of
+# allowing it to update the internal BSS table.
+#ignore_old_scan_res=0
+
# Interworking (IEEE 802.11u)
@@ -374,6 +419,11 @@
# phase2: Pre-configure Phase 2 (inner authentication) parameters
# This optional field is used with like the 'eap' parameter.
#
+# excluded_ssid: Excluded SSID
+# This optional field can be used to excluded specific SSID(s) from
+# matching with the network. Multiple entries can be used to specify more
+# than one SSID.
+#
# for example:
#
#cred={
@@ -474,6 +524,23 @@
# set, scan results that do not match any of the specified frequencies are not
# considered when selecting a BSS.
#
+# bgscan: Background scanning
+# wpa_supplicant behavior for background scanning can be specified by
+# configuring a bgscan module. These modules are responsible for requesting
+# background scans for the purpose of roaming within an ESS (i.e., within a
+# single network block with all the APs using the same SSID). The bgscan
+# parameter uses following format: "<bgscan module name>:<module parameters>"
+# Following bgscan modules are available:
+# simple - Periodic background scans based on signal strength
+# bgscan="simple:<short bgscan interval in seconds>:<signal strength threshold>:
+# <long interval>"
+# bgscan="simple:30:-45:300"
+# learn - Learn channels used by the network and try to avoid bgscans on other
+# channels (experimental)
+# bgscan="learn:<short bgscan interval in seconds>:<signal strength threshold>:
+# <long interval>[:<database file name>]"
+# bgscan="learn:30:-45:300:/etc/wpa_supplicant/network1.bgscan"
+#
# proto: list of accepted protocols
# WPA = WPA/IEEE 802.11i/D3.0
# RSN = WPA2/IEEE 802.11i (also WPA2 can be used as an alias for RSN)
@@ -490,7 +557,7 @@
# If not set, this defaults to: WPA-PSK WPA-EAP
#
# ieee80211w: whether management frame protection is enabled
-# 0 = disabled (default)
+# 0 = disabled (default unless changed with the global pmf parameter)
# 1 = optional
# 2 = required
# The most common configuration options for this based on the PMF (protected
@@ -548,7 +615,7 @@
#
# proactive_key_caching:
# Enable/disable opportunistic PMKSA caching for WPA2.
-# 0 = disabled (default)
+# 0 = disabled (default unless changed with the global okc parameter)
# 1 = enabled
#
# wep_key0..3: Static WEP key (ASCII in double quotation, e.g. "abcde" or
@@ -787,6 +854,51 @@
# DTIM period in Beacon intervals for AP mode (default: 2)
#dtim_period=2
+# Beacon interval (default: 100 TU)
+#beacon_int=100
+
+# disable_ht: Whether HT (802.11n) should be disabled.
+# 0 = HT enabled (if AP supports it)
+# 1 = HT disabled
+#
+# disable_ht40: Whether HT-40 (802.11n) should be disabled.
+# 0 = HT-40 enabled (if AP supports it)
+# 1 = HT-40 disabled
+#
+# disable_sgi: Whether SGI (short guard interval) should be disabled.
+# 0 = SGI enabled (if AP supports it)
+# 1 = SGI disabled
+#
+# ht_mcs: Configure allowed MCS rates.
+# Parsed as an array of bytes, in base-16 (ascii-hex)
+# ht_mcs="" // Use all available (default)
+# ht_mcs="0xff 00 00 00 00 00 00 00 00 00 " // Use MCS 0-7 only
+# ht_mcs="0xff ff 00 00 00 00 00 00 00 00 " // Use MCS 0-15 only
+#
+# disable_max_amsdu: Whether MAX_AMSDU should be disabled.
+# -1 = Do not make any changes.
+# 0 = Enable MAX-AMSDU if hardware supports it.
+# 1 = Disable AMSDU
+#
+# ampdu_density: Allow overriding AMPDU density configuration.
+# Treated as hint by the kernel.
+# -1 = Do not make any changes.
+# 0-3 = Set AMPDU density (aka factor) to specified value.
+
+# disable_vht: Whether VHT should be disabled.
+# 0 = VHT enabled (if AP supports it)
+# 1 = VHT disabled
+#
+# vht_capa: VHT capabilities to set in the override
+# vht_capa_mask: mask of VHT capabilities
+#
+# vht_rx_mcs_nss_1/2/3/4/5/6/7/8: override the MCS set for RX NSS 1-8
+# vht_tx_mcs_nss_1/2/3/4/5/6/7/8: override the MCS set for TX NSS 1-8
+# 0: MCS 0-7
+# 1: MCS 0-8
+# 2: MCS 0-9
+# 3: not supported
+
# Example blocks:
# Simple case: WPA-PSK, PSK as an ASCII passphrase, allow all valid ciphers
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 55f3d88..f96b245 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -11,6 +11,7 @@
#include "utils/list.h"
#include "common/defs.h"
+#include "common/sae.h"
#include "config_ssid.h"
extern const char *wpa_supplicant_version;
@@ -55,6 +56,14 @@
const char *confname;
/**
+ * confanother - Additional configuration name (file or profile) name
+ *
+ * This can also be %NULL when the additional configuration file is not
+ * used.
+ */
+ const char *confanother;
+
+ /**
* ctrl_interface - Control interface parameter
*
* If a configuration file is not used, this variable can be used to
@@ -227,6 +236,7 @@
struct p2p_data *p2p;
struct wpa_supplicant *p2p_init_wpa_s;
struct wpa_supplicant *p2p_group_formation;
+ struct wpa_supplicant *p2p_invite_group;
u8 p2p_dev_addr[ETH_ALEN];
struct dl_list p2p_srv_bonjour; /* struct p2p_srv_bonjour */
struct dl_list p2p_srv_upnp; /* struct p2p_srv_upnp */
@@ -249,11 +259,15 @@
};
+/**
+ * offchannel_send_action_result - Result of offchannel send Action frame
+ */
enum offchannel_send_action_result {
- OFFCHANNEL_SEND_ACTION_SUCCESS /* Frame was send and acknowledged */,
- OFFCHANNEL_SEND_ACTION_NO_ACK /* Frame was sent, but not acknowledged
+ OFFCHANNEL_SEND_ACTION_SUCCESS /**< Frame was send and acknowledged */,
+ OFFCHANNEL_SEND_ACTION_NO_ACK /**< Frame was sent, but not acknowledged
*/,
- OFFCHANNEL_SEND_ACTION_FAILED /* Frame was not sent due to a failure */
+ OFFCHANNEL_SEND_ACTION_FAILED /**< Frame was not sent due to a failure
+ */
};
struct wps_ap_info {
@@ -267,6 +281,11 @@
struct os_time last_attempt;
};
+struct wpa_ssid_value {
+ u8 ssid[32];
+ size_t ssid_len;
+};
+
/**
* struct wpa_supplicant - Internal data for wpa_supplicant interface
*
@@ -296,6 +315,7 @@
char bridge_ifname[16];
char *confname;
+ char *confanother;
struct wpa_config *conf;
int countermeasures;
os_time_t last_michael_mic_error;
@@ -323,6 +343,11 @@
u8 *bssid_filter;
size_t bssid_filter_count;
+ u8 *disallow_aps_bssid;
+ size_t disallow_aps_bssid_count;
+ struct wpa_ssid_value *disallow_aps_ssid;
+ size_t disallow_aps_ssid_count;
+
/* previous scan was wildcard when interleaving between
* wildcard scans and specific SSID scan when max_ssids=1 */
int prev_scan_wildcard;
@@ -370,7 +395,6 @@
int scanning;
int sched_scanning;
int new_connection;
- int reassociated_connection;
int eapol_received; /* number of EAPOL packets received after the
* previous association event */
@@ -387,12 +411,55 @@
struct wpa_blacklist *blacklist;
- int scan_req; /* manual scan request; this forces a scan even if there
- * are no enabled networks in the configuration */
+ /**
+ * extra_blacklist_count - Sum of blacklist counts after last connection
+ *
+ * This variable is used to maintain a count of temporary blacklisting
+ * failures (maximum number for any BSS) over blacklist clear
+ * operations. This is needed for figuring out whether there has been
+ * failures prior to the last blacklist clear operation which happens
+ * whenever no other not-blacklisted BSS candidates are available. This
+ * gets cleared whenever a connection has been established successfully.
+ */
+ int extra_blacklist_count;
+
+ /**
+ * scan_req - Type of the scan request
+ */
+ enum scan_req_type {
+ /**
+ * NORMAL_SCAN_REQ - Normal scan request
+ *
+ * This is used for scans initiated by wpa_supplicant to find an
+ * AP for a connection.
+ */
+ NORMAL_SCAN_REQ,
+
+ /**
+ * INITIAL_SCAN_REQ - Initial scan request
+ *
+ * This is used for the first scan on an interface to force at
+ * least one scan to be run even if the configuration does not
+ * include any enabled networks.
+ */
+ INITIAL_SCAN_REQ,
+
+ /**
+ * MANUAL_SCAN_REQ - Manual scan request
+ *
+ * This is used for scans where the user request a scan or
+ * a specific wpa_supplicant operation (e.g., WPS) requires scan
+ * to be run.
+ */
+ MANUAL_SCAN_REQ
+ } scan_req;
+ struct os_time scan_trigger_time;
int scan_runs; /* number of scan runs since WPS was started */
int *next_scan_freqs;
int scan_interval; /* time in sec between scans to find suitable AP */
int normal_scans; /* normal scans run before sched_scan */
+ int scan_for_connection; /* whether the scan request was triggered for
+ * finding a connection */
unsigned int drv_flags;
unsigned int drv_enc;
@@ -403,6 +470,10 @@
*/
unsigned int probe_resp_offloads;
+ /* extended capabilities supported by the driver */
+ const u8 *extended_capa, *extended_capa_mask;
+ unsigned int extended_capa_len;
+
int max_scan_ssids;
int max_sched_scan_ssids;
int sched_scan_supported;
@@ -422,6 +493,7 @@
struct wpabuf *pending_eapol_rx;
struct os_time pending_eapol_rx_time;
u8 pending_eapol_rx_src[ETH_ALEN];
+ unsigned int last_eapol_matches_bssid:1;
struct ibss_rsn *ibss_rsn;
@@ -457,6 +529,11 @@
u8 sched_obss_scan;
u16 obss_scan_int;
u16 bss_max_idle_period;
+#ifdef CONFIG_SAE
+ struct sae_data sae;
+ struct wpabuf *sae_token;
+ int sae_group_index;
+#endif /* CONFIG_SAE */
} sme;
#endif /* CONFIG_SME */
@@ -549,6 +626,7 @@
unsigned int p2p_fallback_to_go_neg:1;
unsigned int p2p_pd_before_go_neg:1;
unsigned int p2p_go_ht40:1;
+ unsigned int user_initiated_pd:1;
int p2p_persistent_go_freq;
int p2p_persistent_id;
int p2p_go_intent;
@@ -573,6 +651,7 @@
int after_wps;
int known_wps_freq;
unsigned int wps_freq;
+ u16 wps_ap_channel;
int wps_fragment_size;
int auto_reconnect_disabled;
@@ -589,6 +668,7 @@
unsigned int auto_select:1;
unsigned int auto_network_select:1;
unsigned int fetch_all_anqp:1;
+ struct wpa_bss *interworking_gas_bss;
#endif /* CONFIG_INTERWORKING */
unsigned int drv_capa_known;
@@ -608,6 +688,8 @@
struct wpabuf *last_gas_resp;
u8 last_gas_addr[ETH_ALEN];
u8 last_gas_dialog_token;
+
+ unsigned int no_keep_alive:1;
};
@@ -615,6 +697,9 @@
void wpa_supplicant_apply_ht_overrides(
struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
struct wpa_driver_associate_params *params);
+void wpa_supplicant_apply_vht_overrides(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ struct wpa_driver_associate_params *params);
int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
@@ -643,8 +728,6 @@
void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s);
void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
int reason_code);
-void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
- int reason_code);
void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
@@ -684,7 +767,6 @@
void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
const u8 *buf, size_t len);
enum wpa_key_mgmt key_mgmt2driver(int key_mgmt);
-enum wpa_cipher cipher_suite2driver(int cipher);
void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s);
void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s);
void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid);
@@ -693,7 +775,11 @@
void wpas_auth_failed(struct wpa_supplicant *wpa_s);
void wpas_clear_temp_disabled(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, int clear_failures);
-void wpa_supplicant_proc_40mhz_intolerant(struct wpa_supplicant *wpa_s);
+int disallowed_bssid(struct wpa_supplicant *wpa_s, const u8 *bssid);
+int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid,
+ size_t ssid_len);
+void wpas_request_connection(struct wpa_supplicant *wpa_s);
+int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf);
/**
* wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
@@ -718,7 +804,9 @@
void wpa_supplicant_stop_countermeasures(void *eloop_ctx, void *sock_ctx);
void wpa_supplicant_delayed_mic_error_report(void *eloop_ctx, void *sock_ctx);
void wnm_bss_keep_alive_deinit(struct wpa_supplicant *wpa_s);
-int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s);
+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);
/* eap_register.c */
int eap_register_methods(void);
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 6aa5205..cd51873 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -406,14 +406,6 @@
}
-static void _wpa_supplicant_disassociate(void *wpa_s, int reason_code)
-{
- wpa_supplicant_disassociate(wpa_s, reason_code);
- /* Schedule a scan to make sure we continue looking for networks */
- wpa_supplicant_req_scan(wpa_s, 5, 0);
-}
-
-
static void _wpa_supplicant_deauthenticate(void *wpa_s, int reason_code)
{
wpa_supplicant_deauthenticate(wpa_s, reason_code);
@@ -560,20 +552,37 @@
static int wpa_supplicant_tdls_peer_addset(
void *ctx, const u8 *peer, int add, u16 capability,
- const u8 *supp_rates, size_t supp_rates_len)
+ const u8 *supp_rates, size_t supp_rates_len,
+ const struct ieee80211_ht_capabilities *ht_capab,
+ const struct ieee80211_vht_capabilities *vht_capab,
+ u8 qosinfo, const u8 *ext_capab, size_t ext_capab_len)
{
struct wpa_supplicant *wpa_s = ctx;
struct hostapd_sta_add_params params;
+ os_memset(¶ms, 0, sizeof(params));
+
params.addr = peer;
params.aid = 1;
params.capability = capability;
params.flags = WPA_STA_TDLS_PEER | WPA_STA_AUTHORIZED;
- params.ht_capabilities = NULL;
+
+ /*
+ * TDLS Setup frames do not contain WMM IEs, hence need to depend on
+ * qosinfo to check if the peer is WMM capable.
+ */
+ if (qosinfo)
+ params.flags |= WPA_STA_WMM;
+
+ params.ht_capabilities = ht_capab;
+ params.vht_capabilities = vht_capab;
+ params.qosinfo = qosinfo;
params.listen_interval = 0;
params.supp_rates = supp_rates;
params.supp_rates_len = supp_rates_len;
params.set = !add;
+ params.ext_capab = ext_capab;
+ params.ext_capab_len = ext_capab_len;
return wpa_drv_sta_add(wpa_s, ¶ms);
}
@@ -670,6 +679,8 @@
return;
}
+ wpas_notify_eap_status(wpa_s, "eap parameter needed", field_name);
+
buflen = 100 + os_strlen(txt) + ssid->ssid_len;
buf = os_malloc(buflen);
if (buf == NULL)
@@ -787,8 +798,10 @@
ctx->eapol_done_cb = wpa_supplicant_notify_eapol_done;
ctx->eapol_send = wpa_supplicant_eapol_send;
ctx->set_wep_key = wpa_eapol_set_wep_key;
+#ifndef CONFIG_NO_CONFIG_BLOBS
ctx->set_config_blob = wpa_supplicant_set_config_blob;
ctx->get_config_blob = wpa_supplicant_get_config_blob;
+#endif /* CONFIG_NO_CONFIG_BLOBS */
ctx->aborted_cached = wpa_supplicant_aborted_cached;
ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path;
ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
@@ -814,6 +827,7 @@
}
+#ifndef CONFIG_NO_WPA
static void wpa_supplicant_set_rekey_offload(void *ctx, const u8 *kek,
const u8 *kck,
const u8 *replay_ctr)
@@ -822,6 +836,7 @@
wpa_drv_set_rekey_info(wpa_s, kek, kck, replay_ctr);
}
+#endif /* CONFIG_NO_WPA */
int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
@@ -839,7 +854,6 @@
ctx->set_state = _wpa_supplicant_set_state;
ctx->get_state = _wpa_supplicant_get_state;
ctx->deauthenticate = _wpa_supplicant_deauthenticate;
- ctx->disassociate = _wpa_supplicant_disassociate;
ctx->set_key = wpa_supplicant_set_key;
ctx->get_network_ctx = wpa_supplicant_get_network_ctx;
ctx->get_bssid = wpa_supplicant_get_bssid;
@@ -889,7 +903,8 @@
conf.peerkey_enabled = ssid->peerkey;
conf.allowed_pairwise_cipher = ssid->pairwise_cipher;
#ifdef IEEE8021X_EAPOL
- conf.proactive_key_caching = ssid->proactive_key_caching;
+ conf.proactive_key_caching = ssid->proactive_key_caching < 0 ?
+ wpa_s->conf->okc : ssid->proactive_key_caching;
conf.eap_workaround = ssid->eap_workaround;
conf.eap_conf_ctx = &ssid->eap;
#endif /* IEEE8021X_EAPOL */
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 915ca57..9af6084 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -1,6 +1,6 @@
/*
* wpa_supplicant / WPS integration
- * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2013, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -84,6 +84,10 @@
!(wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
int disabled = wpa_s->current_ssid->disabled;
unsigned int freq = wpa_s->assoc_freq;
+ struct wpa_bss *bss;
+ struct wpa_ssid *ssid = NULL;
+ int use_fast_assoc = 0;
+
wpa_printf(MSG_DEBUG, "WPS: Network configuration replaced - "
"try to associate with the received credential "
"(freq=%u)", freq);
@@ -98,7 +102,26 @@
wpa_s->wps_freq = freq;
wpa_s->normal_scans = 0;
wpa_s->reassociate = 1;
- wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+ wpa_printf(MSG_DEBUG, "WPS: Checking whether fast association "
+ "without a new scan can be used");
+ bss = wpa_supplicant_pick_network(wpa_s, &ssid);
+ if (bss) {
+ struct wpabuf *wps;
+ struct wps_parse_attr attr;
+
+ wps = wpa_bss_get_vendor_ie_multi(bss,
+ WPS_IE_VENDOR_TYPE);
+ if (wps && wps_parse_msg(wps, &attr) == 0 &&
+ attr.wps_state &&
+ *attr.wps_state == WPS_STATE_CONFIGURED)
+ use_fast_assoc = 1;
+ wpabuf_free(wps);
+ }
+
+ if (!use_fast_assoc ||
+ wpa_supplicant_fast_associate(wpa_s) != 1)
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
return 1;
}
@@ -256,6 +279,15 @@
return 0;
}
+ if (auth_type == WPS_AUTH_WPAPSK || auth_type == WPS_AUTH_WPA2PSK) {
+ if (cred->key_len < 8 || cred->key_len > 2 * PMK_LEN) {
+ wpa_printf(MSG_ERROR, "WPS: Reject PSK credential with "
+ "invalid Network Key length %lu",
+ (unsigned long) cred->key_len);
+ return -1;
+ }
+ }
+
if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
wpa_printf(MSG_DEBUG, "WPS: Replace WPS network block based "
"on the received credential");
@@ -403,6 +435,9 @@
wpas_wps_security_workaround(wpa_s, ssid, cred);
+ if (cred->ap_channel)
+ wpa_s->wps_ap_channel = cred->ap_channel;
+
#ifndef CONFIG_NO_CONFIG_WRITE
if (wpa_s->conf->update_config &&
wpa_config_write(wpa_s->confname, wpa_s->conf)) {
@@ -411,6 +446,13 @@
}
#endif /* CONFIG_NO_CONFIG_WRITE */
+ /*
+ * Optimize the post-WPS scan based on the channel used during
+ * the provisioning in case EAP-Failure is not received.
+ */
+ wpa_s->after_wps = 5;
+ wpa_s->wps_freq = wpa_s->assoc_freq;
+
return 0;
}
@@ -487,11 +529,58 @@
}
+static void wpas_wps_reenable_networks_cb(void *eloop_ctx, void *timeout_ctx);
+
+static void wpas_wps_reenable_networks(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_ssid *ssid;
+ int changed = 0;
+
+ eloop_cancel_timeout(wpas_wps_reenable_networks_cb, wpa_s, NULL);
+
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ if (ssid->disabled_for_connect && ssid->disabled) {
+ ssid->disabled_for_connect = 0;
+ ssid->disabled = 0;
+ wpas_notify_network_enabled_changed(wpa_s, ssid);
+ changed++;
+ }
+ }
+
+ if (changed) {
+#ifndef CONFIG_NO_CONFIG_WRITE
+ if (wpa_s->conf->update_config &&
+ wpa_config_write(wpa_s->confname, wpa_s->conf)) {
+ wpa_printf(MSG_DEBUG, "WPS: Failed to update "
+ "configuration");
+ }
+#endif /* CONFIG_NO_CONFIG_WRITE */
+ }
+}
+
+
+static void wpas_wps_reenable_networks_cb(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ /* Enable the networks disabled during wpas_wps_reassoc */
+ wpas_wps_reenable_networks(wpa_s);
+}
+
+
static void wpa_supplicant_wps_event_success(struct wpa_supplicant *wpa_s)
{
wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_SUCCESS);
wpa_s->wps_success = 1;
wpas_notify_wps_event_success(wpa_s);
+
+ /*
+ * Enable the networks disabled during wpas_wps_reassoc after 10
+ * seconds. The 10 seconds timer is to allow the data connection to be
+ * formed before allowing other networks to be selected.
+ */
+ eloop_register_timeout(10, 0, wpas_wps_reenable_networks_cb, wpa_s,
+ NULL);
+
#ifdef CONFIG_P2P
wpas_p2p_wps_success(wpa_s, wpa_s->bssid, 0);
#endif /* CONFIG_P2P */
@@ -690,6 +779,9 @@
prev_current = wpa_s->current_ssid;
+ /* Enable the networks disabled during wpas_wps_reassoc */
+ wpas_wps_reenable_networks(wpa_s);
+
eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
/* Remove any existing WPS network from configuration */
@@ -802,9 +894,10 @@
struct wpa_ssid *ssid;
struct wpa_bss *bss;
+ wpa_s->after_wps = 0;
wpa_s->known_wps_freq = 0;
if (bssid) {
- bss = wpa_bss_get_bssid(wpa_s, bssid);
+ bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
if (bss && bss->freq > 0) {
wpa_s->known_wps_freq = 1;
wpa_s->wps_freq = bss->freq;
@@ -819,6 +912,7 @@
ssid = wpa_s->conf->ssid;
while (ssid) {
int was_disabled = ssid->disabled;
+ ssid->disabled_for_connect = 0;
/*
* In case the network object corresponds to a persistent group
* then do not send out network disabled signal. In addition,
@@ -827,9 +921,12 @@
*/
if (was_disabled != 2) {
ssid->disabled = ssid != selected;
- if (was_disabled != ssid->disabled)
+ if (was_disabled != ssid->disabled) {
+ if (ssid->disabled)
+ ssid->disabled_for_connect = 1;
wpas_notify_network_enabled_changed(wpa_s,
ssid);
+ }
}
ssid = ssid->next;
}
@@ -865,7 +962,8 @@
}
}
#endif /* CONFIG_P2P */
- wpa_config_set(ssid, "phase1", "\"pbc=1\"", 0);
+ if (wpa_config_set(ssid, "phase1", "\"pbc=1\"", 0) < 0)
+ return -1;
if (wpa_s->wps_fragment_size)
ssid->eap.fragment_size = wpa_s->wps_fragment_size;
eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
@@ -908,7 +1006,8 @@
os_snprintf(val, sizeof(val), "\"pin=%08d dev_pw_id=%u\"",
rpin, dev_pw_id);
}
- wpa_config_set(ssid, "phase1", val, 0);
+ if (wpa_config_set(ssid, "phase1", val, 0) < 0)
+ return -1;
if (wpa_s->wps_fragment_size)
ssid->eap.fragment_size = wpa_s->wps_fragment_size;
eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
@@ -940,62 +1039,13 @@
wpa_supplicant_deauthenticate(wpa_s,
WLAN_REASON_DEAUTH_LEAVING);
wpas_clear_wps(wpa_s);
- } else
+ } else {
+ wpas_wps_reenable_networks(wpa_s);
wpas_wps_clear_ap_info(wpa_s);
-
- return 0;
-}
-
-
-#ifdef CONFIG_WPS_OOB
-int wpas_wps_start_oob(struct wpa_supplicant *wpa_s, char *device_type,
- char *path, char *method, char *name)
-{
- struct wps_context *wps = wpa_s->wps;
- struct oob_device_data *oob_dev;
-
- oob_dev = wps_get_oob_device(device_type);
- if (oob_dev == NULL)
- return -1;
- oob_dev->device_path = path;
- oob_dev->device_name = name;
- wps->oob_conf.oob_method = wps_get_oob_method(method);
-
- if (wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_E) {
- /*
- * Use pre-configured DH keys in order to be able to write the
- * key hash into the OOB file.
- */
- wpabuf_free(wps->dh_pubkey);
- wpabuf_free(wps->dh_privkey);
- wps->dh_privkey = NULL;
- wps->dh_pubkey = NULL;
- dh5_free(wps->dh_ctx);
- wps->dh_ctx = dh5_init(&wps->dh_privkey, &wps->dh_pubkey);
- wps->dh_pubkey = wpabuf_zeropad(wps->dh_pubkey, 192);
- if (wps->dh_ctx == NULL || wps->dh_pubkey == NULL) {
- wpa_printf(MSG_ERROR, "WPS: Failed to initialize "
- "Diffie-Hellman handshake");
- return -1;
- }
}
- if (wps->oob_conf.oob_method == OOB_METHOD_CRED)
- wpas_clear_wps(wpa_s);
-
- if (wps_process_oob(wps, oob_dev, 0) < 0)
- return -1;
-
- if ((wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_E ||
- wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_R) &&
- wpas_wps_start_pin(wpa_s, NULL,
- wpabuf_head(wps->oob_conf.dev_password), 0,
- DEV_PW_DEFAULT) < 0)
- return -1;
-
return 0;
}
-#endif /* CONFIG_WPS_OOB */
int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
@@ -1031,7 +1081,8 @@
res = os_snprintf(pos, end - pos, "\"");
if (res < 0 || res >= end - pos)
return -1;
- wpa_config_set(ssid, "phase1", val, 0);
+ if (wpa_config_set(ssid, "phase1", val, 0) < 0)
+ return -1;
if (wpa_s->wps_fragment_size)
ssid->eap.fragment_size = wpa_s->wps_fragment_size;
eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
@@ -1247,6 +1298,7 @@
void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
{
eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_wps_reenable_networks_cb, wpa_s, NULL);
wpas_wps_clear_ap_info(wpa_s);
if (wpa_s->wps == NULL)
@@ -1260,8 +1312,6 @@
wps_registrar_deinit(wpa_s->wps->registrar);
wpabuf_free(wpa_s->wps->dh_pubkey);
wpabuf_free(wpa_s->wps->dh_privkey);
- wpabuf_free(wpa_s->wps->oob_conf.pubkey_hash);
- wpabuf_free(wpa_s->wps->oob_conf.dev_password);
wpabuf_free(wpa_s->wps->dev.vendor_ext_m1);
os_free(wpa_s->wps->network_key);
os_free(wpa_s->wps);
@@ -1555,91 +1605,128 @@
const char *uuid, const char *pin)
{
u8 u[UUID_LEN];
- int any = 0;
+ const u8 *use_uuid = NULL;
+ u8 addr_buf[ETH_ALEN];
- if (os_strcmp(uuid, "any") == 0)
- any = 1;
- else if (uuid_str2bin(uuid, u))
+ if (os_strcmp(uuid, "any") == 0) {
+ } else if (uuid_str2bin(uuid, u) == 0) {
+ use_uuid = u;
+ } else if (hwaddr_aton(uuid, addr_buf) == 0) {
+ use_uuid = wps_er_get_sta_uuid(wpa_s->wps_er, addr_buf);
+ if (use_uuid == NULL)
+ return -1;
+ } else
return -1;
return wps_registrar_add_pin(wpa_s->wps->registrar, addr,
- any ? NULL : u,
+ use_uuid,
(const u8 *) pin, os_strlen(pin), 300);
}
int wpas_wps_er_pbc(struct wpa_supplicant *wpa_s, const char *uuid)
{
- u8 u[UUID_LEN];
+ u8 u[UUID_LEN], *use_uuid = NULL;
+ u8 addr[ETH_ALEN], *use_addr = NULL;
- if (uuid_str2bin(uuid, u))
+ if (uuid_str2bin(uuid, u) == 0)
+ use_uuid = u;
+ else if (hwaddr_aton(uuid, addr) == 0)
+ use_addr = addr;
+ else
return -1;
- return wps_er_pbc(wpa_s->wps_er, u);
+ return wps_er_pbc(wpa_s->wps_er, use_uuid, use_addr);
}
int wpas_wps_er_learn(struct wpa_supplicant *wpa_s, const char *uuid,
const char *pin)
{
- u8 u[UUID_LEN];
+ u8 u[UUID_LEN], *use_uuid = NULL;
+ u8 addr[ETH_ALEN], *use_addr = NULL;
- if (uuid_str2bin(uuid, u))
+ if (uuid_str2bin(uuid, u) == 0)
+ use_uuid = u;
+ else if (hwaddr_aton(uuid, addr) == 0)
+ use_addr = addr;
+ else
return -1;
- return wps_er_learn(wpa_s->wps_er, u, (const u8 *) pin,
+
+ return wps_er_learn(wpa_s->wps_er, use_uuid, use_addr, (const u8 *) pin,
os_strlen(pin));
}
+static int wpas_wps_network_to_cred(struct wpa_ssid *ssid,
+ struct wps_credential *cred)
+{
+ os_memset(cred, 0, sizeof(*cred));
+ if (ssid->ssid_len > 32)
+ return -1;
+ os_memcpy(cred->ssid, ssid->ssid, ssid->ssid_len);
+ cred->ssid_len = ssid->ssid_len;
+ if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
+ cred->auth_type = (ssid->proto & WPA_PROTO_RSN) ?
+ WPS_AUTH_WPA2PSK : WPS_AUTH_WPAPSK;
+ if (ssid->pairwise_cipher & WPA_CIPHER_CCMP)
+ cred->encr_type = WPS_ENCR_AES;
+ else
+ cred->encr_type = WPS_ENCR_TKIP;
+ if (ssid->passphrase) {
+ cred->key_len = os_strlen(ssid->passphrase);
+ if (cred->key_len >= 64)
+ return -1;
+ os_memcpy(cred->key, ssid->passphrase, cred->key_len);
+ } else if (ssid->psk_set) {
+ cred->key_len = 32;
+ os_memcpy(cred->key, ssid->psk, 32);
+ } else
+ return -1;
+ } else {
+ cred->auth_type = WPS_AUTH_OPEN;
+ cred->encr_type = WPS_ENCR_NONE;
+ }
+
+ return 0;
+}
+
+
int wpas_wps_er_set_config(struct wpa_supplicant *wpa_s, const char *uuid,
int id)
{
- u8 u[UUID_LEN];
+ u8 u[UUID_LEN], *use_uuid = NULL;
+ u8 addr[ETH_ALEN], *use_addr = NULL;
struct wpa_ssid *ssid;
struct wps_credential cred;
- if (uuid_str2bin(uuid, u))
+ if (uuid_str2bin(uuid, u) == 0)
+ use_uuid = u;
+ else if (hwaddr_aton(uuid, addr) == 0)
+ use_addr = addr;
+ else
return -1;
ssid = wpa_config_get_network(wpa_s->conf, id);
if (ssid == NULL || ssid->ssid == NULL)
return -1;
- os_memset(&cred, 0, sizeof(cred));
- if (ssid->ssid_len > 32)
+ if (wpas_wps_network_to_cred(ssid, &cred) < 0)
return -1;
- os_memcpy(cred.ssid, ssid->ssid, ssid->ssid_len);
- cred.ssid_len = ssid->ssid_len;
- if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
- cred.auth_type = (ssid->proto & WPA_PROTO_RSN) ?
- WPS_AUTH_WPA2PSK : WPS_AUTH_WPAPSK;
- if (ssid->pairwise_cipher & WPA_CIPHER_CCMP)
- cred.encr_type = WPS_ENCR_AES;
- else
- cred.encr_type = WPS_ENCR_TKIP;
- if (ssid->passphrase) {
- cred.key_len = os_strlen(ssid->passphrase);
- if (cred.key_len >= 64)
- return -1;
- os_memcpy(cred.key, ssid->passphrase, cred.key_len);
- } else if (ssid->psk_set) {
- cred.key_len = 32;
- os_memcpy(cred.key, ssid->psk, 32);
- } else
- return -1;
- } else {
- cred.auth_type = WPS_AUTH_OPEN;
- cred.encr_type = WPS_ENCR_NONE;
- }
- return wps_er_set_config(wpa_s->wps_er, u, &cred);
+ return wps_er_set_config(wpa_s->wps_er, use_uuid, use_addr, &cred);
}
int wpas_wps_er_config(struct wpa_supplicant *wpa_s, const char *uuid,
const char *pin, struct wps_new_ap_settings *settings)
{
- u8 u[UUID_LEN];
+ u8 u[UUID_LEN], *use_uuid = NULL;
+ u8 addr[ETH_ALEN], *use_addr = NULL;
struct wps_credential cred;
size_t len;
- if (uuid_str2bin(uuid, u))
+ if (uuid_str2bin(uuid, u) == 0)
+ use_uuid = u;
+ else if (hwaddr_aton(uuid, addr) == 0)
+ use_addr = addr;
+ else
return -1;
if (settings->ssid_hex == NULL || settings->auth == NULL ||
settings->encr == NULL || settings->key_hex == NULL)
@@ -1678,8 +1765,8 @@
else
return -1;
- return wps_er_config(wpa_s->wps_er, u, (const u8 *) pin,
- os_strlen(pin), &cred);
+ return wps_er_config(wpa_s->wps_er, use_uuid, use_addr,
+ (const u8 *) pin, os_strlen(pin), &cred);
}
@@ -1688,15 +1775,20 @@
int ndef, const char *uuid)
{
struct wpabuf *ret;
- u8 u[UUID_LEN];
+ u8 u[UUID_LEN], *use_uuid = NULL;
+ u8 addr[ETH_ALEN], *use_addr = NULL;
if (!wpa_s->wps_er)
return NULL;
- if (uuid_str2bin(uuid, u))
+ if (uuid_str2bin(uuid, u) == 0)
+ use_uuid = u;
+ else if (hwaddr_aton(uuid, addr) == 0)
+ use_addr = addr;
+ else
return NULL;
- ret = wps_er_nfc_config_token(wpa_s->wps_er, u);
+ ret = wps_er_nfc_config_token(wpa_s->wps_er, use_uuid, use_addr);
if (ndef && ret) {
struct wpabuf *tmp;
tmp = ndef_build_wifi(ret);
@@ -1804,8 +1896,69 @@
#ifdef CONFIG_WPS_NFC
+#ifdef CONFIG_WPS_ER
+static struct wpabuf *
+wpas_wps_network_config_token(struct wpa_supplicant *wpa_s, int ndef,
+ struct wpa_ssid *ssid)
+{
+ struct wpabuf *ret;
+ struct wps_credential cred;
+
+ if (wpas_wps_network_to_cred(ssid, &cred) < 0)
+ return NULL;
+
+ ret = wps_er_config_token_from_cred(wpa_s->wps, &cred);
+
+ if (ndef && ret) {
+ struct wpabuf *tmp;
+ tmp = ndef_build_wifi(ret);
+ wpabuf_free(ret);
+ if (tmp == NULL)
+ return NULL;
+ ret = tmp;
+ }
+
+ return ret;
+}
+#endif /* CONFIG_WPS_ER */
+
+
+struct wpabuf * wpas_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
+ int ndef, const char *id_str)
+{
+#ifdef CONFIG_WPS_ER
+ if (id_str) {
+ int id;
+ char *end = NULL;
+ struct wpa_ssid *ssid;
+
+ id = strtol(id_str, &end, 10);
+ if (end && *end)
+ return NULL;
+
+ ssid = wpa_config_get_network(wpa_s->conf, id);
+ if (ssid == NULL)
+ return NULL;
+ return wpas_wps_network_config_token(wpa_s, ndef, ssid);
+ }
+#endif /* CONFIG_WPS_ER */
+#ifdef CONFIG_AP
+ if (wpa_s->ap_iface)
+ return wpas_ap_wps_nfc_config_token(wpa_s, ndef);
+#endif /* CONFIG_AP */
+ return NULL;
+}
+
+
struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef)
{
+ if (wpa_s->conf->wps_nfc_pw_from_config) {
+ return wps_nfc_token_build(ndef,
+ wpa_s->conf->wps_nfc_dev_pw_id,
+ wpa_s->conf->wps_nfc_dh_pubkey,
+ wpa_s->conf->wps_nfc_dev_pw);
+ }
+
return wps_nfc_token_gen(ndef, &wpa_s->conf->wps_nfc_dev_pw_id,
&wpa_s->conf->wps_nfc_dh_pubkey,
&wpa_s->conf->wps_nfc_dh_privkey,
@@ -1837,8 +1990,13 @@
return -1;
}
wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, wps->dh_pubkey);
- if (wps->dh_ctx == NULL)
+ if (wps->dh_ctx == NULL) {
+ wpabuf_free(wps->dh_pubkey);
+ wps->dh_pubkey = NULL;
+ wpabuf_free(wps->dh_privkey);
+ wps->dh_privkey = NULL;
return -1;
+ }
wpa_snprintf_hex_uppercase(pw, sizeof(pw),
wpabuf_head(wpa_s->conf->wps_nfc_dev_pw),
@@ -1851,6 +2009,8 @@
static int wpas_wps_use_cred(struct wpa_supplicant *wpa_s,
struct wps_parse_attr *attr)
{
+ wpa_s->wps_ap_channel = 0;
+
if (wps_oob_use_cred(wpa_s->wps, attr) < 0)
return -1;
@@ -1861,6 +2021,24 @@
"based on the received credential added");
wpa_s->normal_scans = 0;
wpa_supplicant_reinit_autoscan(wpa_s);
+ if (wpa_s->wps_ap_channel) {
+ u16 chan = wpa_s->wps_ap_channel;
+ int freq = 0;
+
+ if (chan >= 1 && chan <= 13)
+ freq = 2407 + 5 * chan;
+ else if (chan == 14)
+ freq = 2484;
+ else if (chan >= 30)
+ freq = 5000 + 5 * chan;
+
+ if (freq) {
+ wpa_printf(MSG_DEBUG, "WPS: Credential indicated "
+ "AP channel %u -> %u MHz", chan, freq);
+ wpa_s->after_wps = 5;
+ wpa_s->wps_freq = freq;
+ }
+ }
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
wpa_supplicant_req_scan(wpa_s, 0, 0);
@@ -1930,6 +2108,108 @@
return ret;
}
+
+struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s, int cr)
+{
+ if (cr)
+ return ndef_build_wifi_hc(1);
+ return ndef_build_wifi_hr();
+}
+
+
+#ifdef CONFIG_WPS_NFC
+struct wpabuf * wpas_wps_er_nfc_handover_sel(struct wpa_supplicant *wpa_s,
+ int ndef, const char *uuid)
+{
+#ifdef CONFIG_WPS_ER
+ struct wpabuf *ret;
+ u8 u[UUID_LEN], *use_uuid = NULL;
+ u8 addr[ETH_ALEN], *use_addr = NULL;
+
+ if (!wpa_s->wps_er)
+ return NULL;
+
+ if (uuid == NULL)
+ return NULL;
+ if (uuid_str2bin(uuid, u) == 0)
+ use_uuid = u;
+ else if (hwaddr_aton(uuid, addr) == 0)
+ use_addr = addr;
+ else
+ return NULL;
+
+ /*
+ * Handover Select carrier record for WPS uses the same format as
+ * configuration token.
+ */
+ ret = wps_er_nfc_config_token(wpa_s->wps_er, use_uuid, use_addr);
+ if (ndef && ret) {
+ struct wpabuf *tmp;
+ tmp = ndef_build_wifi(ret);
+ wpabuf_free(ret);
+ if (tmp == NULL)
+ return NULL;
+ ret = tmp;
+ }
+
+ return ret;
+#else /* CONFIG_WPS_ER */
+ return NULL;
+#endif /* CONFIG_WPS_ER */
+}
+#endif /* CONFIG_WPS_NFC */
+
+
+struct wpabuf * wpas_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s,
+ int ndef, int cr, const char *uuid)
+{
+ struct wpabuf *ret;
+ if (!cr)
+ return NULL;
+ ret = wpas_ap_wps_nfc_handover_sel(wpa_s, ndef);
+ if (ret)
+ return ret;
+ return wpas_wps_er_nfc_handover_sel(wpa_s, ndef, uuid);
+}
+
+
+int wpas_wps_nfc_rx_handover_req(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *data)
+{
+ /* TODO */
+ return -1;
+}
+
+
+int wpas_wps_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *data)
+{
+ struct wpabuf *wps;
+ int ret;
+
+ wps = ndef_parse_wifi(data);
+ if (wps == NULL)
+ return -1;
+ wpa_printf(MSG_DEBUG, "WPS: Received application/vnd.wfa.wsc "
+ "payload from NFC connection handover");
+ wpa_hexdump_buf_key(MSG_DEBUG, "WPS: NFC payload", wps);
+ ret = wpas_wps_nfc_tag_process(wpa_s, wps);
+ wpabuf_free(wps);
+
+ return ret;
+}
+
+
+int wpas_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *req,
+ const struct wpabuf *sel)
+{
+ wpa_printf(MSG_DEBUG, "NFC: WPS connection handover reported");
+ wpa_hexdump_buf_key(MSG_DEBUG, "WPS: Carrier record in request", req);
+ wpa_hexdump_buf_key(MSG_DEBUG, "WPS: Carrier record in select", sel);
+ return wpas_wps_nfc_rx_handover_sel(wpa_s, sel);
+}
+
#endif /* CONFIG_WPS_NFC */
diff --git a/wpa_supplicant/wps_supplicant.h b/wpa_supplicant/wps_supplicant.h
index d5eb3b6..2a212ca 100644
--- a/wpa_supplicant/wps_supplicant.h
+++ b/wpa_supplicant/wps_supplicant.h
@@ -9,7 +9,6 @@
#ifndef WPS_SUPPLICANT_H
#define WPS_SUPPLICANT_H
-struct wpa_scan_res;
struct wpa_scan_results;
#ifdef CONFIG_WPS
@@ -35,8 +34,6 @@
int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
const char *pin, int p2p_group, u16 dev_pw_id);
int wpas_wps_cancel(struct wpa_supplicant *wpa_s);
-int wpas_wps_start_oob(struct wpa_supplicant *wpa_s, char *device_type,
- char *path, char *method, char *name);
int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
const char *pin, struct wps_new_ap_settings *settings);
int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
@@ -65,10 +62,22 @@
int wpas_wps_terminate_pending(struct wpa_supplicant *wpa_s);
int wpas_wps_in_progress(struct wpa_supplicant *wpa_s);
void wpas_wps_update_config(struct wpa_supplicant *wpa_s);
+struct wpabuf * wpas_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
+ int ndef, const char *id_str);
struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef);
int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *bssid);
int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s,
const struct wpabuf *data);
+struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s, int cr);
+struct wpabuf * wpas_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s,
+ int ndef, int cr, const char *uuid);
+int wpas_wps_nfc_rx_handover_req(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *data);
+int wpas_wps_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *data);
+int wpas_wps_nfc_report_handover(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *req,
+ const struct wpabuf *sel);
void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res);
void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid);
@@ -96,14 +105,14 @@
static inline int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
- struct wpa_scan_res *bss)
+ struct wpa_bss *bss)
{
return -1;
}
static inline int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
- struct wpa_scan_res *bss)
+ struct wpa_bss *bss)
{
return 0;
}