Accumulative patch from commit dc013f1e37df3462085cf01a13f0c432f146ad7a
Author: Jouni Malinen <jouni@qca.qualcomm.com>
Date: Tue Jan 15 12:03:29 2013 +0200
eapol_test: Remove unnecessary header file inclusion
- P2P: Send P2P-FIND-STOPPED event in the new continue-search states
- P2P: Add some more details on Service Query TLV format
- P2P: Use the same Dialog Token value for every GO Negotiation retry
- P2P: Publish more connected clients info in Probe Response frames
- P2P: Fix some memory leaks in p2p_add_device()
- P2P: Use the same Dialog Token value for every PD retry
- P2P: Document operating channel selection functions
- P2P: Always re-select operating channel if not hard coded
- P2P: Do not allow re-selection of GO channel if forced_freq in use
- P2P: Set FORCE_FREQ flag as part of p2p_prepare_channel()
- P2P: Share a single function for GO channel selection
- P2P: Prefer operating channels where HT40 is possible
- P2P: Be more careful with wpa_config_update_psk() call
- P2P: Allow PSK to be used instead of passphrase for persistent GO
- P2P: Consider age for the P2P scan results
- Move some P2P offchannel operations to offchannel.c
- P2P: Add more complete description of p2p_cancel
- P2P: Allow p2p_cancel to be used to stop p2p_connect-join operation
- Interworking changes
- WNM changes
- WPS changes
- SAE changes
Change-Id: I38b847d3460066cc58aecbcf67266bfcff1d344e
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index 9b576aa..16417ea 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -217,10 +217,13 @@
ifdef CONFIG_SAE
L_CFLAGS += -DCONFIG_SAE
+OBJS += src/common/sae.c
+NEED_ECC=y
+NEED_DH_GROUPS=y
endif
-ifdef CONFIG_IEEE80211V
-L_CFLAGS += -DCONFIG_IEEE80211V
+ifdef CONFIG_WNM
+L_CFLAGS += -DCONFIG_WNM
OBJS += src/ap/wnm_ap.c
endif
@@ -228,10 +231,6 @@
L_CFLAGS += -DCONFIG_IEEE80211N
endif
-ifdef CONFIG_WNM
-L_CFLAGS += -DCONFIG_WNM
-endif
-
ifdef CONFIG_IEEE80211AC
L_CFLAGS += -DCONFIG_IEEE80211AC
endif
@@ -525,6 +524,10 @@
ifdef TLS_FUNCS
OBJS += src/crypto/tls_gnutls.c
LIBS += -lgnutls -lgpg-error
+ifdef CONFIG_GNUTLS_EXTRA
+L_CFLAGS += -DCONFIG_GNUTLS_EXTRA
+LIBS += -lgnutls-extra
+endif
endif
OBJS += src/crypto/crypto_gnutls.c
HOBJS += src/crypto/crypto_gnutls.c
@@ -779,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
diff --git a/hostapd/ChangeLog b/hostapd/ChangeLog
index e739325..1a4e566 100644
--- a/hostapd/ChangeLog
+++ b/hostapd/ChangeLog
@@ -1,6 +1,10 @@
ChangeLog for hostapd
-????-??-?? - v2.0
+????-??-?? - 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)
@@ -89,6 +93,11 @@
* 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.
diff --git a/hostapd/Makefile b/hostapd/Makefile
index 4cc3805..8404e0c 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -174,10 +174,13 @@
ifdef CONFIG_SAE
CFLAGS += -DCONFIG_SAE
+OBJS += ../src/common/sae.o
+NEED_ECC=y
+NEED_DH_GROUPS=y
endif
-ifdef CONFIG_IEEE80211V
-CFLAGS += -DCONFIG_IEEE80211V
+ifdef CONFIG_WNM
+CFLAGS += -DCONFIG_WNM
OBJS += ../src/ap/wnm_ap.o
endif
@@ -185,10 +188,6 @@
CFLAGS += -DCONFIG_IEEE80211N
endif
-ifdef CONFIG_WNM
-CFLAGS += -DCONFIG_WNM
-endif
-
ifdef CONFIG_IEEE80211AC
CFLAGS += -DCONFIG_IEEE80211AC
endif
@@ -734,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/config_file.c b/hostapd/config_file.c
index 8af8157..7b22dfd 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.
@@ -661,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);
@@ -1780,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 &&
@@ -2311,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);
@@ -2717,6 +2684,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);
@@ -2925,6 +2898,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);
@@ -2938,31 +2919,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 ccc018e..93b740e 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -436,6 +436,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)
{
@@ -486,6 +530,8 @@
return 0;
}
+#endif /* CONFIG_WNM */
+
static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
char *buf, size_t buflen)
@@ -589,20 +635,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;
@@ -614,24 +649,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)
@@ -645,24 +667,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)
@@ -906,9 +915,14 @@
hapd, buf + 14, reply, reply_size);
#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);
@@ -997,12 +1011,27 @@
}
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;
}
+#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;
@@ -1055,7 +1084,7 @@
}
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;
}
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 c839ad0..eca3996 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
@@ -1032,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 ##############################################
@@ -1300,6 +1318,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_cli.c b/hostapd/hostapd_cli.c
index de1af3b..b693fa0 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 =
@@ -544,6 +544,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[])
{
@@ -780,6 +800,7 @@
{ "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..d4256d0 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -468,7 +468,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");
}
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 3c699f7..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;
}
@@ -516,6 +521,8 @@
#endif /* CONFIG_HS20 */
wpabuf_free(conf->vendor_elements);
+
+ os_free(conf->sae_groups);
}
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 71313c0..4742107 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;
@@ -390,6 +391,8 @@
/* IEEE 802.11v */
int time_advertisement;
char *time_zone;
+ int wnm_sleep_mode;
+ int bss_transition;
/* IEEE 802.11u - Interworking */
int interworking;
@@ -452,6 +455,9 @@
#endif /* CONFIG_RADIUS_TEST */
struct wpabuf *vendor_elements;
+
+ unsigned int sae_anti_clogging_threshold;
+ int *sae_groups;
};
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 02da25b..b71d51d 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -338,6 +338,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 +356,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 +456,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/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 c55d3fe..1cb7e73 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -189,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);
@@ -228,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);
@@ -246,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);
@@ -285,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 8613975..8980bec 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -512,13 +512,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 */
}
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index cef9daf..92fda56 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -894,7 +894,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;
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index f1e7d9f..c9087b3 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -192,6 +192,12 @@
#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 */
};
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 97e1238..923b698 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;
}
@@ -756,6 +758,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 a13a135..79235df 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"
@@ -316,19 +320,33 @@
#ifdef CONFIG_SAE
-static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
- struct sta_info *sta)
+static struct wpabuf * auth_process_sae_commit(struct hostapd_data *hapd,
+ struct sta_info *sta)
{
struct wpabuf *buf;
- buf = wpabuf_alloc(2);
+ 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;
-
- wpabuf_put_le16(buf, 19); /* Finite Cyclic Group */
- /* TODO: Anti-Clogging Token (if requested) */
- /* TODO: Scalar */
- /* TODO: Element */
+ sae_write_commit(sta->sae, buf, NULL);
return buf;
}
@@ -339,49 +357,82 @@
{
struct wpabuf *buf;
- buf = wpabuf_alloc(2);
+ buf = wpabuf_alloc(SAE_CONFIRM_MAX_LEN);
if (buf == NULL)
return NULL;
- wpabuf_put_le16(buf, sta->sae_send_confirm);
- sta->sae_send_confirm++;
- /* TODO: Confirm */
+ sae_write_confirm(sta->sae, buf);
return buf;
}
-static u16 handle_sae_commit(struct hostapd_data *hapd, struct sta_info *sta,
- const u8 *data, size_t len)
+static int use_sae_anti_clogging(struct hostapd_data *hapd)
{
- wpa_hexdump(MSG_DEBUG, "SAE commit fields", data, len);
+ struct sta_info *sta;
+ unsigned int open = 0;
- /* Check Finite Cyclic Group */
- if (len < 2)
- return WLAN_STATUS_UNSPECIFIED_FAILURE;
- if (WPA_GET_LE16(data) != 19) {
- wpa_printf(MSG_DEBUG, "SAE: Unsupported Finite Cyclic Group %u",
- WPA_GET_LE16(data));
- return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
+ 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 WLAN_STATUS_SUCCESS;
+ return 0;
}
-static u16 handle_sae_confirm(struct hostapd_data *hapd, struct sta_info *sta,
- const u8 *data, size_t len)
+static int check_sae_token(struct hostapd_data *hapd, const u8 *addr,
+ const u8 *token, size_t token_len)
{
- u16 rc;
+ u8 mac[SHA256_MAC_LEN];
- wpa_hexdump(MSG_DEBUG, "SAE confirm fields", data, 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;
- if (len < 2)
- return WLAN_STATUS_UNSPECIFIED_FAILURE;
- rc = WPA_GET_LE16(data);
- wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", rc);
+ return 0;
+}
- return WLAN_STATUS_SUCCESS;
+
+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;
}
@@ -390,19 +441,52 @@
u8 auth_transaction)
{
u16 resp = WLAN_STATUS_SUCCESS;
- struct wpabuf *data;
+ 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 = handle_sae_commit(hapd, sta, mgmt->u.auth.variable,
- ((u8 *) mgmt) + len -
- mgmt->u.auth.variable);
- if (resp == WLAN_STATUS_SUCCESS)
- sta->sae_state = SAE_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_COMMIT) {
+ if (sta->sae->state != SAE_COMMITTED) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
@@ -412,14 +496,24 @@
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"SAE authentication (RX confirm)");
- resp = handle_sae_confirm(hapd, sta, mgmt->u.auth.variable,
- ((u8 *) mgmt) + len -
- mgmt->u.auth.variable);
- if (resp == WLAN_STATUS_SUCCESS) {
+ 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,
@@ -431,16 +525,6 @@
sta->auth_alg = WLAN_AUTH_SAE;
- if (resp == WLAN_STATUS_SUCCESS) {
- if (auth_transaction == 1)
- data = auth_build_sae_commit(hapd, sta);
- else
- data = auth_build_sae_confirm(hapd, sta);
- if (data == NULL)
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- } else
- data = NULL;
-
send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
auth_transaction, resp,
data ? wpabuf_head(data) : (u8 *) "",
@@ -1434,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,
@@ -1450,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) &&
@@ -1465,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);
@@ -1488,6 +1589,11 @@
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,
@@ -1685,6 +1791,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))) {
@@ -1757,11 +1864,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_shared.c b/src/ap/ieee802_11_shared.c
index b3fdf3d..76f78a7 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -173,6 +173,14 @@
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 == 0)
return eid;
@@ -180,9 +188,20 @@
*pos++ = len;
*pos++ = 0x00;
*pos++ = 0x00;
- *pos++ = 0x00;
*pos = 0x00;
+ if (hapd->conf->wnm_sleep_mode)
+ *pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
+ if (hapd->conf->bss_transition)
+ *pos |= 0x08; /* Bit 19 - BSS Transition */
+ pos++;
+
+ if (len < 4)
+ return pos;
+ *pos = 0x00;
+#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)
@@ -198,6 +217,18 @@
*pos |= 0x80; /* Bit 39 - TDLS Channel Switching Prohibited */
pos++;
+ if (len < 6)
+ return pos;
+ *pos = 0x00;
+ pos++;
+
+ if (len < 7)
+ return pos;
+ *pos = 0x00;
+ if (hapd->conf->ssid.utf8_ssid)
+ *pos |= 0x01; /* Bit 48 - UTF-8 SSID */
+ pos++;
+
return pos;
}
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index b21c2b7..f6cc5d6 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -108,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 e1b11ba..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);
@@ -354,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:
@@ -452,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;
}
diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c
index 3a9cc7b..d27fd30 100644
--- a/src/ap/pmksa_cache_auth.c
+++ b/src/ap/pmksa_cache_auth.c
@@ -209,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 6bc43d2..8ada121 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"
@@ -240,6 +241,11 @@
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);
}
@@ -493,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 "
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index d5e92fa..32ea46e 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -127,8 +127,7 @@
struct os_time connected_time;
#ifdef CONFIG_SAE
- enum { SAE_INIT, SAE_COMMIT, SAE_CONFIRM } sae_state;
- u16 sae_send_confirm;
+ struct sae_data *sae;
#endif /* CONFIG_SAE */
};
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 0816b25..fa4b1cb 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -282,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;
@@ -295,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;
@@ -2413,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;
@@ -2427,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)
@@ -2446,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,
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 6ab170d..465eec6 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -282,14 +282,10 @@
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);
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 76c61ea..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"
@@ -184,7 +185,17 @@
{
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.
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 4fd0135..cdfcca1 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -564,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 85633ec..5ce4f1b 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -957,6 +957,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");
diff --git a/src/common/defs.h b/src/common/defs.h
index 85e9932..281dd8a 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -297,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 07c8580..f72c0d4 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -232,6 +232,7 @@
#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
@@ -537,6 +538,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;
@@ -701,6 +712,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
@@ -1048,11 +1065,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..44ffcd0
--- /dev/null
+++ b/src/common/sae.c
@@ -0,0 +1,1028 @@
+/*
+ * 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;
+
+ 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");
+ 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;
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+static u16 sae_parse_commit_element_ffc(struct sae_data *sae, const u8 *pos,
+ const u8 *end)
+{
+ 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;
+ }
+
+ 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 8d7a11c..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.
@@ -1132,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 ||
@@ -1214,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 20c79d8..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
@@ -386,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/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/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 f7bdc2c..5e8fd65 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -898,6 +898,7 @@
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;
@@ -907,10 +908,19 @@
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 {
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index a0a5210..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 */
@@ -1688,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)
@@ -1959,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)
{
@@ -2112,7 +2116,7 @@
return -1;
}
}
-#endif /* CONFIG_IEEE80211V */
+#endif /* CONFIG_WNM */
const struct wpa_driver_ops wpa_driver_atheros_ops = {
@@ -2146,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_nl80211.c b/src/drivers/driver_nl80211.c
index a0644b4..e530911 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -195,6 +195,7 @@
int freq;
+ void *ctx;
struct nl_handle *nl_preq, *nl_mgmt;
struct nl_cb *nl_cb;
@@ -1538,7 +1539,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;
@@ -1570,7 +1571,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);
}
@@ -2177,9 +2178,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)) {
@@ -2252,7 +2255,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);
@@ -2307,21 +2310,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;
}
@@ -2333,6 +2340,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);
@@ -2342,9 +2350,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;
@@ -3087,6 +3098,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;
@@ -3284,6 +3297,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;
}
@@ -4989,19 +5005,35 @@
/* crude heuristic */
if (mode->channels[idx].freq < 4000)
mode->mode = HOSTAPD_MODE_IEEE80211B;
+ else if (mode->channels[idx].freq > 50000)
+ mode->mode = HOSTAPD_MODE_IEEE80211AD;
else
mode->mode = HOSTAPD_MODE_IEEE80211A;
mode_is_set = 1;
}
- /* crude heuristic */
- if (mode->channels[idx].freq < 4000)
+ switch (mode->mode) {
+ case HOSTAPD_MODE_IEEE80211AD:
+ mode->channels[idx].chan =
+ (mode->channels[idx].freq - 56160) /
+ 2160;
+ break;
+ case HOSTAPD_MODE_IEEE80211A:
+ mode->channels[idx].chan =
+ mode->channels[idx].freq / 5 - 1000;
+ break;
+ case HOSTAPD_MODE_IEEE80211B:
+ case HOSTAPD_MODE_IEEE80211G:
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;
+ mode->channels[idx].chan =
+ (mode->channels[idx].freq -
+ 2407) / 5;
+ break;
+ default:
+ break;
+ }
if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
mode->channels[idx].flag |=
@@ -5665,16 +5697,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;
@@ -5682,9 +5714,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);
@@ -5703,11 +5764,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;
@@ -5768,6 +5829,12 @@
params->ht_capabilities);
}
+ if (params->vht_capabilities) {
+ NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY,
+ sizeof(*params->vht_capabilities),
+ params->vht_capabilities);
+ }
+
os_memset(&upd, 0, sizeof(upd));
upd.mask = sta_flags_nl80211(params->flags);
upd.set = upd.mask;
@@ -6603,7 +6670,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 "
@@ -6612,8 +6682,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;
}
@@ -6899,6 +6976,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);
@@ -7300,8 +7382,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);
}
@@ -8137,6 +8218,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;
diff --git a/src/drivers/driver_test.c b/src/drivers/driver_test.c
index 89aee7d..bd65dd8 100644
--- a/src/drivers/driver_test.c
+++ b/src/drivers/driver_test.c
@@ -1321,7 +1321,8 @@
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, bss->age,
+ bss->level,
(const u8 *) (bss + 1),
bss->ie_len) > 0)
return;
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 1a9a819..e3e19f8 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -118,8 +118,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
@@ -171,7 +172,7 @@
* %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY,
* %NL80211_ATTR_AUTH_TYPE and %NL80211_ATTR_INACTIVITY_TIMEOUT.
* 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
@@ -401,8 +402,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 +440,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 +472,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
@@ -568,8 +567,8 @@
*
* @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
@@ -773,14 +772,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
@@ -1292,6 +1303,13 @@
*
* @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_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -1555,6 +1573,13 @@
NL80211_ATTR_SCAN_FLAGS,
+ NL80211_ATTR_CHANNEL_WIDTH,
+ NL80211_ATTR_CENTER_FREQ1,
+ NL80211_ATTR_CENTER_FREQ2,
+
+ NL80211_ATTR_P2P_CTWINDOW,
+ NL80211_ATTR_P2P_OPPPS,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -1719,10 +1744,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 {
@@ -1732,6 +1762,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,
@@ -2440,6 +2475,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,
@@ -2448,6 +2492,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
@@ -3066,6 +3136,10 @@
* @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
*/
enum nl80211_feature_flags {
NL80211_FEATURE_SK_TX_STATUS = 1 << 0,
@@ -3079,6 +3153,8 @@
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,
};
/**
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index a4c9b25..85c242a 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -891,6 +891,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);
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_server/eap_server_aka.c b/src/eap_server/eap_server_aka.c
index 177b58d..469b9a0 100644
--- a/src/eap_server/eap_server_aka.c
+++ b/src/eap_server/eap_server_aka.c
@@ -731,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/p2p/p2p.c b/src/p2p/p2p.c
index b122f7c..aaacc9a 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -630,6 +630,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
+ * @age_ms: Age of the information in milliseconds
* @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
@@ -640,13 +641,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,
+ unsigned int age_ms, 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, time_tmp_age, entry_ts;
os_memset(&msg, 0, sizeof(msg));
if (p2p_parse_ies(ies, ies_len, &msg)) {
@@ -673,6 +676,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;
}
@@ -681,7 +685,24 @@
p2p_parse_free(&msg);
return -1;
}
- os_get_time(&dev->last_seen);
+
+ os_get_time(&time_now);
+ time_tmp_age.sec = age_ms / 1000;
+ time_tmp_age.usec = (age_ms % 1000) * 1000;
+ os_time_sub(&time_now, &time_tmp_age, &entry_ts);
+
+ /*
+ * Update the device entry only if the new peer
+ * entry is newer than the one previously stored.
+ */
+ if (dev->last_seen.usec > 0 &&
+ os_time_before(&entry_ts, &dev->last_seen)) {
+ p2p_parse_free(&msg);
+ return -1;
+ }
+
+ os_memcpy(&dev->last_seen, &entry_ts, 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)
@@ -1123,7 +1144,9 @@
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);
@@ -1166,89 +1189,115 @@
}
-static int p2p_prepare_channel(struct p2p_data *p2p, unsigned int force_freq,
- unsigned int pref_freq)
+static int p2p_prepare_channel_pref(struct p2p_data *p2p,
+ unsigned int force_freq,
+ unsigned int pref_freq)
{
- if (force_freq || pref_freq) {
- u8 op_reg_class, op_channel;
- unsigned int freq = force_freq ? force_freq : pref_freq;
- if (p2p_freq_to_channel(p2p->cfg->country, freq,
- &op_reg_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_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",
- freq, op_reg_class, op_channel);
- return -1;
- }
- p2p->op_reg_class = op_reg_class;
- p2p->op_channel = op_channel;
- if (force_freq) {
- 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 {
- os_memcpy(&p2p->channels, &p2p->cfg->channels,
- sizeof(struct p2p_channels));
- }
+ 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) {
+ 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 {
- 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.
+ */
+static 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;
}
@@ -1289,9 +1338,6 @@
MAC2STR(peer_addr), go_intent, MAC2STR(own_interface_addr),
wps_method, persistent_group, pd_before_go_neg);
- if (p2p_prepare_channel(p2p, force_freq, pref_freq) < 0)
- return -1;
-
dev = p2p_get_device(p2p, peer_addr);
if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
@@ -1300,6 +1346,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)) {
@@ -1339,8 +1388,16 @@
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 here to use the same value in each
+ * retry within the same GO Negotiation exchange.
+ */
+ dev->dialog_token++;
+ if (dev->dialog_token == 0)
+ dev->dialog_token = 1;
+ }
dev->connect_reqs = 0;
dev->go_neg_req_sent = 0;
dev->go_state = UNKNOWN_GO;
@@ -1367,11 +1424,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");
@@ -1401,9 +1453,6 @@
MAC2STR(peer_addr), go_intent, MAC2STR(own_interface_addr),
wps_method, persistent_group);
- if (p2p_prepare_channel(p2p, force_freq, pref_freq) < 0)
- return -1;
-
dev = p2p_get_device(p2p, peer_addr);
if (dev == NULL) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
@@ -1412,6 +1461,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 +1484,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;
}
@@ -2840,9 +2887,10 @@
int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
- int level, const u8 *ies, size_t ies_len)
+ unsigned int age, int level, const u8 *ies,
+ size_t ies_len)
{
- p2p_add_device(p2p, bssid, freq, level, ies, ies_len, 1);
+ p2p_add_device(p2p, bssid, freq, age, level, ies, ies_len, 1);
return 0;
}
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 045e6f7..18e733b 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -1200,6 +1200,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
+ * @age: Age of the scan result in milliseconds
* @level: Signal level (signal strength of the received Beacon/Probe Response
* frame)
* @ies: Pointer to IEs from the scan result
@@ -1221,7 +1222,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);
+ unsigned int age, int level, const u8 *ies,
+ size_t ies_len);
/**
* p2p_scan_res_handled - Indicate end of scan results
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index fe4b560..37d43bb 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);
@@ -336,6 +333,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)
{
@@ -390,6 +398,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.
@@ -403,6 +440,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)
{
@@ -619,36 +710,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 *)
@@ -1021,35 +1084,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);
diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c
index 8687320..633dd5c 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;
@@ -367,9 +400,8 @@
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
@@ -377,33 +409,32 @@
extra += wpabuf_len(group->wfd_ie);
#endif /* CONFIG_WIFI_DISPLAY */
- ie = wpabuf_alloc(257 + extra);
- if (ie == NULL)
+ p2p_subelems = wpabuf_alloc(500 + extra);
+ if (p2p_subelems == NULL)
return NULL;
#ifdef CONFIG_WIFI_DISPLAY
if (group->wfd_ie)
- wpabuf_put_buf(ie, group->wfd_ie);
+ wpabuf_put_buf(p2p_subelems, 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 */
+ 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(ie, m);
+ p2p_client_info(p2p_subelems, m);
WPA_PUT_LE16(group_info + 1,
- (u8 *) wpabuf_put(ie, 0) - group_info - 3);
+ (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);
return ie;
}
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index d2868fb..712544b 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -705,8 +705,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,
+ unsigned int age_ms, 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);
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index 7bf6600..ac67932 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -176,8 +176,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, 0, 0, data + 1, len - 1,
+ 0)) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Invitation Request add device failed "
MACSTR, MAC2STR(sa));
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index e40f2b7..ca33f17 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -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, 0, 0, data + 1, len - 1,
+ 0)) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Provision Discovery Request add device "
"failed " MACSTR, MAC2STR(sa));
@@ -379,9 +380,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);
@@ -452,6 +450,14 @@
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/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/tdls.c b/src/rsn_supp/tdls.c
index 7646ca8..c38fada 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -1309,21 +1309,10 @@
wpa_printf(MSG_DEBUG, "TDLS: No supported rates received");
return -1;
}
-
- 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;
- }
-
+ 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;
}
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 3c45f3a..e50404c 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -2627,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;
@@ -2637,7 +2637,6 @@
#endif /* CONFIG_IEEE80211W */
u16 keyinfo;
u8 keylen; /* plaintext key len */
- u8 keydatalen;
u8 *key_rsc;
os_memset(&gd, 0, sizeof(gd));
@@ -2655,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",
@@ -2667,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);
@@ -2689,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);
@@ -2723,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 8afdf39..791974c 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -365,8 +365,6 @@
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/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/wps/wps_registrar.c b/src/wps/wps_registrar.c
index b24836e..11e7e84 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -1298,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);
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 0ebe607..7545ab2 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -195,10 +195,13 @@
ifdef CONFIG_SAE
L_CFLAGS += -DCONFIG_SAE
+OBJS += src/common/sae.c
+NEED_ECC=y
+NEED_DH_GROUPS=y
endif
-ifdef CONFIG_IEEE80211V
-L_CFLAGS += -DCONFIG_IEEE80211V
+ifdef CONFIG_WNM
+L_CFLAGS += -DCONFIG_WNM
OBJS += wnm_sta.c
endif
@@ -582,7 +585,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
@@ -747,6 +750,9 @@
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
@@ -760,10 +766,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
@@ -882,6 +884,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
@@ -1144,10 +1148,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
@@ -1203,6 +1204,10 @@
endif
endif
+ifdef NEED_ECC
+L_CFLAGS += -DCONFIG_ECC
+endif
+
ifdef CONFIG_NO_RANDOM_POOL
L_CFLAGS += -DCONFIG_NO_RANDOM_POOL
else
diff --git a/wpa_supplicant/ChangeLog b/wpa_supplicant/ChangeLog
index 6a5ab17..3f10e11 100644
--- a/wpa_supplicant/ChangeLog
+++ b/wpa_supplicant/ChangeLog
@@ -1,6 +1,10 @@
ChangeLog for wpa_supplicant
-????-??-?? - v2.0
+????-??-?? - 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;
@@ -104,6 +108,7 @@
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
@@ -149,6 +154,7 @@
* 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
@@ -223,6 +229,10 @@
* 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.
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index c6c76ec..f39a3d7 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -174,10 +174,13 @@
ifdef CONFIG_SAE
CFLAGS += -DCONFIG_SAE
+OBJS += ../src/common/sae.o
+NEED_ECC=y
+NEED_DH_GROUPS=y
endif
-ifdef CONFIG_IEEE80211V
-CFLAGS += -DCONFIG_IEEE80211V
+ifdef CONFIG_WNM
+CFLAGS += -DCONFIG_WNM
OBJS += wnm_sta.o
endif
@@ -560,7 +563,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
@@ -725,6 +728,9 @@
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
@@ -738,10 +744,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
@@ -860,6 +862,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
@@ -1179,6 +1183,10 @@
endif
endif
+ifdef NEED_ECC
+CFLAGS += -DCONFIG_ECC
+endif
+
ifdef CONFIG_NO_RANDOM_POOL
CFLAGS += -DCONFIG_NO_RANDOM_POOL
else
@@ -1406,6 +1414,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..fb99c7b 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):
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index e261ef9..85ee6cb 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);
@@ -207,22 +210,10 @@
if (ssid->dtim_period)
bss->dtim_period = ssid->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 ((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 +255,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 */
@@ -462,20 +453,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
@@ -599,7 +585,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;
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 0babbd5..87b7db8 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,11 @@
}
+/**
+ * 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;
@@ -92,6 +105,14 @@
}
+/**
+ * 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;
@@ -116,6 +137,10 @@
}
+/**
+ * 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)
@@ -175,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)
{
@@ -496,6 +529,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++;
@@ -505,6 +547,15 @@
}
+/**
+ * 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
+ *
+ * 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)
{
@@ -610,6 +661,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)
{
@@ -655,6 +716,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;
@@ -688,6 +756,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);
@@ -698,6 +774,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;
@@ -713,6 +793,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);
@@ -720,6 +804,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)
{
@@ -735,6 +825,12 @@
#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)
{
@@ -751,6 +847,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;
@@ -762,6 +864,15 @@
}
+/**
+ * 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;
@@ -781,6 +892,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;
@@ -801,6 +921,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)
{
@@ -832,6 +962,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)
{
@@ -864,6 +1007,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;
@@ -886,6 +1034,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 eb01f2d..01f6c59 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 */
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index e157845..2c52c68 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -629,49 +629,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);
@@ -684,72 +647,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;
@@ -765,8 +669,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;
@@ -795,8 +698,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;
@@ -916,9 +818,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;
@@ -965,7 +865,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);
@@ -981,7 +881,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);
@@ -1627,7 +1527,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) },
@@ -1637,6 +1537,7 @@
#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) },
@@ -1835,6 +1736,7 @@
os_free(cred->eap_method);
os_free(cred->phase1);
os_free(cred->phase2);
+ os_free(cred->excluded_ssid);
os_free(cred);
}
@@ -1901,6 +1803,7 @@
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);
os_free(config);
}
@@ -2037,6 +1940,7 @@
#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;
@@ -2411,6 +2315,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);
@@ -2947,6 +2879,24 @@
}
+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;
+}
+
+
#ifdef OFFSET
#undef OFFSET
#endif /* OFFSET */
@@ -3039,6 +2989,7 @@
{ INT_RANGE(auto_interworking, 0, 1), 0 },
{ INT(okc), 0 },
{ INT(pmf), 0 },
+ { FUNC(sae_groups), 0 },
};
#undef FUNC
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index c0aea0b..0c3cb9a 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;
};
@@ -710,12 +716,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;
@@ -791,6 +797,16 @@
* 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;
};
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index d66eac5..50c3533 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)
@@ -676,6 +678,7 @@
INT_DEFe(fragment_size, DEFAULT_FRAGMENT_SIZE);
#endif /* IEEE8021X_EAPOL */
INT(mode);
+ INT(frequency);
write_int(f, "proactive_key_caching", ssid->proactive_key_caching, -1);
INT(disabled);
INT(peerkey);
@@ -704,16 +707,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");
+ }
+ }
}
@@ -931,6 +970,16 @@
fprintf(f, "okc=%d\n", config->okc);
if (config->pmf)
fprintf(f, "pmf=%d\n", config->pmf);
+
+ 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");
+ }
}
#endif /* CONFIG_NO_CONFIG_WRITE */
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index c1184f8..d079863 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 */
@@ -502,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
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 564c91e..3408a85 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -38,6 +38,7 @@
#include "interworking.h"
#include "blacklist.h"
#include "autoscan.h"
+#include "wnm_sta.h"
extern struct wpa_driver_ops *wpa_drivers[];
@@ -57,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;
@@ -112,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;
}
@@ -414,6 +426,8 @@
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);
@@ -1359,6 +1373,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)
@@ -1465,8 +1489,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 : "");
}
@@ -1713,54 +1736,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;
}
@@ -2784,6 +2768,9 @@
case HOSTAPD_MODE_IEEE80211A:
hmode = "A";
break;
+ case HOSTAPD_MODE_IEEE80211AD:
+ hmode = "AD";
+ break;
default:
continue;
}
@@ -4698,6 +4685,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)
{
@@ -5124,7 +5165,7 @@
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
reply_len = -1;
else {
- if (!wpa_s->scanning &&
+ 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;
@@ -5271,6 +5312,11 @@
} 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 {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c
index 03b8c7e..87e399c 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)
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 91c644f..3fefb48 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -102,8 +102,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);
}
@@ -1355,12 +1356,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) {
@@ -2183,7 +2188,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)
{
@@ -2195,11 +2200,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
@@ -2322,50 +2327,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)
{
@@ -2552,11 +2513,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);
@@ -2795,12 +2756,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,
@@ -2809,10 +2770,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 &&
diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c
index 0d4ca8e..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,
@@ -465,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/interworking.c b/wpa_supplicant/interworking.c
index cfe56ea..b8a8bb2 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"
@@ -170,6 +171,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)
{
@@ -238,6 +246,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 +526,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;
@@ -948,6 +963,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)
{
@@ -975,6 +1008,9 @@
cred->roaming_consortium_len))
continue;
+ if (cred_excluded_ssid(cred, bss))
+ continue;
+
if (selected == NULL ||
selected->priority < cred->priority)
selected = cred;
@@ -1263,11 +1299,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;
@@ -1337,6 +1382,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;
@@ -1377,6 +1424,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;
@@ -1459,7 +1508,8 @@
mnc_len = wpa_s->mnc_len;
}
#endif /* CONFIG_PCSC */
- if (imsi && build_root_nai(nai, sizeof(nai), imsi, mnc_len, 0) == 0) {
+ if (domain_names &&
+ imsi && build_root_nai(nai, sizeof(nai), imsi, mnc_len, 0) == 0) {
realm = os_strchr(nai, '@');
if (realm)
realm++;
@@ -1471,7 +1521,7 @@
}
#endif /* INTERWORKING_3GPP */
- if (cred->domain == NULL)
+ if (domain_names == NULL || cred->domain == NULL)
return 0;
wpa_printf(MSG_DEBUG, "Interworking: Search for match with "
@@ -1630,6 +1680,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)
@@ -1655,7 +1710,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) {
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 c2d702e..523178f 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -112,7 +112,7 @@
for (i = 0; i < scan_res->num; i++) {
struct wpa_scan_res *bss = scan_res->res[i];
if (p2p_scan_res_handler(wpa_s->global->p2p, bss->bssid,
- bss->freq, bss->level,
+ bss->freq, bss->age, bss->level,
(const u8 *) (bss + 1),
bss->ie_len) > 0)
break;
@@ -820,15 +820,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(
@@ -898,17 +911,20 @@
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;
- }
+ 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
+ else if (ssid->passphrase)
wpa_config_update_psk(ssid);
ssid->ap_max_inactivity = wpa_s->parent->conf->p2p_go_max_inactivity;
@@ -3567,6 +3583,7 @@
}
group->p2p_in_provisioning = 1;
+ wpa_s->global->p2p_group_formation = wpa_s;
group->p2p_fallback_to_go_neg = wpa_s->p2p_fallback_to_go_neg;
os_memset(&res, 0, sizeof(res));
@@ -3845,12 +3862,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;
@@ -4186,14 +4203,15 @@
params.psk_set = ssid->psk_set;
if (params.psk_set)
os_memcpy(params.psk, ssid->psk, sizeof(params.psk));
- if (ssid->passphrase == NULL ||
- os_strlen(ssid->passphrase) >= sizeof(params.passphrase)) {
- wpa_printf(MSG_DEBUG, "P2P: Invalid passphrase in persistent "
- "group");
- return -1;
+ 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;
@@ -4408,13 +4426,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);
}
@@ -5336,6 +5353,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;
@@ -5359,6 +5383,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) {
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 048e6d0..c59b8ba 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.
@@ -81,6 +81,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;
@@ -199,6 +208,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)
{
@@ -861,6 +876,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.
@@ -882,6 +898,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.
@@ -1135,6 +1152,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)
{
@@ -1172,6 +1199,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;
@@ -1191,6 +1227,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)
{
@@ -1212,6 +1257,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)
{
@@ -1243,40 +1298,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
@@ -1440,6 +1461,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)
{
@@ -1531,6 +1561,18 @@
}
+/**
+ * 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;
diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
index b0ddf97..5096287 100644
--- a/wpa_supplicant/scan.h
+++ b/wpa_supplicant/scan.h
@@ -30,8 +30,6 @@
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);
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index e273cb3..30f9779 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"
@@ -41,20 +42,78 @@
#ifdef CONFIG_SAE
-static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s)
+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;
- buf = wpabuf_alloc(4 + 2);
+ 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);
- wpabuf_put_le16(buf, 19); /* Finite Cyclic Group */
- /* TODO: Anti-Clogging Token (if requested) */
- /* TODO: Scalar */
- /* TODO: Element */
+ sae_write_commit(&wpa_s->sme.sae, buf, wpa_s->sme.sae_token);
return buf;
}
@@ -64,15 +123,13 @@
{
struct wpabuf *buf;
- buf = wpabuf_alloc(4 + 2);
+ 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);
- wpabuf_put_le16(buf, wpa_s->sme.sae_send_confirm);
- wpa_s->sme.sae_send_confirm++;
- /* TODO: Confirm */
+ sae_write_confirm(&wpa_s->sme.sae, buf);
return buf;
}
@@ -94,6 +151,8 @@
#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 "
@@ -308,35 +367,30 @@
}
#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);
+ 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 ? SME_SAE_COMMIT : SME_SAE_CONFIRM;
+ wpa_s->sme.sae.state = start ? SAE_COMMITTED : SAE_CONFIRMED;
}
#endif /* CONFIG_SAE */
@@ -381,53 +435,48 @@
void sme_authenticate(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, struct wpa_ssid *ssid)
{
- wpa_s->sme.sae_state = SME_SAE_INIT;
- wpa_s->sme.sae_send_confirm = 0;
+#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_process_commit(struct wpa_supplicant *wpa_s, const u8 *data,
- size_t len)
-{
- /* Check Finite Cyclic Group */
- if (len < 2)
- return -1;
- if (WPA_GET_LE16(data) != 19) {
- wpa_printf(MSG_DEBUG, "SAE: Unsupported Finite Cyclic Group %u",
- WPA_GET_LE16(data));
- return -1;
- }
-
- /* TODO */
-
- return 0;
-}
-
-
-static int sme_sae_process_confirm(struct wpa_supplicant *wpa_s, const u8 *data,
- size_t len)
-{
- u16 rc;
-
- if (len < 2)
- return -1;
- rc = WPA_GET_LE16(data);
- wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", rc);
-
- /* TODO */
- return 0;
-}
-
-
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);
- wpa_hexdump(MSG_DEBUG, "SME: SAE fields", data, len);
+
+ 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;
@@ -437,19 +486,32 @@
if (wpa_s->current_bss == NULL ||
wpa_s->current_ssid == NULL)
return -1;
- if (wpa_s->sme.sae_state != SME_SAE_COMMIT)
+ if (wpa_s->sme.sae.state != SAE_COMMITTED)
return -1;
- if (sme_sae_process_commit(wpa_s, data, len) < 0)
+ 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 != SME_SAE_CONFIRM)
+ if (wpa_s->sme.sae.state != SAE_CONFIRMED)
return -1;
- if (sme_sae_process_confirm(wpa_s, data, len) < 0)
+ 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;
}
@@ -503,6 +565,10 @@
}
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 */
@@ -577,8 +643,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));
@@ -805,6 +872,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);
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/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 4e7c81c..cc08009 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 =
@@ -2273,6 +2273,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)
@@ -2737,6 +2747,10 @@
{ "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" },
#ifdef ANDROID
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 2f7d9ea..ee1a06c 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"
@@ -665,15 +665,13 @@
struct wpa_ssid *ssid = wpa_s->current_ssid;
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)",
+ MAC2STR(wpa_s->bssid), "(auth)",
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);
@@ -853,26 +851,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) {
@@ -1041,45 +1019,24 @@
}
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
@@ -1236,6 +1193,33 @@
}
+int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf)
+{
+ u32 ext_capab = 0;
+ u8 *pos = buf;
+
+#ifdef CONFIG_INTERWORKING
+ if (wpa_s->conf->interworking)
+ ext_capab |= BIT(31); /* Interworking */
+#endif /* CONFIG_INTERWORKING */
+
+#ifdef CONFIG_WNM
+ ext_capab |= BIT(17); /* WNM-Sleep Mode */
+ ext_capab |= BIT(19); /* BSS Transition */
+#endif /* CONFIG_WNM */
+
+ if (!ext_capab)
+ return 0;
+
+ *pos++ = WLAN_EID_EXT_CAPAB;
+ *pos++ = 4;
+ WPA_PUT_LE32(pos, ext_capab);
+ pos += 4;
+
+ return pos - buf;
+}
+
+
/**
* wpa_supplicant_associate - Request association
* @wpa_s: Pointer to wpa_supplicant data
@@ -1257,6 +1241,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;
@@ -1470,26 +1456,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)
@@ -2609,6 +2590,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)
@@ -2631,6 +2634,7 @@
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 */
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 5f0dec6..18460b8 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -281,6 +281,14 @@
# 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
+
# Interworking (IEEE 802.11u)
# Enable Interworking
@@ -389,6 +397,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={
@@ -489,6 +502,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)
@@ -802,6 +832,34 @@
# DTIM period in Beacon intervals for AP mode (default: 2)
#dtim_period=2
+# 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.
+
# 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 87d2098..ecbdedf 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;
@@ -249,11 +250,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 {
@@ -380,7 +385,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 */
@@ -510,12 +514,11 @@
u8 sched_obss_scan;
u16 obss_scan_int;
u16 bss_max_idle_period;
- enum {
- SME_SAE_INIT,
- SME_SAE_COMMIT,
- SME_SAE_CONFIRM
- } sae_state;
- u16 sae_send_confirm;
+#ifdef CONFIG_SAE
+ struct sae_data sae;
+ struct wpabuf *sae_token;
+ int sae_group_index;
+#endif /* CONFIG_SAE */
} sme;
#endif /* CONFIG_SME */
@@ -669,6 +672,8 @@
struct wpabuf *last_gas_resp;
u8 last_gas_addr[ETH_ALEN];
u8 last_gas_dialog_token;
+
+ unsigned int no_keep_alive:1;
};
@@ -743,7 +748,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);
@@ -756,6 +760,7 @@
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
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 1ba4c92..4859774 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -662,6 +662,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)
@@ -806,6 +808,7 @@
}
+#ifndef CONFIG_NO_WPA
static void wpa_supplicant_set_rekey_offload(void *ctx, const u8 *kek,
const u8 *kck,
const u8 *replay_ctr)
@@ -814,6 +817,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)
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 0239c55..711c3c0 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -423,6 +423,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;
}
@@ -504,6 +511,7 @@
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);
@@ -512,8 +520,19 @@
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 */
+ }
}
@@ -919,7 +938,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,
@@ -962,7 +982,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,
@@ -1036,7 +1057,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,