diff options
110 files changed, 5615 insertions, 1382 deletions
diff --git a/hostapd/Android.mk b/hostapd/Android.mk index 9b576aa3..16417ea6 100644 --- a/hostapd/Android.mk +++ b/hostapd/Android.mk @@ -217,10 +217,13 @@ endif 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 @@ ifdef CONFIG_IEEE80211N 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 @@ ifeq ($(CONFIG_TLS), gnutls) 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 @@ OBJS += src/crypto/dh_group5.c 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 e7393251..1a4e566b 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 @@ ChangeLog for hostapd * 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 4cc38059..8404e0cb 100644 --- a/hostapd/Makefile +++ b/hostapd/Makefile @@ -174,10 +174,13 @@ endif 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 @@ ifdef CONFIG_IEEE80211N CFLAGS += -DCONFIG_IEEE80211N endif -ifdef CONFIG_WNM -CFLAGS += -DCONFIG_WNM -endif - ifdef CONFIG_IEEE80211AC CFLAGS += -DCONFIG_IEEE80211AC endif @@ -734,6 +733,10 @@ OBJS += ../src/crypto/dh_group5.o 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 34dad303..39b70cab 100644 --- a/hostapd/README +++ b/hostapd/README @@ -2,7 +2,7 @@ hostapd - user space IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP Authenticator and RADIUS authentication server ================================================================ -Copyright (c) 2002-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 8af8157a..7b22dfd0 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_key_mgmt(int line, const char *value) 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 @@ static int hostapd_config_fill(struct hostapd_config *conf, 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 @@ static int hostapd_config_fill(struct hostapd_config *conf, 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 @@ static int hostapd_config_fill(struct hostapd_config *conf, 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 @@ static int hostapd_config_fill(struct hostapd_config *conf, 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 int hostapd_config_fill(struct hostapd_config *conf, 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 ccc018ec..93b740eb 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -436,6 +436,50 @@ static int hostapd_ctrl_iface_wps_config(struct hostapd_data *hapd, char *txt) #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 @@ static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd, 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 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd, 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 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd, 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 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd, 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 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, 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 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd) } 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 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd) } 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 d33e05f7..fcd98905 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 @@ static void hostapd_dump_state(struct hostapd_data *hapd) #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 @@ static void hostapd_dump_state(struct hostapd_data *hapd) "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 c839ad0c..eca39960 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -90,6 +90,9 @@ ssid=test #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 @@ ssid=test #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 @@ own_ip_addr=127.0.0.1 # 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 @@ own_ip_addr=127.0.0.1 # 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 de1af3bb..b693fa05 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 @@ static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc, #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 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = { { "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 56f00023..d4256d0f 100644 --- a/hostapd/main.c +++ b/hostapd/main.c @@ -468,7 +468,7 @@ static void show_version(void) "hostapd v" VERSION_STR "\n" "User space daemon for IEEE 802.11 AP management,\n" "IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n" - "Copyright (c) 2002-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 7563b52e..95405313 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 @@ void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta) 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 @@ void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta) } -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 9d13d011..dcc54ee9 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 @@ static inline void accounting_deinit(struct hostapd_data *hapd) { } #else /* CONFIG_NO_ACCOUNTING */ +void accounting_sta_get_id(struct hostapd_data *hapd, struct sta_info *sta); 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 3c699f71..922f5646 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -89,6 +89,8 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss) #endif /* CONFIG_IEEE80211R */ bss->radius_das_time_window = 300; + + bss->sae_anti_clogging_threshold = 5; } @@ -158,6 +160,9 @@ struct hostapd_config * hostapd_config_defaults(void) 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 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf) #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 71313c02..4742107d 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -51,7 +51,8 @@ typedef enum hostap_security_policy { 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 @@ struct hostapd_bss_config { /* 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 @@ struct hostapd_bss_config { #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 02da25b7..b71d51d8 100644 --- a/src/ap/ap_drv_ops.c +++ b/src/ap/ap_drv_ops.c @@ -338,6 +338,7 @@ int hostapd_sta_add(struct hostapd_data *hapd, 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 @@ int hostapd_sta_add(struct hostapd_data *hapd, 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_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) { 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 9c53b99d..ceb7e68e 100644 --- a/src/ap/ap_drv_ops.h +++ b/src/ap/ap_drv_ops.h @@ -13,6 +13,7 @@ enum wpa_driver_if_type; 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 @@ int hostapd_sta_add(struct hostapd_data *hapd, 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 @@ int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd, const u8 *addr, int idx, u8 *seq); int hostapd_flush(struct hostapd_data *hapd); int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq, - int channel, int ht_enabled, int 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 f761bf55..4c47c758 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 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, } +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 @@ void handle_probe_req(struct hostapd_data *hapd, 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 @@ void handle_probe_req(struct hostapd_data *hapd, } #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 @@ void handle_probe_req(struct hostapd_data *hapd, } #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 @@ void handle_probe_req(struct hostapd_data *hapd, 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 @@ void handle_probe_req(struct hostapd_data *hapd, * 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 c55d3fe3..1cb7e73c 100644 --- a/src/ap/ctrl_iface_ap.c +++ b/src/ap/ctrl_iface_ap.c @@ -189,6 +189,7 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd, 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 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd, } #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 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd, 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 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd, } #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 86139752..8980bec0 100644 --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c @@ -512,13 +512,13 @@ static void hostapd_action_rx(struct hostapd_data *hapd, 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 cef9dafc..92fda569 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -894,7 +894,11 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) 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 f1e7d9ff..c9087b31 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -192,6 +192,12 @@ struct hostapd_data { #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 97e1238e..923b6982 100644 --- a/src/ap/hw_features.c +++ b/src/ap/hw_features.c @@ -122,6 +122,8 @@ int hostapd_prepare_rates(struct hostapd_iface *iface, 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 @@ const char * hostapd_hw_mode_txt(int mode) 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 a13a135e..79235dfd 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 @@ static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid, #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 (buf == NULL) + 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; + } - wpabuf_put_le16(buf, 19); /* Finite Cyclic Group */ - /* TODO: Anti-Clogging Token (if requested) */ - /* TODO: Scalar */ - /* TODO: Element */ + buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN); + if (buf == NULL) + return NULL; + sae_write_commit(sta->sae, buf, NULL); return buf; } @@ -339,49 +357,82 @@ static struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd, { 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 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta, 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 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta, 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 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta, 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 @@ static int robust_action_frame(u8 category) #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 @@ static void handle_action(struct hostapd_data *hapd, 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 @@ static void handle_action(struct hostapd_data *hapd, 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 @@ static void handle_action(struct hostapd_data *hapd, 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 @@ static void handle_assoc_cb(struct hostapd_data *hapd, 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 @@ static void handle_assoc_cb(struct hostapd_data *hapd, 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 1e5800d0..2aab56de 100644 --- a/src/ap/ieee802_11.h +++ b/src/ap/ieee802_11.h @@ -53,6 +53,9 @@ void ieee802_11_send_sa_query_req(struct hostapd_data *hapd, 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 b3fdf3d6..76f78a7d 100644 --- a/src/ap/ieee802_11_shared.c +++ b/src/ap/ieee802_11_shared.c @@ -173,6 +173,14 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid) 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 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid) *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 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid) *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 b21c2b7f..f6cc5d6c 100644 --- a/src/ap/ieee802_11_vht.c +++ b/src/ap/ieee802_11_vht.c @@ -108,3 +108,14 @@ u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta, 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 e1b11ba1..a832a732 100644 --- a/src/ap/ieee802_1x.c +++ b/src/ap/ieee802_1x.c @@ -66,8 +66,9 @@ static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta, 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 @@ void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta) 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 @@ static int add_common_radius_sta_attr(struct hostapd_data *hapd, return -1; } + if (sta->acct_session_id_hi || sta->acct_session_id_lo) { + os_snprintf(buf, sizeof(buf), "%08X-%08X", + sta->acct_session_id_hi, sta->acct_session_id_lo); + if (!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 3a9cc7b4..d27fd302 100644 --- a/src/ap/pmksa_cache_auth.c +++ b/src/ap/pmksa_cache_auth.c @@ -209,6 +209,8 @@ static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa, 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 6bc43d2d..8ada1218 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 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) 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 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr) return NULL; } sta->acct_interim_interval = hapd->conf->acct_interim_interval; + accounting_sta_get_id(hapd, sta); /* 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 d5e92faa..32ea46e0 100644 --- a/src/ap/sta_info.h +++ b/src/ap/sta_info.h @@ -127,8 +127,7 @@ struct sta_info { 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 25944045..54a6b857 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 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd, 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 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd, 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 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd, 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 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd, * 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 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd, * 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 int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd, 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 @@ static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd, 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 @@ static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd, 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 @@ static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd, } -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 ab7c4f1c..f05726ee 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 0816b25b..fa4b1cb3 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -282,8 +282,9 @@ static void wpa_auth_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry, 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 @@ static int wpa_group_init_gmk_and_counter(struct wpa_authenticator *wpa_auth, */ 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 @@ static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx) "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 @@ static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx) } -#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 @@ void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag) 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; - - /* - * 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]; + u8 *start = pos; /* + * 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); - return 0; - } - if (aes_wrap(sm->PTK.kek, key_len / 8, key, subelem + 13)) { - 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; - } - - os_memcpy(pos, subelem, subelem_len); + pos += 8; + os_memcpy(pos, gsm->GTK[gsm->GN - 1], gsm->GTK_len); + pos += gsm->GTK_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; - - /* 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) - return 0; + u8 *start = pos; - 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); + /* + * 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; - } - ptr += 6; - if (aes_wrap(sm->PTK.kek, WPA_IGTK_LEN / 8, - gsm->IGTK[gsm->GN_igtk - 4], ptr)) { - os_free(subelem); - return -1; - } + pos += 6; - os_memcpy(pos, subelem, subelem_len); + os_memcpy(pos, gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN); + pos += WPA_IGTK_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 6ab170d1..465eec6a 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -282,14 +282,10 @@ int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr, 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 48bf79b9..ccb3f823 100644 --- a/src/ap/wpa_auth_ft.c +++ b/src/ap/wpa_auth_ft.c @@ -416,7 +416,7 @@ static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len) 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 76c61ea1..fdaaaff5 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 @@ static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr, { 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 d5cf2c50..97489d34 100644 --- a/src/ap/wpa_auth_i.h +++ b/src/ap/wpa_auth_i.h @@ -87,9 +87,7 @@ struct wpa_state_machine { 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 4fd0135f..cdfcca19 100644 --- a/src/ap/wpa_auth_ie.c +++ b/src/ap/wpa_auth_ie.c @@ -564,12 +564,9 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, } #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 85633ec5..5ce4f1be 100644 --- a/src/ap/wps_hostapd.c +++ b/src/ap/wps_hostapd.c @@ -957,6 +957,9 @@ int hostapd_init_wps(struct hostapd_data *hapd, 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 85e99329..281dd8a5 100644 --- a/src/common/defs.h +++ b/src/common/defs.h @@ -297,6 +297,7 @@ enum hostapd_hw_mode { 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 d9d3cd05..98fadda1 100644 --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -284,6 +284,10 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, 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 bfc3eb27..55fa49d1 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 @@ struct ieee802_11_elems { 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 @@ struct ieee802_11_elems { 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 07c85807..f72c0d40 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 @@ struct ieee80211_mgmt { * 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 @@ struct ieee80211_vht_operation { #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 ieee80211_2040_intol_chan_report { 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 00000000..44ffcd09 --- /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 00000000..d82a98e8 --- /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 7afba48d..2faa8c7c 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 8d7a11cf..a8cf6be8 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 @@ int wpa_cipher_to_alg(int cipher) } +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 @@ int wpa_cipher_put_suites(u8 *pos, int ciphers) 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 20c79d80..2d636623 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_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse); 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 26b9acf2..9bccaaa8 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 rc4_skip(const u8 *key, size_t keylen, size_t skip, */ 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 711e312d..5215c00f 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 @@ int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac) return omac1_aes_128_vector(key, 1, &data, &data_len, mac); } #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 f757b6b5..3a675df1 100644 --- a/src/crypto/dh_groups.c +++ b/src/crypto/dh_groups.c @@ -35,6 +35,20 @@ static const u8 dh_group1_prime[96] = { 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 @@ static const u8 dh_group2_prime[128] = { 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 @@ static const u8 dh_group5_prime[192] = { 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 @@ static const u8 dh_group14_prime[256] = { 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 @@ static const u8 dh_group15_prime[384] = { 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 @@ static const u8 dh_group16_prime[512] = { 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 @@ static const u8 dh_group17_prime[768] = { 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 @@ static const u8 dh_group18_prime[1024] = { 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 225f0067..d0e74b92 100644 --- a/src/crypto/dh_groups.h +++ b/src/crypto/dh_groups.h @@ -15,6 +15,9 @@ struct dh_group { 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 0da6d130..9a11208f 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 @@ void sha256_prf(const u8 *key, size_t key_len, const char *label, 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 @@ void sha256_prf(const u8 *key, size_t key_len, const char *label, } 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 fcac8004..7596a522 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 @@ int hmac_sha256(const u8 *key, size_t key_len, const u8 *data, 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 f7bdc2c9..5e8fd656 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -898,6 +898,7 @@ struct hostapd_sta_add_params { 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 @@ struct hostapd_freq_params { int mode; int freq; int channel; + /* for HT */ int ht_enabled; int sec_channel_offset; /* 0 = HT40 disabled, -1 = HT40 enabled, * secondary channel below primary, 1 = HT40 * enabled, secondary channel above primary */ + + /* for VHT */ + int vht_enabled; + + /* valid for both HT and VHT, center_freq2 is non-zero + * only for bandwidth 80 and an 80+80 channel */ + int center_freq1, center_freq2; + int bandwidth; }; enum wpa_driver_if_type { diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c index a0a52102..c2f59344 100644 --- a/src/drivers/driver_atheros.c +++ b/src/drivers/driver_atheros.c @@ -874,7 +874,7 @@ static void atheros_raw_recv_hs20(void *ctx, const u8 *src_addr, const u8 *buf, } #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 @@ static void atheros_raw_recv_11v(void *ctx, const u8 *src_addr, const u8 *buf, 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 @@ static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf, #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 @@ static int atheros_receive_pkt(struct atheros_driver_data *drv) 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 @@ atheros_init(struct hostapd_data *hapd, struct wpa_init_params *params) 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 @@ static int atheros_send_action(void *priv, unsigned int freq, } -#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 @@ static int atheros_wnm_oper(void *priv, enum wnm_oper oper, const u8 *peer, return -1; } } -#endif /* CONFIG_IEEE80211V */ +#endif /* CONFIG_WNM */ const struct wpa_driver_ops wpa_driver_atheros_ops = { @@ -2146,7 +2150,7 @@ const struct wpa_driver_ops wpa_driver_atheros_ops = { .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 a0644b45..e530911d 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -195,6 +195,7 @@ struct i802_bss { int freq; + void *ctx; struct nl_handle *nl_preq, *nl_mgmt; struct nl_cb *nl_cb; @@ -1538,7 +1539,7 @@ static void mlme_event(struct wpa_driver_nl80211_data *drv, } -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 @@ static void mlme_event_michael_mic_failure(struct wpa_driver_nl80211_data *drv, 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 nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb, } -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 @@ static void do_process_drv_event(struct wpa_driver_nl80211_data *drv, 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 @@ static int process_drv_event(struct nl_msg *msg, void *arg) struct wpa_driver_nl80211_data *drv = arg; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct i802_bss *bss; + int ifidx = -1; nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); - if (tb[NL80211_ATTR_IFINDEX]) { - 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 @@ static int process_global_event(struct nl_msg *msg, void *arg) 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 @@ static int process_global_event(struct nl_msg *msg, void *arg) 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 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname, 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 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss) /* 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 @@ static int phy_info_handler(struct nl_msg *msg, void *arg) /* 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_ap(void *priv, 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 @@ static int wpa_driver_nl80211_set_freq(struct i802_bss *bss, 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 @@ static int wpa_driver_nl80211_set_freq(struct i802_bss *bss, 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 @@ static int wpa_driver_nl80211_sta_add(void *priv, 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_sta_set_flags(void *priv, const u8 *addr, 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 @@ static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv, } 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 @@ skip_auth_type: 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 wpa_driver_nl80211_set_supp_port(void *priv, int authorized) 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 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type, 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 89aee7df..bd65dd87 100644 --- a/src/drivers/driver_test.c +++ b/src/drivers/driver_test.c @@ -1321,7 +1321,8 @@ static void wpa_driver_test_scan_timeout(void *eloop_ctx, void *timeout_ctx) 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 1a9a819c..e3e19f8b 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 @@ enum nl80211_commands { * /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 @@ enum nl80211_commands { * * @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 @@ enum nl80211_attrs { 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 @@ struct nl80211_sta_flag_update { * @__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 @@ enum nl80211_rate_info { 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 @@ enum nl80211_ac { #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_channel_type { }; /** + * 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 @@ enum nl80211_ap_sme_features { * @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 @@ enum nl80211_feature_flags { 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 a4c9b250..85c242a8 100644 --- a/src/eap_peer/eap.c +++ b/src/eap_peer/eap.c @@ -891,6 +891,7 @@ static void eap_sm_processIdentity(struct eap_sm *sm, const struct wpabuf *req) 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 fc987da1..8c480b96 100644 --- a/src/eap_peer/eap_fast_pac.c +++ b/src/eap_peer/eap_fast_pac.c @@ -422,8 +422,12 @@ int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_pac **pac_root, 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 177b58da..469b9a0f 100644 --- a/src/eap_server/eap_server_aka.c +++ b/src/eap_server/eap_server_aka.c @@ -731,6 +731,17 @@ static void eap_aka_determine_identity(struct eap_sm *sm, 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 b122f7ce..aaacc9ac 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -630,6 +630,7 @@ static void p2p_copy_wps_info(struct p2p_device *dev, int probe_req, * 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 @@ static void p2p_copy_wps_info(struct p2p_device *dev, int probe_req, * 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 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, int level, 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 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, int level, 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 @@ void p2p_stop_find_for_freq(struct p2p_data *p2p, int freq) 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 @@ void p2p_stop_find(struct p2p_data *p2p) } -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)); - } - } else { - u8 op_reg_class, op_channel; + u8 op_class, op_channel; + unsigned int freq = force_freq ? force_freq : pref_freq; - 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; - } + 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 { 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 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr, 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 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr, 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 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr, 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 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr, 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 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr, 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 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr, 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 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr, 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 @@ static void p2p_prov_disc_cb(struct p2p_data *p2p, int success) 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 045e6f70..18e733b4 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -1200,6 +1200,7 @@ void p2p_rx_action(struct p2p_data *p2p, const u8 *da, const u8 *sa, * @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 @@ void p2p_rx_action(struct p2p_data *p2p, const u8 *da, const u8 *sa, * 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 fe4b5608..37d43bb3 100644 --- a/src/p2p/p2p_go_neg.c +++ b/src/p2p/p2p_go_neg.c @@ -145,9 +145,6 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p, 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 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p, } +/** + * 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 @@ void p2p_reselect_channel(struct p2p_data *p2p, } } + /* 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 @@ void p2p_reselect_channel(struct p2p_data *p2p, } +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 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa, 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 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa, 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 86873205..633dd5c9 100644 --- a/src/p2p/p2p_group.c +++ b/src/p2p/p2p_group.c @@ -169,6 +169,39 @@ static void p2p_group_add_noa(struct wpabuf *ie, struct wpabuf *noa) } +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 void wifi_display_group_update(struct p2p_group *group) 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 @@ static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group) 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 d2868fbb..712544b1 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -705,8 +705,9 @@ struct p2p_device * p2p_add_dev_from_go_neg_req(struct p2p_data *p2p, 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 7bf66001..ac679323 100644 --- a/src/p2p/p2p_invitation.c +++ b/src/p2p/p2p_invitation.c @@ -176,8 +176,8 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa, "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 e40f2b71..ca33f17a 100644 --- a/src/p2p/p2p_pd.c +++ b/src/p2p/p2p_pd.c @@ -151,8 +151,9 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, 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 @@ int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev, /* 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 @@ int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr, 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 f2bac348..789ac255 100644 --- a/src/rsn_supp/peerkey.c +++ b/src/rsn_supp/peerkey.c @@ -217,23 +217,17 @@ static int wpa_supplicant_process_smk_m2( 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 @@ static int wpa_supplicant_process_smk_m5(struct wpa_sm *sm, 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 @@ static int wpa_supplicant_process_smk_m5(struct wpa_sm *sm, /* 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 7646ca88..c38fadaf 100644 --- a/src/rsn_supp/tdls.c +++ b/src/rsn_supp/tdls.c @@ -1309,21 +1309,10 @@ static int copy_supp_rates(const struct wpa_eapol_ie_parse *kde, 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 3c45f3a0..e50404ce 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -2627,7 +2627,7 @@ void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx) } -#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 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf) #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 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf) 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 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf) 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 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf) } #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 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf) return 0; } -#endif /* CONFIG_IEEE80211V */ +#endif /* CONFIG_WNM */ diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index 8afdf39b..791974c2 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -365,8 +365,6 @@ void wpa_tdls_enable(struct wpa_sm *sm, int enabled); void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr); int wpa_tdls_is_external_setup(struct wpa_sm *sm); -#ifdef CONFIG_IEEE80211V int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf); -#endif /* CONFIG_IEEE80211V */ #endif /* WPA_H */ diff --git a/src/utils/common.h b/src/utils/common.h index 5fc916c0..a859042a 100644 --- a/src/utils/common.h +++ b/src/utils/common.h @@ -224,69 +224,105 @@ static inline unsigned int wpa_swap_32(unsigned int v) /* 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) - -#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) - -#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) - -#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) - -#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) - -#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) - -#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 u16 WPA_GET_BE16(const u8 *a) +{ + return (a[0] << 8) | a[1]; +} + +static inline void WPA_PUT_BE16(u8 *a, u16 val) +{ + a[0] = val >> 8; + a[1] = val & 0xff; +} + +static inline u16 WPA_GET_LE16(const u8 *a) +{ + return (a[1] << 8) | a[0]; +} + +static inline void WPA_PUT_LE16(u8 *a, u16 val) +{ + a[1] = val >> 8; + a[0] = val & 0xff; +} + +static inline u32 WPA_GET_BE24(const u8 *a) +{ + return (a[0] << 16) | (a[1] << 8) | a[2]; +} + +static inline void WPA_PUT_BE24(u8 *a, u32 val) +{ + a[0] = (val >> 16) & 0xff; + a[1] = (val >> 8) & 0xff; + a[2] = val & 0xff; +} + +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 b24836ee..11e7e84b 100644 --- a/src/wps/wps_registrar.c +++ b/src/wps/wps_registrar.c @@ -1298,7 +1298,7 @@ static int wps_set_ie(struct wps_registrar *reg) 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 0ebe607b..7545ab2c 100644 --- a/wpa_supplicant/Android.mk +++ b/wpa_supplicant/Android.mk @@ -195,10 +195,13 @@ endif 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 @@ endif 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 @@ OBJS += src/ap/eap_user_db.c ifdef CONFIG_IEEE80211N OBJS += src/ap/ieee802_11_ht.c endif +ifdef CONFIG_WNM +OBJS += src/ap/wnm_ap.c +endif ifdef CONFIG_CTRL_IFACE OBJS += src/ap/ctrl_iface_ap.c endif @@ -760,10 +766,6 @@ ifdef CONFIG_IEEE80211N 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 += src/eap_peer/eap_tls_common.c 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 @@ SHA1OBJS += src/crypto/sha1-tlsprf.c 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 @@ OBJS += src/crypto/dh_group5.c 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 6a5ab17a..3f10e113 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 @@ ChangeLog for wpa_supplicant 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 @@ ChangeLog for wpa_supplicant * 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 @@ ChangeLog for wpa_supplicant * 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 c6c76ec8..f39a3d7b 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -174,10 +174,13 @@ endif 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 @@ endif 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 @@ OBJS += ../src/ap/eap_user_db.o ifdef CONFIG_IEEE80211N OBJS += ../src/ap/ieee802_11_ht.o endif +ifdef CONFIG_WNM +OBJS += ../src/ap/wnm_ap.o +endif ifdef CONFIG_CTRL_IFACE OBJS += ../src/ap/ctrl_iface_ap.o endif @@ -738,10 +744,6 @@ ifdef CONFIG_IEEE80211N 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 += ../src/eap_peer/eap_tls_common.o 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 @@ OBJS += ../src/crypto/dh_group5.o endif endif +ifdef NEED_ECC +CFLAGS += -DCONFIG_ECC +endif + ifdef CONFIG_NO_RANDOM_POOL CFLAGS += -DCONFIG_NO_RANDOM_POOL else @@ -1406,6 +1414,7 @@ CFLAGS += -DCONFIG_OFFCHANNEL 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 a06e5c1f..d84e61e4 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 feb90490..5669c55c 100644 --- a/wpa_supplicant/README-HS20 +++ b/wpa_supplicant/README-HS20 @@ -190,6 +190,11 @@ Credentials can be pre-configured for automatic network selection: # 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 4abc2f2a..fb99c7bc 100644 --- a/wpa_supplicant/README-P2P +++ b/wpa_supplicant/README-P2P @@ -191,7 +191,13 @@ group interface is used as a parameter for this command. 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 @@ This command returns an identifier for the pending query (e.g., 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 e261ef9d..85ee6cb2 100644 --- a/wpa_supplicant/ap.c +++ b/wpa_supplicant/ap.c @@ -46,7 +46,6 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s, struct hostapd_config *conf) { struct hostapd_bss_config *bss = &conf->bss[0]; - int pairwise; conf->driver = wpa_s->driver; @@ -63,6 +62,10 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s, (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 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s, 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 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s, 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 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s, 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 @@ void wpa_supplicant_ap_deinit(struct wpa_supplicant *wpa_s) 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 0babbd5e..87b7db89 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 @@ static void wpa_bss_set_hessid(struct wpa_bss *bss) } +/** + * 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 @@ struct wpa_bss_anqp * wpa_bss_anqp_alloc(void) } +/** + * 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 @@ static struct wpa_bss_anqp * wpa_bss_anqp_clone(struct wpa_bss_anqp *anqp) } +/** + * 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 @@ int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss) } +/** + * 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 @@ static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, } +/** + * 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(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, } +/** + * 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 @@ void wpa_bss_update_start(struct wpa_supplicant *wpa_s) } +/** + * 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 @@ static int wpa_bss_included_in_scan(const struct wpa_bss *bss, } +/** + * 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 @@ void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info, } +/** + * 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 @@ static void wpa_bss_timeout(void *eloop_ctx, void *timeout_ctx) } +/** + * 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 @@ int wpa_bss_init(struct wpa_supplicant *wpa_s) } +/** + * 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 @@ void wpa_bss_flush(struct wpa_supplicant *wpa_s) } +/** + * 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 @@ void wpa_bss_deinit(struct wpa_supplicant *wpa_s) } +/** + * 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 @@ struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s, #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 @@ struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s, #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 @@ struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id) } +/** + * 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 @@ const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie) } +/** + * 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 @@ const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type) } +/** + * 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 @@ struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss, } +/** + * 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 @@ struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss, } +/** + * 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 @@ int wpa_bss_get_max_rate(const struct wpa_bss *bss) } +/** + * 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 eb01f2da..01f6c59d 100644 --- a/wpa_supplicant/bss.h +++ b/wpa_supplicant/bss.h @@ -19,7 +19,11 @@ struct wpa_scan_res; #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_anqp { /** * 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 e157845f..2c52c682 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -629,49 +629,12 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data, 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 @@ static int wpa_config_parse_cipher(int line, const char *value) #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 @@ static int wpa_config_parse_pairwise(const struct parse_data *data, 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 @@ static int wpa_config_parse_group(const struct parse_data *data, 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 @@ static char * wpa_config_write_auth_alg(const struct parse_data *data, #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 @@ static int wpa_config_parse_scan_freq(const struct parse_data *data, { 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 @@ static int wpa_config_parse_freq_list(const struct parse_data *data, { 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 @@ static const struct parse_data ssid_fields[] = { #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 @@ static const struct parse_data ssid_fields[] = { #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 @@ void wpa_config_free_cred(struct wpa_cred *cred) 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 @@ void wpa_config_free(struct wpa_config *config) 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 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid) #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 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var, 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_hessid( } +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 @@ static const struct global_parse_data global_fields[] = { { 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 c0aea0b3..0c3cb9a9 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -196,6 +196,12 @@ struct wpa_cred { * 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 wpa_config { 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 @@ struct wpa_config { * 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 d66eac55..50c35333 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 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) 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 @@ static void wpa_config_write_cred(FILE *f, struct wpa_cred *cred) 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 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) 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 c1184f87..d079863b 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 @@ struct wpa_ssid { 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 564c91ed..3408a854 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 @@ static int pno_start(struct wpa_supplicant *wpa_s) 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_start(struct wpa_supplicant *wpa_s) 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 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, 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 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s, #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 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s, 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 int wpa_supplicant_ctrl_iface_list_networks( 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 @@ static int ctrl_iface_get_capability_channels(struct wpa_supplicant *wpa_s, case HOSTAPD_MODE_IEEE80211A: hmode = "A"; break; + case HOSTAPD_MODE_IEEE80211AD: + hmode = "AD"; + break; default: continue; } @@ -4698,6 +4685,60 @@ static int wpa_supplicant_ctrl_iface_autoscan(struct wpa_supplicant *wpa_s, #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 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, 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 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } 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 03b8c7e4..87e399c7 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 @@ static int add_extra_attr(struct radius_msg *msg, 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 @@ static int add_extra_attr(struct radius_msg *msg, 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 @@ static void ieee802_1x_encapsulate_radius(struct eapol_test_data *e, 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 @@ int main(int argc, char *argv[]) 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 91c644f1..3fefb48d 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -102,8 +102,9 @@ static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s) 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 @@ static void wnm_bss_keep_alive(void *eloop_ctx, void *sock_ctx) 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 @@ static void wpa_supplicant_event_tdls(struct wpa_supplicant *wpa_s, #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 @@ static void wpa_supplicant_event_wnm(struct wpa_supplicant *wpa_s, "(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 wpa_supplicant_event_unprot_disassoc(struct wpa_supplicant *wpa_s, } -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 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, 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 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, } #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 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, 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 0d4ca8ec..27bcc7aa 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 @@ struct gas_query_pending { 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_tx_comeback_timeout(void *eloop_data, void *user_ctx); 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 @@ static void gas_query_done(struct gas_query *gas, } +/** + * 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 @@ static void gas_query_rx_comeback(struct gas_query *gas, } +/** + * 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 @@ static int gas_query_dialog_token_available(struct gas_query *gas, } +/** + * 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 @@ int gas_query_req(struct gas_query *gas, const u8 *dst, int freq, } +/** + * 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 01aba6e8..5c3d161a 100644 --- a/wpa_supplicant/gas_query.h +++ b/wpa_supplicant/gas_query.h @@ -19,6 +19,9 @@ void gas_query_deinit(struct gas_query *gas); 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 cfe56ea9..b8a8bb2b 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 int additional_roaming_consortiums(struct wpa_bss *bss) } +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 @@ static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s, 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 @@ static int nai_realm_cred_username(struct nai_realm_eap *eap) 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 roaming_consortium_match(const u8 *ie, const struct wpabuf *anqp, } +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 @@ static struct wpa_cred * interworking_credentials_available_roaming_consortium( 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 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) 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 @@ static struct wpa_cred * interworking_credentials_available_3gpp( 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 @@ static struct wpa_cred * interworking_credentials_available_realm( 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 @@ int interworking_home_sp_cred(struct wpa_supplicant *wpa_s, 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 @@ int interworking_home_sp_cred(struct wpa_supplicant *wpa_s, } #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 @@ interworking_match_anqp_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) 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 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s) 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 b88eab1e..856eca70 100644 --- a/wpa_supplicant/offchannel.c +++ b/wpa_supplicant/offchannel.c @@ -132,6 +132,17 @@ static void wpas_send_action_cb(void *eloop_ctx, void *timeout_ctx) } +/** + * 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 @@ void offchannel_send_action_tx_status( } +/** + * 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 @@ int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq, } +/** + * 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 @@ void offchannel_send_action_done(struct wpa_supplicant *wpa_s) } +/** + * 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 @@ void offchannel_remain_on_channel_cb(struct wpa_supplicant *wpa_s, } +/** + * 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_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s, } -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 1d3948c0..0ad7e18f 100644 --- a/wpa_supplicant/offchannel.h +++ b/wpa_supplicant/offchannel.h @@ -29,5 +29,7 @@ void offchannel_deinit(struct wpa_supplicant *wpa_s); 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 c2d702e2..523178ff 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -112,7 +112,7 @@ static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s, 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 @@ static void p2p_go_configured(void *ctx, void *data) 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 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s, 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 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s) } 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 @@ void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s, { 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 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s, 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 @@ int wpas_p2p_scan_result_text(const u8 *ies, size_t ies_len, char *buf, 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 @@ void wpas_p2p_update_channel_list(struct wpa_supplicant *wpa_s) } +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 @@ int wpas_p2p_cancel(struct wpa_supplicant *wpa_s) 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 048e6d01..c59b8bab 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 @@ static int wpas_wps_in_use(struct wpa_supplicant *wpa_s, #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 @@ static void int_array_sort_unique(int *a) } +/** + * 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 @@ void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec) * @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 @@ int wpa_supplicant_delayed_sched_scan(struct wpa_supplicant *wpa_s, /** * 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 @@ void wpa_supplicant_cancel_sched_scan(struct wpa_supplicant *wpa_s) } +/** + * 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 @@ static int wpa_scan_get_max_rate(const struct wpa_scan_res *res) } +/** + * 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 @@ const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie) } +/** + * 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 @@ const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res, } +/** + * 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(const struct wpa_scan_res *res, } -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 @@ static void dump_scan_res(struct wpa_scan_results *scan_res) } +/** + * 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_get_scan_results(struct wpa_supplicant *wpa_s, } +/** + * 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 b0ddf97e..5096287a 100644 --- a/wpa_supplicant/scan.h +++ b/wpa_supplicant/scan.h @@ -30,8 +30,6 @@ const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res, 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 e273cb3f..30f9779e 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 @@ static void sme_stop_sa_query(struct wpa_supplicant *wpa_s); #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; + + 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; + } - buf = wpabuf_alloc(4 + 2); + 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 @@ static struct wpabuf * sme_auth_build_sae_confirm(struct wpa_supplicant *wpa_s) { 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 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, #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 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, } #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 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, 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 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, 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 (sae_parse_commit(&wpa_s->sme.sae, data, len, NULL, NULL, + wpa_s->conf->sae_groups) != + WLAN_STATUS_SUCCESS) return -1; - if (sme_sae_process_commit(wpa_s, data, len) < 0) + + 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 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data) } 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 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode, 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 @@ void sme_deinit(struct wpa_supplicant *wpa_s) #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 0d659ada..ba2be6f5 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 98ce9661..4d9e4533 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 @@ static int ieee80211_11_set_tfs_ie(struct wpa_supplicant *wpa_s, /* 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 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, 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 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, 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 (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 (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; + } } + 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 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, 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 @@ int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, } +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 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s, */ 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 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s, 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 @@ void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s, break; } } - -#endif /* CONFIG_IEEE80211V */ diff --git a/wpa_supplicant/wnm_sta.h b/wpa_supplicant/wnm_sta.h index ba2535b0..3f9d88b7 100644 --- a/wpa_supplicant/wnm_sta.h +++ b/wpa_supplicant/wnm_sta.h @@ -13,7 +13,7 @@ struct rx_action; 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 4e7c81ce..cc080097 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 @@ static int wpa_cli_cmd_autoscan(struct wpa_ctrl *ctrl, int argc, char *argv[]) #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 @@ static struct wpa_cli_cmd wpa_cli_commands[] = { { "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 42e14f01..6bba8d21 100644 --- a/wpa_supplicant/wpa_gui-qt4/wpagui.cpp +++ b/wpa_supplicant/wpa_gui-qt4/wpagui.cpp @@ -709,7 +709,7 @@ void WpaGui::helpContents() 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 2f7d9ea5..ee1a06c5 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 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s, 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 @@ static void wpa_supplicant_reconfig(int sig, void *signal_ctx) } -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 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, } 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 wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, } +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 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, 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 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, } #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_ht40(struct wpa_supplicant *wpa_s, } +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 @@ void wpa_supplicant_apply_ht_overrides( 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 5f0dec66..18460b89 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -281,6 +281,14 @@ fast_reauth=1 # 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 @@ fast_reauth=1 # 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 @@ fast_reauth=1 # 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 @@ fast_reauth=1 # 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 87d20981..ecbdedf0 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 @@ struct wpa_global { }; +/** + * 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 @@ struct wpa_supplicant { 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 @@ struct wpa_supplicant { 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 wpa_supplicant { 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_terminate_proc(struct wpa_global *global); 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_bssid(struct wpa_supplicant *wpa_s, const u8 *bssid); int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid, size_t ssid_len); void wpas_request_connection(struct wpa_supplicant *wpa_s); +int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf); /** * wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c index 1ba4c92b..4859774f 100644 --- a/wpa_supplicant/wpas_glue.c +++ b/wpa_supplicant/wpas_glue.c @@ -662,6 +662,8 @@ static void wpa_supplicant_eap_param_needed(void *ctx, 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 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s) } +#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 @@ static void wpa_supplicant_set_rekey_offload(void *ctx, const u8 *kek, 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 0239c55d..711c3c08 100644 --- a/wpa_supplicant/wps_supplicant.c +++ b/wpa_supplicant/wps_supplicant.c @@ -423,6 +423,13 @@ static int wpa_supplicant_wps_cred(void *ctx, } #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_cb(void *eloop_ctx, void *timeout_ctx); static void wpas_wps_reenable_networks(struct wpa_supplicant *wpa_s) { struct wpa_ssid *ssid; + int changed = 0; eloop_cancel_timeout(wpas_wps_reenable_networks_cb, wpa_s, NULL); @@ -512,8 +520,19 @@ static void wpas_wps_reenable_networks(struct wpa_supplicant *wpa_s) 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 @@ int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid, } } #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 @@ int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid, 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 @@ int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid, 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, |
