diff options
| author | Dmitry Shmidt <dimitrysh@google.com> | 2015-02-25 14:36:37 -0800 |
|---|---|---|
| committer | Dmitry Shmidt <dimitrysh@google.com> | 2015-03-10 11:04:32 -0700 |
| commit | 7f65602d49069f96a7bb44da8bd79ffe8d4c6a98 (patch) | |
| tree | 0f5470742861a3ea4efb80552c3f8282fb79092c | |
| parent | 912d96b4e283c9bc0633a065901153bf74e1f911 (diff) | |
| download | android_external_wpa_supplicant_8-7f65602d49069f96a7bb44da8bd79ffe8d4c6a98.tar.gz android_external_wpa_supplicant_8-7f65602d49069f96a7bb44da8bd79ffe8d4c6a98.tar.bz2 android_external_wpa_supplicant_8-7f65602d49069f96a7bb44da8bd79ffe8d4c6a98.zip | |
Cumulative patch from commit f51f54a007e0de1d413dee3523472d3bbeed2ecc
f51f54a nl80211: Resubscribe to nl80211 events on global nl_event socket
48ec694 Fix Linux packet socket workaround to not close the socket too easily
0d2030e Use estimated throughput to improve roaming selection
1d747e2 Add snr and est_throughput to the BSS entries
a1b790e Select AP based on estimated maximum throughput
ab647ff Add wpa_supplicant Makefile target libwpa_ctrl.a
abae2d1 trace: Initialize alloc_list even without os_program_init() call
891dfb3 Add helper function to clear and free wpa_psk list
71d77ad Update current BSS level when signal change event occurs
f1609f1 wpa_supplicant: Cancel sched_scan when stopping countermeasures
abb8d08 nl80211: Add support for configuring P2P GO CTWindow
0b8bcaa P2P: Allow configuring CTWindow when working as GO
c77ffc6 TDLS: Ignore extra padding in all packets
5ce6ac1 Inteworking: Add support to update the ANQP Capability List into the BSS
185ada4 HS 2.0: Add support to update the HS20 Capability List into the BSS
7fe7a3a wpa_gui: Debug enhancement
2b892d4 Add forgotten network profile parameters to config file writing
563ee18 IBSS: Add support for VHT80 configuration
ada157f Make hostapd_set_freq_params() common
98479dc IBSS: Update operating frequency if joining an existing IBSS
4d9e6fb IBSS: Add fixed_freq network parameter
6f5e1b0 Use priority list instead of global for PNO
97fc2dc Allow libnl-3.0 include path be specified
f92446f P2PS: Add P2PS interface info
59b416c Add optional reassoc-to-same-BSS optimization
c4da67d Fix passive_scan config parameter writing
715d5c4 hs20-osu-client: Ensure NULL checks are done before dereferencing
58d405f Fix OCSP debug messages
710dfb4 OpenSSL: Fix OCSP error path
bd7bb43 HTTP: Fix OCSP error path
946572c Android: Remove commented out non-Android build parameters
15ada7f Android: Remove libxml2 config defines
ebe8d3f Android: Silence unused function parameter warnings
dbd10da Android: Fix hs20-osu-client build on Android 5.0
a926295 HS 2.0R2: Fix permissions for SP/<fqdn> directory on Android
480994d nl80211: Allocate QCA vendor subcmds for DFS radar detected and CAC events
c165cb4 Drop all hostapd STA entries on interface disabled event
106fa1e nl80211: Indicate interface-down event only for the main netdev
eeb1cb2 VLAN: Clean up RTM_NEW/DELLINK processing
47e5fbd hostapd: Avoid sending client probe on removed client
3478273 Re-configure WPA2 group keys on hostapd interface re-enable
f33c860 Re-enable beaconing on interface disable+enable
fc99fab nl80211: Print a debug log entry on NL80211_CMD_PROBE_CLIENT failures
0d2f324 P2P: Fix send_action_in_progress clearing in corner cases
9ff8dda Add hostapd UPDATE_BEACON ctrl_iface command
e0761c5 nl80211: Allocate QCA vendor subcmd for DFS CAC Start event
1db718b nl80211: Test vendor command and event
10263dc Add control interface commands for fetching wpa_config values
f91a512 Add INTERWORKING_ADD_NETWORK command
c612ae9 AP: Do not reply to Probe Request frames with DS Params mismatch
5b74e08 P2P: Document P2P_CONNECT-auto
99650ca Add STOP_AP control interface command
6b00512 P2P: Add event messages for P2P_CONNECT-fallback-to-GO-Neg
b0e669b P2P: Fix P2P_CONNECT-auto fallback to GO Neg with group interface
bf51f4f mesh: Fix remaining BLOCKED state after SAE auth failure
79ddb20 mesh: Add a monitor event on SAE authentication getting blocked
dd2cbaf mesh: Add a monitor event for SAE authentication failure
0cb5f8d mesh: Fix inactivity timer for 32 bit system
11e2ddb mesh: Remove duplicated no_auto_peer update
1e52983 D-Bus: Fix network block type change
4fada12 Fix HT40 co-ex scanning issue on hostapd error path
23ed011 Fix Linux packat socket regression work around
663ae2f Don't write to wpa_supplicant.conf directly
d9a9bc0 IBSS: Do not enable HT with WEP or TKIP
0d7eb43 ACS: Accept channel if any (rather than all) survey results are valid
68fa00c ACS: Allow specific channels to be preferred
6f41a25 ACS: Use weighted average for 2.4 GHz adjacent channel interference
Change-Id: Ie1cabd28dcfdefafa02e81477e34badae6f7e629
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
66 files changed, 1854 insertions, 351 deletions
diff --git a/hostapd/config_file.c b/hostapd/config_file.c index e3cad7c9..9edbe632 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -1856,6 +1856,48 @@ static struct wpabuf * hostapd_parse_bin(const char *buf) #endif /* CONFIG_WPS_NFC */ +#ifdef CONFIG_ACS +static int hostapd_config_parse_acs_chan_bias(struct hostapd_config *conf, + char *pos) +{ + struct acs_bias *bias = NULL, *tmp; + unsigned int num = 0; + char *end; + + while (*pos) { + tmp = os_realloc_array(bias, num + 1, sizeof(*bias)); + if (!tmp) + goto fail; + bias = tmp; + + bias[num].channel = atoi(pos); + if (bias[num].channel <= 0) + goto fail; + pos = os_strchr(pos, ':'); + if (!pos) + goto fail; + pos++; + bias[num].bias = strtod(pos, &end); + if (end == pos || bias[num].bias < 0.0) + goto fail; + pos = end; + if (*pos != ' ' && *pos != '\0') + goto fail; + num++; + } + + os_free(conf->acs_chan_bias); + conf->acs_chan_bias = bias; + conf->num_acs_chan_bias = num; + + return 0; +fail: + os_free(bias); + return -1; +} +#endif /* CONFIG_ACS */ + + static int hostapd_config_fill(struct hostapd_config *conf, struct hostapd_bss_config *bss, char *buf, char *pos, int line) @@ -2283,12 +2325,11 @@ static int hostapd_config_fill(struct hostapd_config *conf, os_free(bss->ssid.wpa_passphrase); bss->ssid.wpa_passphrase = os_strdup(pos); if (bss->ssid.wpa_passphrase) { - os_free(bss->ssid.wpa_psk); - bss->ssid.wpa_psk = NULL; + hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk); bss->ssid.wpa_passphrase_set = 1; } } else if (os_strcmp(buf, "wpa_psk") == 0) { - os_free(bss->ssid.wpa_psk); + hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk); bss->ssid.wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk)); if (bss->ssid.wpa_psk == NULL) return 1; @@ -2296,8 +2337,7 @@ static int hostapd_config_fill(struct hostapd_config *conf, pos[PMK_LEN * 2] != '\0') { wpa_printf(MSG_ERROR, "Line %d: Invalid PSK '%s'.", line, pos); - os_free(bss->ssid.wpa_psk); - bss->ssid.wpa_psk = NULL; + hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk); return 1; } bss->ssid.wpa_psk->group = 1; @@ -2508,6 +2548,12 @@ static int hostapd_config_fill(struct hostapd_config *conf, return 1; } conf->acs_num_scans = val; + } else if (os_strcmp(buf, "acs_chan_bias") == 0) { + if (hostapd_config_parse_acs_chan_bias(conf, pos)) { + wpa_printf(MSG_ERROR, "Line %d: invalid acs_chan_bias", + line); + return -1; + } #endif /* CONFIG_ACS */ } else if (os_strcmp(buf, "dtim_period") == 0) { bss->dtim_period = atoi(pos); diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index 54b17dc9..86f1aa6d 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -40,6 +40,7 @@ #include "ap/hs20.h" #include "ap/wnm_ap.h" #include "ap/wpa_auth.h" +#include "ap/beacon.h" #include "wps/wps_defs.h" #include "wps/wps.h" #include "config_file.h" @@ -1955,6 +1956,9 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) { if (hostapd_ctrl_iface_disassociate(hapd, buf + 13)) reply_len = -1; + } else if (os_strcmp(buf, "STOP_AP") == 0) { + if (hostapd_ctrl_iface_stop_ap(hapd)) + reply_len = -1; #ifdef CONFIG_IEEE80211W #ifdef NEED_AP_MLME } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) { @@ -2047,6 +2051,9 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, } else if (os_strncmp(buf, "DISABLE", 7) == 0) { if (hostapd_ctrl_iface_disable(hapd->iface)) reply_len = -1; + } else if (os_strcmp(buf, "UPDATE_BEACON") == 0) { + if (ieee802_11_set_beacon(hapd)) + reply_len = -1; #ifdef CONFIG_TESTING_OPTIONS } else if (os_strncmp(buf, "RADAR ", 6) == 0) { if (hostapd_ctrl_iface_radar(hapd, buf + 6)) diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index 1e569598..dd05c2ff 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -154,8 +154,19 @@ channel=1 # interference that may help choosing a better channel. This can also help fine # tune the ACS scan time in case a driver has different scan dwell times. # +# acs_chan_bias is a space-separated list of <channel>:<bias> pairs. It can be +# used to increase (or decrease) the likelihood of a specific channel to be +# selected by the ACS algorithm. The total interference factor for each channel +# gets multiplied by the specified bias value before finding the channel with +# the lowest value. In other words, values between 0.0 and 1.0 can be used to +# make a channel more likely to be picked while values larger than 1.0 make the +# specified channel less likely to be picked. This can be used, e.g., to prefer +# the commonly used 2.4 GHz band channels 1, 6, and 11 (which is the default +# behavior on 2.4 GHz band if no acs_chan_bias parameter is specified). +# # Defaults: #acs_num_scans=5 +#acs_chan_bias=1:0.8 6:0.8 11:0.8 # Channel list restriction. This option allows hostapd to select one of the # provided channels when a channel should be automatically selected. diff --git a/hs20/client/Android.mk b/hs20/client/Android.mk index 63cbc6f2..212aefe4 100644 --- a/hs20/client/Android.mk +++ b/hs20/client/Android.mk @@ -12,19 +12,21 @@ ifneq ($(wildcard external/icu),) INCLUDES += external/icu/icu4c/source/common else INCLUDES += external/icu4c/common +else +# The LOCAL_EXPORT_C_INCLUDE_DIRS from ICU did not seem to fully resolve the +# build (e.g., "mm -B" failed to build, but following that with "mm" allowed +# the build to complete). For now, add the include directory manually here for +# Android 5.0. +ver = $(filter 5.0%,$(PLATFORM_VERSION)) +ifneq (,$(strip $(ver))) +INCLUDES += external/icu/icu4c/source/common +endif endif -#GTKCFLAGS := $(shell pkg-config --cflags gtk+-2.0 webkit-1.0) -#GTKLIBS := $(shell pkg-config --libs gtk+-2.0 webkit-1.0) -#CFLAGS += $(GTKCFLAGS) -#LIBS += $(GTKLIBS) - L_CFLAGS += -DCONFIG_CTRL_IFACE L_CFLAGS += -DCONFIG_CTRL_IFACE_UNIX L_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/misc/wifi/sockets\" -L_CFLAGS += -DLIBXML_SCHEMAS_ENABLED -L_CFLAGS += -DLIBXML_REGEXP_ENABLED OBJS = spp_client.c OBJS += oma_dm_client.c @@ -53,8 +55,7 @@ OBJS += ../../src/crypto/sha256-internal.c L_CFLAGS += -DEAP_TLS_OPENSSL -#CFLAGS += $(shell xml2-config --cflags) -#LIBS += $(shell xml2-config --libs) +L_CFLAGS += -Wno-unused-parameter ######################## diff --git a/hs20/client/oma_dm_client.c b/hs20/client/oma_dm_client.c index 82e91062..6eaeeb47 100644 --- a/hs20/client/oma_dm_client.c +++ b/hs20/client/oma_dm_client.c @@ -394,6 +394,10 @@ static int oma_dm_exec_browser(struct hs20_osu_client *ctx, xml_node_t *exec) } data = xml_node_get_text(ctx->xml, node); + if (data == NULL) { + wpa_printf(MSG_INFO, "Invalid data"); + return DM_RESP_BAD_REQUEST; + } wpa_printf(MSG_INFO, "Data: %s", data); wpa_printf(MSG_INFO, "Launch browser to URI '%s'", data); write_summary(ctx, "Launch browser to URI '%s'", data); @@ -428,6 +432,10 @@ static int oma_dm_exec_get_cert(struct hs20_osu_client *ctx, xml_node_t *exec) } data = xml_node_get_text(ctx->xml, node); + if (data == NULL) { + wpa_printf(MSG_INFO, "Invalid data"); + return DM_RESP_BAD_REQUEST; + } wpa_printf(MSG_INFO, "Data: %s", data); getcert = xml_node_from_buf(ctx->xml, data); xml_node_get_text_free(ctx->xml, data); @@ -576,6 +584,11 @@ static int oma_dm_run_add(struct hs20_osu_client *ctx, const char *locuri, if (node) { char *type; type = xml_node_get_text(ctx->xml, node); + if (type == NULL) { + wpa_printf(MSG_ERROR, "Could not find type text"); + os_free(uri); + return DM_RESP_BAD_REQUEST; + } use_tnds = node && os_strstr(type, "application/vnd.syncml.dmtnds+xml"); } @@ -648,6 +661,10 @@ static int oma_dm_add(struct hs20_osu_client *ctx, xml_node_t *add, return DM_RESP_BAD_REQUEST; } locuri = xml_node_get_text(ctx->xml, node); + if (locuri == NULL) { + wpa_printf(MSG_ERROR, "No LocURI node text found"); + return DM_RESP_BAD_REQUEST; + } wpa_printf(MSG_INFO, "Target LocURI: %s", locuri); if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) { wpa_printf(MSG_INFO, "Unsupported Add Target LocURI"); diff --git a/hs20/client/osu_client.c b/hs20/client/osu_client.c index e452aa70..de7f351d 100644 --- a/hs20/client/osu_client.c +++ b/hs20/client/osu_client.c @@ -9,6 +9,9 @@ #include "includes.h" #include <time.h> #include <sys/stat.h> +#ifdef ANDROID +#include "private/android_filesystem_config.h" +#endif /* ANDROID */ #include "common.h" #include "utils/browser.h" @@ -571,6 +574,21 @@ int hs20_add_pps_mo(struct hs20_osu_client *ctx, const char *uri, } } +#ifdef ANDROID + /* Allow processes running with Group ID as AID_WIFI, + * to read files from SP/<fqdn> directory */ + if (chown(fname, -1, AID_WIFI)) { + wpa_printf(MSG_INFO, "CTRL: Could not chown directory: %s", + strerror(errno)); + /* Try to continue anyway */ + } + if (chmod(fname, S_IRWXU | S_IRGRP | S_IXGRP) < 0) { + wpa_printf(MSG_INFO, "CTRL: Could not chmod directory: %s", + strerror(errno)); + /* Try to continue anyway */ + } +#endif /* ANDROID */ + snprintf(fname, fname_len, "SP/%s/pps.xml", fqdn); if (os_file_exists(fname)) { @@ -669,6 +687,10 @@ int update_pps_file(struct hs20_osu_client *ctx, const char *pps_fname, wpa_printf(MSG_INFO, "Updating PPS MO %s", pps_fname); str = xml_node_to_str(ctx->xml, pps); + if (str == NULL) { + wpa_printf(MSG_ERROR, "No node found"); + return -1; + } wpa_printf(MSG_MSGDUMP, "[hs20] Updated PPS: '%s'", str); snprintf(backup, sizeof(backup), "%s.bak", pps_fname); diff --git a/src/ap/acs.c b/src/ap/acs.c index e4c834ce..ae7f6c30 100644 --- a/src/ap/acs.c +++ b/src/ap/acs.c @@ -242,6 +242,7 @@ static int acs_request_scan(struct hostapd_iface *iface); +static int acs_survey_is_sufficient(struct freq_survey *survey); static void acs_clean_chan_surveys(struct hostapd_channel_data *chan) @@ -328,6 +329,7 @@ acs_survey_chan_interference_factor(struct hostapd_iface *iface, struct freq_survey *survey; unsigned int i = 0; long double int_factor = 0; + unsigned count = 0; if (dl_list_empty(&chan->survey_list)) return; @@ -339,18 +341,27 @@ acs_survey_chan_interference_factor(struct hostapd_iface *iface, dl_list_for_each(survey, &chan->survey_list, struct freq_survey, list) { + i++; + + if (!acs_survey_is_sufficient(survey)) { + wpa_printf(MSG_DEBUG, "ACS: %d: insufficient data", i); + continue; + } + + count++; int_factor = acs_survey_interference_factor(survey, iface->lowest_nf); chan->interference_factor += int_factor; wpa_printf(MSG_DEBUG, "ACS: %d: min_nf=%d interference_factor=%Lg nf=%d time=%lu busy=%lu rx=%lu", - ++i, chan->min_nf, int_factor, + i, chan->min_nf, int_factor, survey->nf, (unsigned long) survey->channel_time, (unsigned long) survey->channel_time_busy, (unsigned long) survey->channel_time_rx); } - chan->interference_factor = chan->interference_factor / - dl_list_len(&chan->survey_list); + if (!count) + return; + chan->interference_factor /= count; } @@ -384,18 +395,19 @@ static int acs_usable_vht80_chan(struct hostapd_channel_data *chan) static int acs_survey_is_sufficient(struct freq_survey *survey) { if (!(survey->filled & SURVEY_HAS_NF)) { - wpa_printf(MSG_ERROR, "ACS: Survey is missing noise floor"); + wpa_printf(MSG_INFO, "ACS: Survey is missing noise floor"); return 0; } if (!(survey->filled & SURVEY_HAS_CHAN_TIME)) { - wpa_printf(MSG_ERROR, "ACS: Survey is missing channel time"); + wpa_printf(MSG_INFO, "ACS: Survey is missing channel time"); return 0; } if (!(survey->filled & SURVEY_HAS_CHAN_TIME_BUSY) && !(survey->filled & SURVEY_HAS_CHAN_TIME_RX)) { - wpa_printf(MSG_ERROR, "ACS: Survey is missing RX and busy time (at least one is required)"); + wpa_printf(MSG_INFO, + "ACS: Survey is missing RX and busy time (at least one is required)"); return 0; } @@ -406,18 +418,27 @@ static int acs_survey_is_sufficient(struct freq_survey *survey) static int acs_survey_list_is_sufficient(struct hostapd_channel_data *chan) { struct freq_survey *survey; + int ret = -1; dl_list_for_each(survey, &chan->survey_list, struct freq_survey, list) { - if (!acs_survey_is_sufficient(survey)) { - wpa_printf(MSG_ERROR, "ACS: Channel %d has insufficient survey data", - chan->chan); - return 0; + if (acs_survey_is_sufficient(survey)) { + ret = 1; + break; } + ret = 0; } - return 1; + if (ret == -1) + ret = 1; /* no survey list entries */ + + if (!ret) { + wpa_printf(MSG_INFO, + "ACS: Channel %d has insufficient survey data", + chan->chan); + } + return ret; } @@ -517,6 +538,36 @@ static struct hostapd_channel_data *acs_find_chan(struct hostapd_iface *iface, } +static int is_24ghz_mode(enum hostapd_hw_mode mode) +{ + return mode == HOSTAPD_MODE_IEEE80211B || + mode == HOSTAPD_MODE_IEEE80211G; +} + + +static int is_common_24ghz_chan(int chan) +{ + return chan == 1 || chan == 6 || chan == 11; +} + + +#ifndef ACS_ADJ_WEIGHT +#define ACS_ADJ_WEIGHT 0.85 +#endif /* ACS_ADJ_WEIGHT */ + +#ifndef ACS_NEXT_ADJ_WEIGHT +#define ACS_NEXT_ADJ_WEIGHT 0.55 +#endif /* ACS_NEXT_ADJ_WEIGHT */ + +#ifndef ACS_24GHZ_PREFER_1_6_11 +/* + * Select commonly used channels 1, 6, 11 by default even if a neighboring + * channel has a smaller interference factor as long as it is not better by more + * than this multiplier. + */ +#define ACS_24GHZ_PREFER_1_6_11 0.8 +#endif /* ACS_24GHZ_PREFER_1_6_11 */ + /* * At this point it's assumed chan->interface_factor has been computed. * This function should be reusable regardless of interference computation @@ -531,6 +582,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface) long double factor, ideal_factor = 0; int i, j; int n_chans = 1; + unsigned int k; /* TODO: HT40- support */ @@ -557,6 +609,9 @@ acs_find_ideal_chan(struct hostapd_iface *iface) -1); for (i = 0; i < iface->current_mode->num_channels; i++) { + double total_weight; + struct acs_bias *bias, tmp_bias; + chan = &iface->current_mode->channels[i]; if (chan->flag & HOSTAPD_CHAN_DISABLED) @@ -588,14 +643,17 @@ acs_find_ideal_chan(struct hostapd_iface *iface) factor = 0; if (acs_usable_chan(chan)) factor = chan->interference_factor; + total_weight = 1; for (j = 1; j < n_chans; j++) { adj_chan = acs_find_chan(iface, chan->freq + (j * 20)); if (!adj_chan) break; - if (acs_usable_chan(adj_chan)) + if (acs_usable_chan(adj_chan)) { factor += adj_chan->interference_factor; + total_weight += 1; + } } if (j != n_chans) { @@ -606,36 +664,69 @@ acs_find_ideal_chan(struct hostapd_iface *iface) /* 2.4 GHz has overlapping 20 MHz channels. Include adjacent * channel interference factor. */ - if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211B || - iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) { + if (is_24ghz_mode(iface->current_mode->mode)) { for (j = 0; j < n_chans; j++) { - /* TODO: perhaps a multiplier should be used - * here? */ - adj_chan = acs_find_chan(iface, chan->freq + (j * 20) - 5); - if (adj_chan && acs_usable_chan(adj_chan)) - factor += adj_chan->interference_factor; + if (adj_chan && acs_usable_chan(adj_chan)) { + factor += ACS_ADJ_WEIGHT * + adj_chan->interference_factor; + total_weight += ACS_ADJ_WEIGHT; + } adj_chan = acs_find_chan(iface, chan->freq + (j * 20) - 10); - if (adj_chan && acs_usable_chan(adj_chan)) - factor += adj_chan->interference_factor; + if (adj_chan && acs_usable_chan(adj_chan)) { + factor += ACS_NEXT_ADJ_WEIGHT * + adj_chan->interference_factor; + total_weight += ACS_NEXT_ADJ_WEIGHT; + } adj_chan = acs_find_chan(iface, chan->freq + (j * 20) + 5); - if (adj_chan && acs_usable_chan(adj_chan)) - factor += adj_chan->interference_factor; + if (adj_chan && acs_usable_chan(adj_chan)) { + factor += ACS_ADJ_WEIGHT * + adj_chan->interference_factor; + total_weight += ACS_ADJ_WEIGHT; + } adj_chan = acs_find_chan(iface, chan->freq + (j * 20) + 10); - if (adj_chan && acs_usable_chan(adj_chan)) - factor += adj_chan->interference_factor; + if (adj_chan && acs_usable_chan(adj_chan)) { + factor += ACS_NEXT_ADJ_WEIGHT * + adj_chan->interference_factor; + total_weight += ACS_NEXT_ADJ_WEIGHT; + } + } + } + + factor /= total_weight; + + bias = NULL; + if (iface->conf->acs_chan_bias) { + for (k = 0; k < iface->conf->num_acs_chan_bias; k++) { + bias = &iface->conf->acs_chan_bias[k]; + if (bias->channel == chan->chan) + break; + bias = NULL; } + } else if (is_24ghz_mode(iface->current_mode->mode) && + is_common_24ghz_chan(chan->chan)) { + tmp_bias.channel = chan->chan; + tmp_bias.bias = ACS_24GHZ_PREFER_1_6_11; + bias = &tmp_bias; } - wpa_printf(MSG_DEBUG, "ACS: * channel %d: total interference = %Lg", - chan->chan, factor); + if (bias) { + factor *= bias->bias; + wpa_printf(MSG_DEBUG, + "ACS: * channel %d: total interference = %Lg (%f bias)", + chan->chan, factor, bias->bias); + } else { + wpa_printf(MSG_DEBUG, + "ACS: * channel %d: total interference = %Lg", + chan->chan, factor); + } if (acs_usable_chan(chan) && (!ideal_chan || factor < ideal_factor)) { diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index 1c0ed7aa..76011dc0 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -394,20 +394,27 @@ static void hostapd_config_free_wep(struct hostapd_wep_keys *keys) } +void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **l) +{ + struct hostapd_wpa_psk *psk, *tmp; + + for (psk = *l; psk;) { + tmp = psk; + psk = psk->next; + bin_clear_free(tmp, sizeof(*tmp)); + } + *l = NULL; +} + + void hostapd_config_free_bss(struct hostapd_bss_config *conf) { - struct hostapd_wpa_psk *psk, *prev; struct hostapd_eap_user *user, *prev_user; if (conf == NULL) return; - psk = conf->ssid.wpa_psk; - while (psk) { - prev = psk; - psk = psk->next; - bin_clear_free(prev, sizeof(*prev)); - } + hostapd_config_clear_wpa_psk(&conf->ssid.wpa_psk); str_clear_free(conf->ssid.wpa_passphrase); os_free(conf->ssid.wpa_psk_file); @@ -574,6 +581,9 @@ void hostapd_config_free(struct hostapd_config *conf) os_free(conf->basic_rates); os_free(conf->chanlist); os_free(conf->driver_params); +#ifdef CONFIG_ACS + os_free(conf->acs_chan_bias); +#endif /* CONFIG_ACS */ os_free(conf); } diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index e5215c52..961d2dd3 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -629,6 +629,10 @@ struct hostapd_config { u8 vht_oper_centr_freq_seg0_idx; u8 vht_oper_centr_freq_seg1_idx; +#ifdef CONFIG_P2P + u8 p2p_go_ctwindow; +#endif /* CONFIG_P2P */ + #ifdef CONFIG_TESTING_OPTIONS double ignore_probe_probability; double ignore_auth_probability; @@ -639,6 +643,11 @@ struct hostapd_config { #ifdef CONFIG_ACS unsigned int acs_num_scans; + struct acs_bias { + int channel; + double bias; + } *acs_chan_bias; + unsigned int num_acs_chan_bias; #endif /* CONFIG_ACS */ }; @@ -648,6 +657,7 @@ int hostapd_mac_comp_empty(const void *a); struct hostapd_config * hostapd_config_defaults(void); void hostapd_config_defaults_bss(struct hostapd_bss_config *bss); void hostapd_config_free_eap_user(struct hostapd_eap_user *user); +void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **p); void hostapd_config_free_bss(struct hostapd_bss_config *conf); void hostapd_config_free(struct hostapd_config *conf); int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries, diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c index 8514cbe7..e16306c4 100644 --- a/src/ap/ap_drv_ops.c +++ b/src/ap/ap_drv_ops.c @@ -10,6 +10,7 @@ #include "utils/common.h" #include "common/ieee802_11_defs.h" +#include "common/hw_features_common.h" #include "wps/wps.h" #include "p2p/p2p.h" #include "hostapd.h" @@ -477,92 +478,6 @@ int hostapd_flush(struct hostapd_data *hapd) } -int hostapd_set_freq_params(struct hostapd_freq_params *data, - enum hostapd_hw_mode mode, - int freq, int channel, int ht_enabled, - int vht_enabled, int sec_channel_offset, - int vht_oper_chwidth, int center_segment0, - int center_segment1, u32 vht_caps) -{ - int 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 (center_segment0 != 0 && - 5000 + center_segment0 * 5 != data->center_freq1 && - 2407 + center_segment0 * 5 != data->center_freq1) - return -1; - break; - case VHT_CHANWIDTH_80P80MHZ: - if (!(vht_caps & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) { - wpa_printf(MSG_ERROR, - "80+80 channel width is not supported!"); - return -1; - } - 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 (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ | - VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) { - wpa_printf(MSG_ERROR, - "160MHZ channel width is not supported!"); - return -1; - } - 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; - } - - return 0; -} - - int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode, int freq, int channel, int ht_enabled, int vht_enabled, int sec_channel_offset, int vht_oper_chwidth, diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h index c133be75..5d07e71f 100644 --- a/src/ap/ap_drv_ops.h +++ b/src/ap/ap_drv_ops.h @@ -107,12 +107,6 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface, int channel, int ht_enabled, int vht_enabled, int sec_channel_offset, int vht_oper_chwidth, int center_segment0, int center_segment1); -int hostapd_set_freq_params(struct hostapd_freq_params *data, - enum hostapd_hw_mode mode, - int freq, int channel, int ht_enabled, - int vht_enabled, int sec_channel_offset, - int vht_oper_chwidth, int center_segment0, - int center_segment1, u32 vht_caps); int hostapd_drv_do_acs(struct hostapd_data *hapd); @@ -335,4 +329,11 @@ static inline int hostapd_drv_vendor_cmd(struct hostapd_data *hapd, data_len, buf); } +static inline int hostapd_drv_stop_ap(struct hostapd_data *hapd) +{ + if (hapd->driver == NULL || hapd->driver->stop_ap == NULL) + return 0; + return hapd->driver->stop_ap(hapd->drv_priv); +} + #endif /* AP_DRV_OPS */ diff --git a/src/ap/beacon.c b/src/ap/beacon.c index b0a74e01..e575b65c 100644 --- a/src/ap/beacon.c +++ b/src/ap/beacon.c @@ -15,6 +15,7 @@ #include "utils/common.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" +#include "common/hw_features_common.h" #include "wps/wps_defs.h" #include "p2p/p2p.h" #include "hostapd.h" @@ -579,6 +580,27 @@ void handle_probe_req(struct hostapd_data *hapd, return; } + /* + * No need to reply if the Probe Request frame was sent on an adjacent + * channel. IEEE Std 802.11-2012 describes this as a requirement for an + * AP with dot11RadioMeasurementActivated set to true, but strictly + * speaking does not allow such ignoring of Probe Request frames if + * dot11RadioMeasurementActivated is false. Anyway, this can help reduce + * number of unnecessary Probe Response frames for cases where the STA + * is less likely to see them (Probe Request frame sent on a + * neighboring, but partially overlapping, channel). + */ + if (elems.ds_params && elems.ds_params_len == 1 && + hapd->iface->current_mode && + (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G || + hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211B) && + hapd->iconf->channel != elems.ds_params[0]) { + wpa_printf(MSG_DEBUG, + "Ignore Probe Request due to DS Params mismatch: chan=%u != ds.chan=%u", + hapd->iconf->channel, elems.ds_params[0]); + return; + } + #ifdef CONFIG_P2P if (hapd->p2p && elems.wps_ie) { struct wpabuf *wps; @@ -986,6 +1008,9 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, params->hessid = hapd->conf->hessid; params->access_network_type = hapd->conf->access_network_type; params->ap_max_inactivity = hapd->conf->ap_max_inactivity; +#ifdef CONFIG_P2P + params->p2p_go_ctwindow = hapd->iconf->p2p_go_ctwindow; +#endif /* CONFIG_P2P */ #ifdef CONFIG_HS20 params->disable_dgaf = hapd->conf->disable_dgaf; if (hapd->conf->osen) { @@ -1034,6 +1059,8 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd) params.beacon_ies = beacon; params.proberesp_ies = proberesp; params.assocresp_ies = assocresp; + params.reenable = hapd->reenable_beacon; + hapd->reenable_beacon = 0; if (iface->current_mode && hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq, diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c index 8c84e3ef..41ab9882 100644 --- a/src/ap/ctrl_iface_ap.c +++ b/src/ap/ctrl_iface_ap.c @@ -537,3 +537,9 @@ int hostapd_parse_csa_settings(const char *pos, return 0; } + + +int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd) +{ + return hostapd_drv_stop_ap(hapd); +} diff --git a/src/ap/ctrl_iface_ap.h b/src/ap/ctrl_iface_ap.h index ee58b4c9..e5297d03 100644 --- a/src/ap/ctrl_iface_ap.h +++ b/src/ap/ctrl_iface_ap.h @@ -23,6 +23,6 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf, size_t buflen); int hostapd_parse_csa_settings(const char *pos, struct csa_settings *settings); - +int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd); #endif /* CTRL_IFACE_AP_H */ diff --git a/src/ap/dfs.c b/src/ap/dfs.c index 0db5ef69..fc8d7adf 100644 --- a/src/ap/dfs.c +++ b/src/ap/dfs.c @@ -11,6 +11,7 @@ #include "utils/common.h" #include "common/ieee802_11_defs.h" +#include "common/hw_features_common.h" #include "common/wpa_ctrl.h" #include "hostapd.h" #include "ap_drv_ops.h" diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c index 40a2a9c7..c39989c3 100644 --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c @@ -1210,9 +1210,21 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, #endif /* NEED_AP_MLME */ case EVENT_INTERFACE_ENABLED: wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_ENABLED); + if (hapd->disabled && hapd->started) { + hapd->disabled = 0; + /* + * Try to re-enable interface if the driver stopped it + * when the interface got disabled. + */ + wpa_auth_reconfig_group_keys(hapd->wpa_auth); + hapd->reenable_beacon = 1; + ieee802_11_set_beacon(hapd); + } break; case EVENT_INTERFACE_DISABLED: + hostapd_free_stas(hapd); wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_DISABLED); + hapd->disabled = 1; break; #ifdef CONFIG_ACS case EVENT_ACS_CHANNEL_SELECTED: diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index b641503c..e641b129 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -82,8 +82,7 @@ static void hostapd_reload_bss(struct hostapd_data *hapd) * Force PSK to be derived again since SSID or passphrase may * have changed. */ - os_free(ssid->wpa_psk); - ssid->wpa_psk = NULL; + hostapd_config_clear_wpa_psk(&hapd->conf->ssid.wpa_psk); } if (hostapd_setup_wpa_psk(hapd->conf)) { wpa_printf(MSG_ERROR, "Failed to re-configure WPA PSK " @@ -357,6 +356,11 @@ static void hostapd_cleanup(struct hostapd_data *hapd) static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface) { wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface); +#ifdef CONFIG_IEEE80211N +#ifdef NEED_AP_MLME + hostapd_stop_setup_timers(iface); +#endif /* NEED_AP_MLME */ +#endif /* CONFIG_IEEE80211N */ hostapd_free_hw_features(iface->hw_features, iface->num_hw_features); iface->hw_features = NULL; os_free(iface->current_rates); diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index 8e2c70ec..75cc24ed 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -105,6 +105,8 @@ struct hostapd_data { struct hostapd_bss_config *conf; int interface_added; /* virtual interface added for this BSS */ unsigned int started:1; + unsigned int disabled:1; + unsigned int reenable_beacon:1; u8 own_addr[ETH_ALEN]; diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c index eebaa3ce..7e75e1a6 100644 --- a/src/ap/sta_info.c +++ b/src/ap/sta_info.c @@ -375,8 +375,9 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) "Station " MACSTR " has lost its driver entry", MAC2STR(sta->addr)); - if (hapd->conf->skip_inactivity_poll) - sta->timeout_next = STA_DISASSOC; + /* Avoid sending client probe on removed client */ + sta->timeout_next = STA_DISASSOC; + goto skip_poll; } else if (inactive_sec < hapd->conf->ap_max_inactivity) { /* station activity detected; reset timeout state */ wpa_msg(hapd->msg_ctx, MSG_DEBUG, @@ -409,6 +410,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) next_time = hapd->conf->ap_max_inactivity; } +skip_poll: if (next_time) { wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout " "for " MACSTR " (%lu seconds)", diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c index 2af2cbce..dc650199 100644 --- a/src/ap/vlan_init.c +++ b/src/ap/vlan_init.c @@ -617,6 +617,7 @@ vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del, struct ifinfomsg *ifi; int attrlen, nlmsg_len, rta_len; struct rtattr *attr; + char ifname[IFNAMSIZ + 1]; if (len < sizeof(*ifi)) return; @@ -631,29 +632,39 @@ vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del, attr = (struct rtattr *) (((char *) ifi) + nlmsg_len); + os_memset(ifname, 0, sizeof(ifname)); rta_len = RTA_ALIGN(sizeof(struct rtattr)); while (RTA_OK(attr, attrlen)) { - char ifname[IFNAMSIZ + 1]; - if (attr->rta_type == IFLA_IFNAME) { int n = attr->rta_len - rta_len; if (n < 0) break; - os_memset(ifname, 0, sizeof(ifname)); - - if ((size_t) n > sizeof(ifname)) - n = sizeof(ifname); + if ((size_t) n >= sizeof(ifname)) + n = sizeof(ifname) - 1; os_memcpy(ifname, ((char *) attr) + rta_len, n); - if (del) - vlan_dellink(ifname, hapd); - else - vlan_newlink(ifname, hapd); } attr = RTA_NEXT(attr, attrlen); } + + if (!ifname[0]) + return; + + wpa_printf(MSG_DEBUG, + "VLAN: RTM_%sLINK: ifi_index=%d ifname=%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)", + del ? "DEL" : "NEW", + ifi->ifi_index, ifname, ifi->ifi_family, ifi->ifi_flags, + (ifi->ifi_flags & IFF_UP) ? "[UP]" : "", + (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "", + (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "", + (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : ""); + + if (del) + vlan_dellink(ifname, hapd); + else + vlan_newlink(ifname, hapd); } @@ -677,7 +688,7 @@ static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx) } h = (struct nlmsghdr *) buf; - while (left >= (int) sizeof(*h)) { + while (NLMSG_OK(h, left)) { int len, plen; len = h->nlmsg_len; @@ -698,9 +709,7 @@ static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx) break; } - len = NLMSG_ALIGN(len); - left -= len; - h = (struct nlmsghdr *) ((char *) h + len); + h = NLMSG_NEXT(h, left); } if (left > 0) { diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index 668cb429..9c5f6094 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -3387,3 +3387,14 @@ int wpa_auth_radius_das_disconnect_pmksa(struct wpa_authenticator *wpa_auth, { return pmksa_cache_auth_radius_das_disconnect(wpa_auth->pmksa, attr); } + + +void wpa_auth_reconfig_group_keys(struct wpa_authenticator *wpa_auth) +{ + struct wpa_group *group; + + if (!wpa_auth) + return; + for (group = wpa_auth->group; group; group = group->next) + wpa_group_config_group_keys(wpa_auth, group); +} diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index b34b84dd..2788e657 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -318,5 +318,6 @@ int wpa_auth_get_ip_addr(struct wpa_state_machine *sm, u8 *addr); struct radius_das_attrs; int wpa_auth_radius_das_disconnect_pmksa(struct wpa_authenticator *wpa_auth, struct radius_das_attrs *attr); +void wpa_auth_reconfig_group_keys(struct wpa_authenticator *wpa_auth); #endif /* WPA_AUTH_H */ diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c index 9ba7aba8..b0e8b0bf 100644 --- a/src/ap/wps_hostapd.c +++ b/src/ap/wps_hostapd.c @@ -362,10 +362,9 @@ static int hapd_wps_reconfig_in_memory(struct hostapd_data *hapd, if (bss->ssid.wpa_passphrase) os_memcpy(bss->ssid.wpa_passphrase, cred->key, cred->key_len); - os_free(bss->ssid.wpa_psk); - bss->ssid.wpa_psk = NULL; + hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk); } else if (cred->key_len == 64) { - os_free(bss->ssid.wpa_psk); + hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk); bss->ssid.wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk)); if (bss->ssid.wpa_psk && diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c index 942380b8..e8babb52 100644 --- a/src/common/hw_features_common.c +++ b/src/common/hw_features_common.c @@ -354,3 +354,85 @@ int check_40mhz_2g4(struct hostapd_hw_modes *mode, return 1; } + + +int hostapd_set_freq_params(struct hostapd_freq_params *data, + enum hostapd_hw_mode mode, + int freq, int channel, int ht_enabled, + int vht_enabled, int sec_channel_offset, + int vht_oper_chwidth, int center_segment0, + int center_segment1, u32 vht_caps) +{ + int 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; + + if (data->vht_enabled) switch (vht_oper_chwidth) { + case VHT_CHANWIDTH_USE_HT: + if (center_segment1) + return -1; + if (center_segment0 != 0 && + 5000 + center_segment0 * 5 != data->center_freq1 && + 2407 + center_segment0 * 5 != data->center_freq1) + return -1; + break; + case VHT_CHANWIDTH_80P80MHZ: + if (!(vht_caps & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) { + wpa_printf(MSG_ERROR, + "80+80 channel width is not supported!"); + return -1; + } + 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 (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ | + VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) { + wpa_printf(MSG_ERROR, + "160MHZ channel width is not supported!"); + return -1; + } + 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; + } + + return 0; +} diff --git a/src/common/hw_features_common.h b/src/common/hw_features_common.h index 046fccde..7f43d00c 100644 --- a/src/common/hw_features_common.h +++ b/src/common/hw_features_common.h @@ -30,5 +30,11 @@ int check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq, int start, int end); int check_40mhz_2g4(struct hostapd_hw_modes *mode, struct wpa_scan_results *scan_res, int pri_chan, int sec_chan); +int hostapd_set_freq_params(struct hostapd_freq_params *data, + enum hostapd_hw_mode mode, + int freq, int channel, int ht_enabled, + int vht_enabled, int sec_channel_offset, + int vht_oper_chwidth, int center_segment0, + int center_segment1, u32 vht_caps); #endif /* HW_FEATURES_COMMON_H */ diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h index ec1be863..cf041938 100644 --- a/src/common/qca-vendor.h +++ b/src/common/qca-vendor.h @@ -1,6 +1,6 @@ /* * Qualcomm Atheros OUI and vendor specific assignments - * Copyright (c) 2014, Qualcomm Atheros, Inc. + * Copyright (c) 2014-2015, Qualcomm Atheros, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -69,6 +69,26 @@ enum qca_radiotap_vendor_ids { * @QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES: Command to get the features * supported by the driver. enum qca_wlan_vendor_features defines * the possible features. + * + * @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED: Event used by driver, + * which supports DFS offloading, to indicate a channel availability check + * start. + * + * @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED: Event used by driver, + * which supports DFS offloading, to indicate a channel availability check + * completion. + * + * @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED: Event used by driver, + * which supports DFS offloading, to indicate that the channel availability + * check aborted, no change to the channel status. + * + * @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED: Event used by + * driver, which supports DFS offloading, to indicate that the + * Non-Occupancy Period for this channel is over, channel becomes usable. + * + * @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED: Event used by driver, + * which supports DFS offloading, to indicate a radar pattern has been + * detected. The channel is now unusable. */ enum qca_nl80211_vendor_subcmds { QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0, @@ -115,6 +135,11 @@ enum qca_nl80211_vendor_subcmds { /* 53 - reserved for QCA */ QCA_NL80211_VENDOR_SUBCMD_DO_ACS = 54, QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES = 55, + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED = 56, + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED = 57, + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED = 58, + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED = 59, + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED = 60, }; @@ -134,6 +159,7 @@ enum qca_wlan_vendor_attr { QCA_WLAN_VENDOR_ATTR_MAC_ADDR = 6, /* used by QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES */ QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS = 7, + QCA_WLAN_VENDOR_ATTR_TEST = 8, /* keep last */ QCA_WLAN_VENDOR_ATTR_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_AFTER_LAST - 1, diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index c8e302a8..1d19fc55 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -127,6 +127,9 @@ extern "C" { #define MESH_GROUP_REMOVED "MESH-GROUP-REMOVED " #define MESH_PEER_CONNECTED "MESH-PEER-CONNECTED " #define MESH_PEER_DISCONNECTED "MESH-PEER-DISCONNECTED " +/** Mesh SAE authentication failure. Wrong password suspected. */ +#define MESH_SAE_AUTH_FAILURE "MESH-SAE-AUTH-FAILURE " +#define MESH_SAE_AUTH_BLOCKED "MESH-SAE-AUTH-BLOCKED " /* WMM AC events */ #define WMM_AC_EVENT_TSPEC_ADDED "TSPEC-ADDED " @@ -173,6 +176,8 @@ extern "C" { #define P2P_EVENT_NFC_BOTH_GO "P2P-NFC-BOTH-GO " #define P2P_EVENT_NFC_PEER_CLIENT "P2P-NFC-PEER-CLIENT " #define P2P_EVENT_NFC_WHILE_CLIENT "P2P-NFC-WHILE-CLIENT " +#define P2P_EVENT_FALLBACK_TO_GO_NEG "P2P-FALLBACK-TO-GO-NEG " +#define P2P_EVENT_FALLBACK_TO_GO_NEG_ENABLED "P2P-FALLBACK-TO-GO-NEG-ENABLED " /* parameters: <PMF enabled> <timeout in ms> <Session Information URL> */ #define ESS_DISASSOC_IMMINENT "ESS-DISASSOC-IMMINENT " @@ -269,6 +274,8 @@ extern "C" { #define WPA_BSS_MASK_WIFI_DISPLAY BIT(16) #define WPA_BSS_MASK_DELIM BIT(17) #define WPA_BSS_MASK_MESH_SCAN BIT(18) +#define WPA_BSS_MASK_SNR BIT(19) +#define WPA_BSS_MASK_EST_THROUGHPUT BIT(20) /* VENDOR_ELEM_* frame id values */ diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c index d8c8c56b..46c4a461 100644 --- a/src/crypto/tls_openssl.c +++ b/src/crypto/tls_openssl.c @@ -3153,7 +3153,7 @@ static int ocsp_resp_cb(SSL *s, void *arg) if (X509_STORE_add_cert(store, conn->peer_issuer) != 1) { tls_show_errors(MSG_INFO, __func__, - "OpenSSL: Could not add issuer to certificate store\n"); + "OpenSSL: Could not add issuer to certificate store"); } certs = sk_X509_new_null(); if (certs) { @@ -3162,17 +3162,17 @@ static int ocsp_resp_cb(SSL *s, void *arg) if (cert && !sk_X509_push(certs, cert)) { tls_show_errors( MSG_INFO, __func__, - "OpenSSL: Could not add issuer to OCSP responder trust store\n"); + "OpenSSL: Could not add issuer to OCSP responder trust store"); X509_free(cert); sk_X509_free(certs); certs = NULL; } - if (conn->peer_issuer_issuer) { + if (certs && conn->peer_issuer_issuer) { cert = X509_dup(conn->peer_issuer_issuer); if (cert && !sk_X509_push(certs, cert)) { tls_show_errors( MSG_INFO, __func__, - "OpenSSL: Could not add issuer to OCSP responder trust store\n"); + "OpenSSL: Could not add issuer's issuer to OCSP responder trust store"); X509_free(cert); } } diff --git a/src/drivers/driver.h b/src/drivers/driver.h index c9e860f8..d35309af 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -213,6 +213,9 @@ struct hostapd_hw_modes { * @tsf: Timestamp * @age: Age of the information in milliseconds (i.e., how many milliseconds * ago the last Beacon or Probe Response frame was received) + * @est_throughput: Estimated throughput in kbps (this is calculated during + * scan result processing if left zero by the driver wrapper) + * @snr: Signal-to-noise ratio in dB (calculated during scan result processing) * @ie_len: length of the following IE field in octets * @beacon_ie_len: length of the following Beacon IE field in octets * @@ -241,6 +244,8 @@ struct wpa_scan_res { int level; u64 tsf; unsigned int age; + unsigned int est_throughput; + int snr; size_t ie_len; size_t beacon_ie_len; /* Followed by ie_len + beacon_ie_len octets of IE data */ @@ -767,6 +772,14 @@ struct wpa_driver_associate_params { int fixed_bssid; /** + * fixed_freq - Fix control channel in IBSS mode + * 0 = don't fix control channel (default) + * 1 = fix control channel; this prevents IBSS merging with another + * channel + */ + int fixed_freq; + + /** * disable_ht - Disable HT (IEEE 802.11n) for this connection */ int disable_ht; @@ -1010,6 +1023,11 @@ struct wpa_driver_ap_params { int ap_max_inactivity; /** + * ctwindow - Client Traffic Window (in TUs) + */ + u8 p2p_go_ctwindow; + + /** * smps_mode - SMPS mode * * SMPS mode to be used by the AP, specified as the relevant bits of @@ -1031,6 +1049,11 @@ struct wpa_driver_ap_params { * freq - Channel parameters for dynamic bandwidth changes */ struct hostapd_freq_params *freq; + + /** + * reenable - Whether this is to re-enable beaconing + */ + int reenable; }; struct wpa_driver_mesh_bss_params { @@ -1186,6 +1209,8 @@ struct wpa_driver_capa { #define WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH 0x0000000800000000ULL /** Driver supports IBSS with HT datarates */ #define WPA_DRIVER_FLAGS_HT_IBSS 0x0000001000000000ULL +/** Driver supports IBSS with VHT datarates */ +#define WPA_DRIVER_FLAGS_VHT_IBSS 0x0000002000000000ULL u64 flags; #define WPA_DRIVER_SMPS_MODE_STATIC 0x00000001 @@ -3758,7 +3783,7 @@ enum wpa_event_type { EVENT_CONNECT_FAILED_REASON, /** - * EVENT_RADAR_DETECTED - Notify of radar detection + * EVENT_DFS_RADAR_DETECTED - Notify of radar detection * * A radar has been detected on the supplied frequency, hostapd should * react accordingly (e.g., change channel). @@ -3766,14 +3791,14 @@ enum wpa_event_type { EVENT_DFS_RADAR_DETECTED, /** - * EVENT_CAC_FINISHED - Notify that channel availability check has been completed + * EVENT_DFS_CAC_FINISHED - Notify that channel availability check has been completed * * After a successful CAC, the channel can be marked clear and used. */ EVENT_DFS_CAC_FINISHED, /** - * EVENT_CAC_ABORTED - Notify that channel availability check has been aborted + * EVENT_DFS_CAC_ABORTED - Notify that channel availability check has been aborted * * The CAC was not successful, and the channel remains in the previous * state. This may happen due to a radar beeing detected or other @@ -3782,7 +3807,7 @@ enum wpa_event_type { EVENT_DFS_CAC_ABORTED, /** - * EVENT_DFS_CAC_NOP_FINISHED - Notify that non-occupancy period is over + * EVENT_DFS_NOP_FINISHED - Notify that non-occupancy period is over * * The channel which was previously unavailable is now available again. */ @@ -3831,6 +3856,15 @@ enum wpa_event_type { * in device. */ EVENT_ACS_CHANNEL_SELECTED, + + /** + * EVENT_DFS_CAC_STARTED - Notify that channel availability check has + * been started. + * + * This event indicates that channel availability check has been started + * on a DFS frequency by a driver that supports DFS Offload. + */ + EVENT_DFS_CAC_STARTED, }; diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c index f897c114..aebea8cf 100644 --- a/src/drivers/driver_common.c +++ b/src/drivers/driver_common.c @@ -79,6 +79,7 @@ const char * event_to_string(enum wpa_event_type event) E2S(AVOID_FREQUENCIES); E2S(NEW_PEER_CANDIDATE); E2S(ACS_CHANNEL_SELECTED); + E2S(DFS_CAC_STARTED); } return "UNKNOWN"; diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index d681ea63..2dce242a 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -164,6 +164,7 @@ static void nl80211_destroy_eloop_handle(struct nl_handle **handle) static void nl80211_global_deinit(void *priv); +static void nl80211_check_global(struct nl80211_global *global); static void wpa_driver_nl80211_deinit(struct i802_bss *bss); static int wpa_driver_nl80211_set_mode_ibss(struct i802_bss *bss, @@ -864,6 +865,7 @@ static int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv, return 1; if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) { + nl80211_check_global(drv->global); wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed " "interface"); wpa_driver_nl80211_finish_drv_init(drv, NULL, 0, NULL); @@ -952,16 +954,21 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx, (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : ""); if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) { + namebuf[0] = '\0'; if (if_indextoname(ifi->ifi_index, namebuf) && - linux_iface_up(drv->global->ioctl_sock, - drv->first_bss->ifname) > 0) { + linux_iface_up(drv->global->ioctl_sock, namebuf) > 0) { wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down " "event since interface %s is up", namebuf); drv->ignore_if_down_event = 0; return; } - wpa_printf(MSG_DEBUG, "nl80211: Interface down"); - if (drv->ignore_if_down_event) { + wpa_printf(MSG_DEBUG, "nl80211: Interface down (%s/%s)", + namebuf, ifname); + if (os_strcmp(drv->first_bss->ifname, ifname) != 0) { + wpa_printf(MSG_DEBUG, + "nl80211: Not the main interface (%s) - do not indicate interface down", + drv->first_bss->ifname); + } else if (drv->ignore_if_down_event) { wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down " "event generated by mode change"); drv->ignore_if_down_event = 0; @@ -984,8 +991,7 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx, if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) { if (if_indextoname(ifi->ifi_index, namebuf) && - linux_iface_up(drv->global->ioctl_sock, - drv->first_bss->ifname) == 0) { + linux_iface_up(drv->global->ioctl_sock, namebuf) == 0) { wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up " "event since interface %s is down", namebuf); @@ -1477,6 +1483,33 @@ err: } +static void nl80211_check_global(struct nl80211_global *global) +{ + struct nl_handle *handle; + const char *groups[] = { "scan", "mlme", "regulatory", "vendor", NULL }; + int ret; + unsigned int i; + + /* + * Try to re-add memberships to handle case of cfg80211 getting reloaded + * and all registration having been cleared. + */ + handle = (void *) (((intptr_t) global->nl_event) ^ + ELOOP_SOCKET_INVALID); + + for (i = 0; groups[i]; i++) { + ret = nl_get_multicast_id(global, "nl80211", groups[i]); + if (ret >= 0) + ret = nl_socket_add_membership(handle, ret); + if (ret < 0) { + wpa_printf(MSG_INFO, + "nl80211: Could not re-add multicast membership for %s events: %d (%s)", + groups[i], ret, strerror(-ret)); + } + } +} + + static void wpa_driver_nl80211_rfkill_blocked(void *ctx) { wpa_printf(MSG_DEBUG, "nl80211: RFKILL blocked"); @@ -1670,6 +1703,7 @@ static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname, } if (drv->global) { + nl80211_check_global(drv->global); dl_list_add(&drv->global->interfaces, &drv->list); drv->in_interface_list = 1; } @@ -2065,6 +2099,60 @@ static int i802_set_iface_flags(struct i802_bss *bss, int up) } +#ifdef CONFIG_TESTING_OPTIONS +static int qca_vendor_test_cmd_handler(struct nl_msg *msg, void *arg) +{ + /* struct wpa_driver_nl80211_data *drv = arg; */ + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + + + wpa_printf(MSG_DEBUG, + "nl80211: QCA vendor test command response received"); + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + if (!tb[NL80211_ATTR_VENDOR_DATA]) { + wpa_printf(MSG_DEBUG, "nl80211: No vendor data attribute"); + return NL_SKIP; + } + + wpa_hexdump(MSG_DEBUG, + "nl80211: Received QCA vendor test command response", + nla_data(tb[NL80211_ATTR_VENDOR_DATA]), + nla_len(tb[NL80211_ATTR_VENDOR_DATA])); + + return NL_SKIP; +} +#endif /* CONFIG_TESTING_OPTIONS */ + + +static void qca_vendor_test(struct wpa_driver_nl80211_data *drv) +{ +#ifdef CONFIG_TESTING_OPTIONS + struct nl_msg *msg; + struct nlattr *params; + int ret; + + if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) || + nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) || + nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, + QCA_NL80211_VENDOR_SUBCMD_TEST) || + !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) || + nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_TEST, 123)) { + nlmsg_free(msg); + return; + } + nla_nest_end(msg, params); + + ret = send_and_recv_msgs(drv, msg, qca_vendor_test_cmd_handler, drv); + wpa_printf(MSG_DEBUG, + "nl80211: QCA vendor test command returned %d (%s)", + ret, strerror(-ret)); +#endif /* CONFIG_TESTING_OPTIONS */ +} + + static int wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv, const u8 *set_addr, int first, @@ -2151,6 +2239,9 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv, drv, drv->ctx); } + if (drv->vendor_cmd_test_avail) + qca_vendor_test(drv); + return 0; } @@ -3213,7 +3304,7 @@ static int wpa_driver_nl80211_set_ap(void *priv, u32 suites[10], suite; u32 ver; - beacon_set = bss->beacon_set; + beacon_set = params->reenable ? 0 : bss->beacon_set; wpa_printf(MSG_DEBUG, "nl80211: Set beacon (beacon_set=%d)", beacon_set); @@ -3378,6 +3469,21 @@ static int wpa_driver_nl80211_set_ap(void *priv, goto fail; } +#ifdef CONFIG_P2P + if (params->p2p_go_ctwindow > 0) { + if (drv->p2p_go_ctwindow_supported) { + wpa_printf(MSG_DEBUG, "nl80211: P2P GO ctwindow=%d", + params->p2p_go_ctwindow); + if (nla_put_u8(msg, NL80211_ATTR_P2P_CTWINDOW, + params->p2p_go_ctwindow)) + goto fail; + } else { + wpa_printf(MSG_INFO, + "nl80211: Driver does not support CTWindow configuration - ignore this parameter"); + } + } +#endif /* CONFIG_P2P */ + ret = send_and_recv_msgs(drv, msg, NULL, NULL); if (ret) { wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)", @@ -4317,6 +4423,12 @@ retry: goto fail; } + if (params->fixed_freq) { + wpa_printf(MSG_DEBUG, " * fixed_freq"); + if (nla_put_flag(msg, NL80211_ATTR_FREQ_FIXED)) + goto fail; + } + if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X || params->key_mgmt_suite == WPA_KEY_MGMT_PSK || params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 || @@ -6867,6 +6979,7 @@ static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr, struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; struct nl_msg *msg; + int ret; if (!drv->poll_command_supported) { nl80211_send_null_frame(bss, own_addr, addr, qos); @@ -6879,7 +6992,12 @@ static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr, return; } - send_and_recv_msgs(drv, msg, NULL, NULL); + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + if (ret < 0) { + wpa_printf(MSG_DEBUG, "nl80211: Client probe request for " + MACSTR " failed: ret=%d (%s)", + MAC2STR(addr), ret, strerror(-ret)); + } } @@ -7849,16 +7967,13 @@ static int nl80211_put_mesh_id(struct nl_msg *msg, const u8 *mesh_id, } -static int -wpa_driver_nl80211_join_mesh(void *priv, +static int nl80211_join_mesh(struct i802_bss *bss, struct wpa_driver_mesh_join_params *params) { - struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; struct nl_msg *msg; struct nlattr *container; int ret = -1; - u32 timeout; wpa_printf(MSG_DEBUG, "nl80211: mesh join (ifindex=%d)", drv->ifindex); msg = nl80211_drv_msg(drv, 0, NL80211_CMD_JOIN_MESH); @@ -7910,14 +8025,9 @@ wpa_driver_nl80211_join_mesh(void *priv, /* * Set NL80211_MESHCONF_PLINK_TIMEOUT even if user mpm is used because * the timer could disconnect stations even in that case. - * - * Set 0xffffffff instead of 0 because NL80211_MESHCONF_PLINK_TIMEOUT - * does not allow 0. */ - timeout = params->conf.peer_link_timeout; - if ((params->flags & WPA_DRIVER_MESH_FLAG_USER_MPM) || timeout == 0) - timeout = 0xffffffff; - if (nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT, timeout)) { + if (nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT, + params->conf.peer_link_timeout)) { wpa_printf(MSG_ERROR, "nl80211: Failed to set PLINK_TIMEOUT"); goto fail; } @@ -7941,6 +8051,37 @@ fail: } +static int +wpa_driver_nl80211_join_mesh(void *priv, + struct wpa_driver_mesh_join_params *params) +{ + struct i802_bss *bss = priv; + int ret, timeout; + + timeout = params->conf.peer_link_timeout; + + /* Disable kernel inactivity timer */ + if (params->flags & WPA_DRIVER_MESH_FLAG_USER_MPM) + params->conf.peer_link_timeout = 0; + + ret = nl80211_join_mesh(bss, params); + if (ret == -EINVAL && params->conf.peer_link_timeout == 0) { + wpa_printf(MSG_DEBUG, + "nl80211: Mesh join retry for peer_link_timeout"); + /* + * Old kernel does not support setting + * NL80211_MESHCONF_PLINK_TIMEOUT to zero, so set 60 seconds + * into future from peer_link_timeout. + */ + params->conf.peer_link_timeout = timeout + 60; + ret = nl80211_join_mesh(priv, params); + } + + params->conf.peer_link_timeout = timeout; + return ret; +} + + static int wpa_driver_nl80211_leave_mesh(void *priv) { struct i802_bss *bss = priv; diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h index 4567f422..802589aa 100644 --- a/src/drivers/driver_nl80211.h +++ b/src/drivers/driver_nl80211.h @@ -136,6 +136,7 @@ struct wpa_driver_nl80211_data { unsigned int start_iface_up:1; unsigned int test_use_roc_tx:1; unsigned int ignore_deauth_event:1; + unsigned int vendor_cmd_test_avail:1; unsigned int roaming_vendor_cmd_avail:1; unsigned int dfs_vendor_cmd_avail:1; unsigned int have_low_prio_scan:1; @@ -143,6 +144,7 @@ struct wpa_driver_nl80211_data { unsigned int addr_changed:1; unsigned int get_features_vendor_cmd_avail:1; unsigned int set_rekey_offload:1; + unsigned int p2p_go_ctwindow_supported:1; u64 remain_on_chan_cookie; u64 send_action_cookie; diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c index 36c8ce2b..e0d1d233 100644 --- a/src/drivers/driver_nl80211_capa.c +++ b/src/drivers/driver_nl80211_capa.c @@ -71,6 +71,7 @@ struct wiphy_info_data { unsigned int connect_supported:1; unsigned int p2p_go_supported:1; unsigned int p2p_client_supported:1; + unsigned int p2p_go_ctwindow_supported:1; unsigned int p2p_concurrent:1; unsigned int channel_switch_supported:1; unsigned int set_qos_map_supported:1; @@ -365,6 +366,9 @@ static void wiphy_info_feature_flags(struct wiphy_info_data *info, capa->flags |= WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH; } + if (flags & NL80211_FEATURE_P2P_GO_CTWIN) + info->p2p_go_ctwindow_supported = 1; + if (flags & NL80211_FEATURE_LOW_PRIORITY_SCAN) info->have_low_prio_scan = 1; @@ -544,6 +548,9 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) } vinfo = nla_data(nl); switch (vinfo->subcmd) { + case QCA_NL80211_VENDOR_SUBCMD_TEST: + drv->vendor_cmd_test_avail = 1; + break; case QCA_NL80211_VENDOR_SUBCMD_ROAMING: drv->roaming_vendor_cmd_avail = 1; break; @@ -824,6 +831,7 @@ int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv) drv->device_ap_sme = info.device_ap_sme; drv->poll_command_supported = info.poll_command_supported; drv->data_tx_status = info.data_tx_status; + drv->p2p_go_ctwindow_supported = info.p2p_go_ctwindow_supported; if (info.set_qos_map_supported) drv->capa.flags |= WPA_DRIVER_FLAGS_QOS_MAPPING; drv->have_low_prio_scan = info.have_low_prio_scan; diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c index d5550339..6a7b509e 100644 --- a/src/drivers/driver_nl80211_event.c +++ b/src/drivers/driver_nl80211_event.c @@ -1535,6 +1535,9 @@ static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv, u32 subcmd, u8 *data, size_t len) { switch (subcmd) { + case QCA_NL80211_VENDOR_SUBCMD_TEST: + wpa_hexdump(MSG_DEBUG, "nl80211: QCA test event", data, len); + break; case QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY: qca_nl80211_avoid_freq(drv, data, len); break; diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak index ab392bca..94340787 100644 --- a/src/drivers/drivers.mak +++ b/src/drivers/drivers.mak @@ -39,7 +39,13 @@ NEED_RFKILL=y ifdef CONFIG_LIBNL32 DRV_LIBS += -lnl-3 DRV_LIBS += -lnl-genl-3 - DRV_CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3 + DRV_CFLAGS += -DCONFIG_LIBNL20 + ifdef LIBNL_INC + DRV_CFLAGS += -I$(LIBNL_INC) + else + PKG_CONFIG ?= pkg-config + DRV_CFLAGS += $(shell $(PKG_CONFIG) --cflags libnl-3.0) + endif ifdef CONFIG_LIBNL3_ROUTE DRV_LIBS += -lnl-route-3 DRV_CFLAGS += -DCONFIG_LIBNL3_ROUTE diff --git a/src/l2_packet/l2_packet_linux.c b/src/l2_packet/l2_packet_linux.c index 68b20089..41de2f85 100644 --- a/src/l2_packet/l2_packet_linux.c +++ b/src/l2_packet/l2_packet_linux.c @@ -14,6 +14,8 @@ #include "common.h" #include "eloop.h" +#include "crypto/sha1.h" +#include "crypto/crypto.h" #include "l2_packet.h" @@ -30,6 +32,9 @@ struct l2_packet_data { /* For working around Linux packet socket behavior and regression. */ int fd_br_rx; + int last_from_br; + u8 last_hash[SHA1_MAC_LEN]; + unsigned int num_rx, num_rx_br; }; /* Generated by 'sudo tcpdump -s 3000 -dd greater 278 and ip and udp and @@ -122,6 +127,7 @@ static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx) struct sockaddr_ll ll; socklen_t fromlen; + l2->num_rx++; os_memset(&ll, 0, sizeof(ll)); fromlen = sizeof(ll); res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &ll, @@ -132,15 +138,42 @@ static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx) return; } - l2->rx_callback(l2->rx_callback_ctx, ll.sll_addr, buf, res); + wpa_printf(MSG_DEBUG, "%s: src=" MACSTR " len=%d", + __func__, MAC2STR(ll.sll_addr), (int) res); if (l2->fd_br_rx >= 0) { - wpa_printf(MSG_DEBUG, "l2_packet_receive: Main packet socket for %s seems to have working RX - close workaround bridge socket", - l2->ifname); - eloop_unregister_read_sock(l2->fd_br_rx); - close(l2->fd_br_rx); - l2->fd_br_rx = -1; + u8 hash[SHA1_MAC_LEN]; + const u8 *addr[1]; + size_t len[1]; + + /* + * Close the workaround socket if the kernel version seems to be + * able to deliver packets through the packet socket before + * authorization has been completed (in dormant state). + */ + if (l2->num_rx_br <= 1) { + wpa_printf(MSG_DEBUG, + "l2_packet_receive: Main packet socket for %s seems to have working RX - close workaround bridge socket", + l2->ifname); + eloop_unregister_read_sock(l2->fd_br_rx); + close(l2->fd_br_rx); + l2->fd_br_rx = -1; + } + + addr[0] = buf; + len[0] = res; + sha1_vector(1, addr, len, hash); + if (l2->last_from_br && + os_memcmp(hash, l2->last_hash, SHA1_MAC_LEN) == 0) { + wpa_printf(MSG_DEBUG, "%s: Drop duplicate RX", + __func__); + return; + } + os_memcpy(l2->last_hash, hash, SHA1_MAC_LEN); } + + l2->last_from_br = 0; + l2->rx_callback(l2->rx_callback_ctx, ll.sll_addr, buf, res); } @@ -151,7 +184,11 @@ static void l2_packet_receive_br(int sock, void *eloop_ctx, void *sock_ctx) int res; struct sockaddr_ll ll; socklen_t fromlen; + u8 hash[SHA1_MAC_LEN]; + const u8 *addr[1]; + size_t len[1]; + l2->num_rx_br++; os_memset(&ll, 0, sizeof(ll)); fromlen = sizeof(ll); res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &ll, @@ -162,6 +199,19 @@ static void l2_packet_receive_br(int sock, void *eloop_ctx, void *sock_ctx) return; } + wpa_printf(MSG_DEBUG, "%s: src=" MACSTR " len=%d", + __func__, MAC2STR(ll.sll_addr), (int) res); + + addr[0] = buf; + len[0] = res; + sha1_vector(1, addr, len, hash); + if (!l2->last_from_br && + os_memcmp(hash, l2->last_hash, SHA1_MAC_LEN) == 0) { + wpa_printf(MSG_DEBUG, "%s: Drop duplicate RX", __func__); + return; + } + l2->last_from_br = 1; + os_memcpy(l2->last_hash, hash, SHA1_MAC_LEN); l2->rx_callback(l2->rx_callback_ctx, ll.sll_addr, buf, res); } diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index 602aa366..d9f97ed2 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -1279,6 +1279,7 @@ void p2p_stop_find_for_freq(struct p2p_data *p2p, int freq) p2p->sd_peer = NULL; p2p->invite_peer = NULL; p2p_stop_listen_for_freq(p2p, freq); + p2p->send_action_in_progress = 0; } diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c index 10413edc..c1d77491 100644 --- a/src/rsn_supp/tdls.c +++ b/src/rsn_supp/tdls.c @@ -939,10 +939,15 @@ static int wpa_tdls_recv_teardown(struct wpa_sm *sm, const u8 *src_addr, " (reason code %u)", MAC2STR(src_addr), reason_code); ielen = len - (pos - buf); /* start of IE in buf */ - if (wpa_supplicant_parse_ies((const u8 *) pos, ielen, &kde) < 0) { - wpa_printf(MSG_INFO, "TDLS: Failed to parse IEs in Teardown"); - return -1; - } + + /* + * Don't reject the message if failing to parse IEs. The IEs we need are + * explicitly checked below. Some APs may add arbitrary padding to the + * end of short TDLS frames and that would look like invalid IEs. + */ + if (wpa_supplicant_parse_ies((const u8 *) pos, ielen, &kde) < 0) + wpa_printf(MSG_DEBUG, + "TDLS: Failed to parse IEs in Teardown - ignore as an interop workaround"); if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) { wpa_printf(MSG_INFO, "TDLS: No Link Identifier IE in TDLS " @@ -1823,10 +1828,15 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr, cpos += 2; ielen = len - (cpos - buf); /* start of IE in buf */ - if (wpa_supplicant_parse_ies(cpos, ielen, &kde) < 0) { - wpa_printf(MSG_INFO, "TDLS: Failed to parse IEs in TPK M1"); - goto error; - } + + /* + * Don't reject the message if failing to parse IEs. The IEs we need are + * explicitly checked below. Some APs may add arbitrary padding to the + * end of short TDLS frames and that would look like invalid IEs. + */ + if (wpa_supplicant_parse_ies(cpos, ielen, &kde) < 0) + wpa_printf(MSG_DEBUG, + "TDLS: Failed to parse IEs in TPK M1 - ignore as an interop workaround"); if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) { wpa_printf(MSG_INFO, "TDLS: No valid Link Identifier IE in " @@ -2199,10 +2209,15 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr, pos += 2; ielen = len - (pos - buf); /* start of IE in buf */ - if (wpa_supplicant_parse_ies(pos, ielen, &kde) < 0) { - wpa_printf(MSG_INFO, "TDLS: Failed to parse IEs in TPK M2"); - goto error; - } + + /* + * Don't reject the message if failing to parse IEs. The IEs we need are + * explicitly checked below. Some APs may add arbitrary padding to the + * end of short TDLS frames and that would look like invalid IEs. + */ + if (wpa_supplicant_parse_ies(pos, ielen, &kde) < 0) + wpa_printf(MSG_DEBUG, + "TDLS: Failed to parse IEs in TPK M2 - ignore as an interop workaround"); #ifdef CONFIG_TDLS_TESTING if (tdls_testing & TDLS_TESTING_DECLINE_RESP) { diff --git a/src/utils/http_curl.c b/src/utils/http_curl.c index 0c18269d..b38cf796 100644 --- a/src/utils/http_curl.c +++ b/src/utils/http_curl.c @@ -1084,7 +1084,7 @@ static int ocsp_resp_cb(SSL *s, void *arg) if (X509_STORE_add_cert(store, ctx->peer_issuer) != 1) { tls_show_errors(__func__, - "OpenSSL: Could not add issuer to certificate store\n"); + "OpenSSL: Could not add issuer to certificate store"); } certs = sk_X509_new_null(); if (certs) { @@ -1093,17 +1093,17 @@ static int ocsp_resp_cb(SSL *s, void *arg) if (cert && !sk_X509_push(certs, cert)) { tls_show_errors( __func__, - "OpenSSL: Could not add issuer to OCSP responder trust store\n"); + "OpenSSL: Could not add issuer to OCSP responder trust store"); X509_free(cert); sk_X509_free(certs); certs = NULL; } - if (ctx->peer_issuer_issuer) { + if (certs && ctx->peer_issuer_issuer) { cert = X509_dup(ctx->peer_issuer_issuer); if (cert && !sk_X509_push(certs, cert)) { tls_show_errors( __func__, - "OpenSSL: Could not add issuer to OCSP responder trust store\n"); + "OpenSSL: Could not add issuer's issuer to OCSP responder trust store"); X509_free(cert); } } diff --git a/src/utils/list.h b/src/utils/list.h index 68811309..ee2f4856 100644 --- a/src/utils/list.h +++ b/src/utils/list.h @@ -17,6 +17,8 @@ struct dl_list { struct dl_list *prev; }; +#define DL_LIST_HEAD_INIT(l) { &(l), &(l) } + static inline void dl_list_init(struct dl_list *list) { list->next = list; diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c index 86fbd0ae..e0c1125d 100644 --- a/src/utils/os_unix.c +++ b/src/utils/os_unix.c @@ -26,7 +26,7 @@ #include "trace.h" #include "list.h" -static struct dl_list alloc_list; +static struct dl_list alloc_list = DL_LIST_HEAD_INIT(alloc_list); #define ALLOC_MAGIC 0xa84ef1b2 #define FREED_MAGIC 0x67fd487a @@ -321,9 +321,6 @@ int os_program_init(void) capset(&header, &cap); #endif /* ANDROID */ -#ifdef WPA_TRACE - dl_list_init(&alloc_list); -#endif /* WPA_TRACE */ return 0; } diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index 95fbe789..0f82af9d 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -105,6 +105,7 @@ OBJS += ../src/utils/trace.o OBJS_p += ../src/utils/trace.o OBJS_c += ../src/utils/trace.o OBJS_priv += ../src/utils/trace.o +LIBCTRL += ../src/utils/trace.o LDFLAGS += -rdynamic CFLAGS += -funwind-tables ifdef CONFIG_WPA_TRACE_BFD @@ -1636,6 +1637,15 @@ wpa_cli: $(OBJS_c) $(Q)$(LDO) $(LDFLAGS) -o wpa_cli $(OBJS_c) $(LIBS_c) @$(E) " LD " $@ +LIBCTRL += ../src/common/wpa_ctrl.o +LIBCTRL += ../src/utils/os_$(CONFIG_OS).o +LIBCTRL += ../src/utils/wpa_debug.o + +libwpa_ctrl.a: $(LIBCTRL) + $(Q)rm -f $@ + $(Q)$(AR) crs $@ $? + @$(E) " AR " $@ + link_test: $(OBJS) $(OBJS_h) tests/link_test.o $(Q)$(LDO) $(LDFLAGS) -o link_test $(OBJS) $(OBJS_h) tests/link_test.o $(LIBS) @$(E) " LD " $@ @@ -1755,5 +1765,6 @@ clean: rm -f nfc_pw_token rm -f lcov.info rm -rf lcov-html + rm -f libwpa_ctrl.a -include $(OBJS:%.o=%.d) diff --git a/wpa_supplicant/README-P2P b/wpa_supplicant/README-P2P index 5c1e4f92..a1d96fb5 100644 --- a/wpa_supplicant/README-P2P +++ b/wpa_supplicant/README-P2P @@ -73,7 +73,7 @@ Device Discovery p2p_find [timeout in seconds] [type=<social|progressive>] \ [dev_id=<addr>] [dev_type=<device type>] \ - [delay=<search delay in ms>] + [delay=<search delay in ms>] [seek=<service name>] The default behavior is to run a single full scan in the beginning and then scan only social channels. type=social will scan only social @@ -92,6 +92,24 @@ The optional dev_type option can be used to specify a single device type (primary or secondary) to search for, e.g., "p2p_find dev_type=1-0050F204-1". + +With one or more seek arguments, the command sends Probe Request frames +for a P2PS service. For example, +p2p_find 5 dev_id=11:22:33:44:55:66 seek=alt.example.chat seek=alt.example.video + +Parameters description: + Timeout - Optional ASCII base-10-encoded u16. If missing, request will not + time out and must be canceled manually + dev_id - Optional to request responses from a single known remote device + Service Name - Mandatory UTF-8 string for ASP seeks + Service name must match the remote service being advertised exactly + (no prefix matching). + Service name may be empty, in which case all ASP services will be + returned, and may be filtered with p2p_serv_disc_req settings, and + p2p_serv_asp_resp results. + Multiple service names may be requested, but if it exceeds internal + limit, it will automatically revert to requesting all ASP services. + p2p_listen [timeout in seconds] Start Listen-only state (become discoverable without searching for @@ -128,9 +146,9 @@ parameter can be used to request wpa_supplicant to automatically figure out whether the peer device is operating as a GO and if so, use join-a-group style PD instead of GO Negotiation style PD. -p2p_connect <peer device address> <pbc|pin|PIN#> [display|keypad] +p2p_connect <peer device address> <pbc|pin|PIN#|p2ps> [display|keypad|p2ps] [persistent|persistent=<network id>] [join|auth] - [go_intent=<0..15>] [freq=<in MHz>] [ht40] [vht] [provdisc] + [go_intent=<0..15>] [freq=<in MHz>] [ht40] [vht] [provdisc] [auto] Start P2P group formation with a discovered P2P peer. This includes optional group owner negotiation, group interface setup, provisioning, @@ -171,6 +189,69 @@ used prior to starting GO Negotiation as a workaround with some deployed P2P implementations that require this to allow the user to accept the connection. +"auto" can be used to request wpa_supplicant to automatically figure +out whether the peer device is operating as a GO and if so, use +join-a-group operation rather than GO Negotiation. + +P2PS attribute changes to p2p_connect command: + +P2PS supports two WPS provisioning methods namely PIN method and P2PS default. +The remaining paramters hold same role as in legacy P2P. In case of P2PS default +config method "p2ps" keyword is added in p2p_connect command. + +For example: +p2p_connect 02:0a:f5:85:11:00 12345670 p2ps persistent join + (WPS Method = P2PS default) + +p2p_connect 02:0a:f5:85:11:00 45629034 keypad persistent + (WPS Method = PIN) + +p2p_asp_provision <peer MAC address> <adv_id=peer adv id> + <adv_mac=peer MAC address> [role=2|4|1] <session=session id> + <session_mac=initiator mac address> + [info='service info'] <method=Default|keypad|Display> + +This command starts provision discovery with the P2PS enabled peer device. + +For example, +p2p_asp_provision 00:11:22:33:44:55 adv_id=4d6fc7 adv_mac=00:55:44:33:22:11 role=1 session=12ab34 session_mac=00:11:22:33:44:55 info='name=john' method=1000 + +Parameter description: + MAC address - Mandatory + adv_id - Mandatory remote Advertising ID of service connection is being + established for + adv_mac - Mandatory MAC address that owns/registered the service + role - Optional + 2 (group client only) or 4 (group owner only) + if not present (or 1) role is negotiated by the two peers. + session - Mandatory Session ID of the first session to be established + session_mac - Mandatory MAC address that owns/initiated the session + method - Optional method to request for provisioning (1000 - P2PS Default, + 100 - Keypad(PIN), 8 - Display(PIN)) + info - Optional UTF-8 string. Hint for service to indicate possible usage + parameters - Escape single quote & backslash: + with a backslash 0x27 == ' == \', and 0x5c == \ == \\ + +p2p_asp_provision_resp <peer mac address> <adv_id= local adv id> + <adv_mac=local MAC address> <role=1|2|4> <status=0> + <session=session id> <session_mac=peer MAC address> + +This command sends a provision discovery response from responder side. + +For example, +p2p_asp_provision_resp 00:55:44:33:22:11 adv_id=4d6fc7 adv_mac=00:55:44:33:22:11 role=1 status=0 session=12ab34 session_mac=00:11:22:33:44:55 + +Parameters definition: + MAC address - Mandatory + adv_id - Mandatory local Advertising ID of service connection is being + established for + adv_mac - Mandatory MAC address that owns/registered the service + role - Optional 2 (group client only) or 4 (group owner only) + if not present (or 1) role is negotiated by the two peers. + status - Mandatory Acceptance/Rejection code of Provisioning + session - Mandatory Session ID of the first session to be established + session_mac - Mandatory MAC address that owns/initiated the session + p2p_group_add [persistent|persistent=<network id>] [freq=<freq in MHz>] [ht40] [vht] @@ -215,6 +296,70 @@ removed securely. Service Discovery +p2p_service_add asp <auto accept> <adv id> <status 0/1> <Config Methods> + <Service name> [Service Information] [Response Info] + +This command can be used to search for a P2PS service which includes +Play, Send, Display, and Print service. The parameters for this command +are "asp" to identify the command as P2PS one, auto accept value, +advertisement id which uniquely identifies the service requests, state +of the service whether the service is available or not, config methods +which can be either P2PS method or PIN method, service name followed by +two optional parameters service information, and response info. + +For example, +p2p_service_add asp 1 4d6fc7 0 1108 alt.example.chat svc_info='name=john' rsp_info='enter PIN 1234' + +Parameters definition: + asp - Mandatory for ASP service registration + auto accept - Mandatory ASCII hex-encoded boolean (0 == no auto-accept, + 1 == auto-accept ANY role, 2 == auto-accept CLIENT role, + 4 == auto-accept GO role) + Advertisement ID - Mandatory non-zero ASCII hex-encoded u32 + (Must be unique/not yet exist in svc db) + State - Mandatory ASCII hex-encoded u8 (0 -- Svc not available, + 1 -- Svc available, 2-0xff Application defined) + Config Methods - Mandatory ASCII hex-encoded u16 (bitmask of WSC config + methods) + Service Name - Mandatory UTF-8 string + Service Information - Optional UTF-8 string + Escape single quote & backslash with a backslash: + 0x27 == ' == \', and 0x5c == \ == \\ + Session response information - Optional (used only if auto accept is TRUE) + UTF-8 string + Escape single quote & backslash with a backslash: + 0x27 == ' == \', and 0x5c == \ == \\ + +p2p_service_rep asp <auto accept> <adv id> <status 0/1> <Config Methods> + <Service name> [Service Information] [Response Info] + +This command can be used to replace the existing service request +attributes from the initiator side. The replacement is only allowed if +the advertisement id issued in the command matches with any one entry in +the list of existing SD queries. If advertisement id doesn't match the +command returns a failure. + +For example, +p2p_service_rep asp 1 4d6fc7 1 1108 alt.example.chat svc_info='name=john' rsp_info='enter PIN 1234' + +Parameters definition: + asp - Mandatory for ASP service registration + auto accept - Mandatory ASCII hex-encoded boolean (1 == true, 0 == false) + Advertisement ID - Mandatory non-zero ASCII hex-encoded u32 + (Must already exist in svc db) + State - Mandatory ASCII hex-encoded u8 (can be used to indicate svc + available or not available for instance) + Config Methods - Mandatory ASCII hex-encoded u16 (bitmask of WSC config + methods) + Service Name - Mandatory UTF-8 string (Must match existing string in svc db) + Service Information - Optional UTF-8 string + Escape single quote & backslash with a backslash: + 0x27 == ' == \', and 0x5c == \ == \\ + Session response information - Optional (used only if auto accept is TRUE) + UTF-8 string + Escape single quote & backslash with a backslash: + 0x27 == ' == \', and 0x5c == \ == \\ + p2p_serv_disc_req Schedule a P2P service discovery request. The parameters for this @@ -296,6 +441,27 @@ p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [sec-source] 2 p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [source+sink] 2,3,4,5 p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [source][pri-sink] 2,3,4,5 +p2p_serv_disc_req <Unicast|Broadcast mac address> asp <Transaction ID> + <Service Name> [Service Information] + +The command can be used for service discovery for P2PS enabled devices. + +For example: p2p_serv_disc_req 00:00:00:00:00:00 asp a1 alt.example 'john' + +Parameters definition: + MAC address - Mandatory Existing + asp - Mandatory for ASP queries + Transaction ID - Mandatory non-zero ASCII hex-encoded u8 for GAS + Service Name Prefix - Mandatory UTF-8 string. + Will match from beginning of remote Service Name + Service Information Substring - Optional UTF-8 string + If Service Information Substring is not included, all services matching + Service Name Prefix will be returned. + If Service Information Substring is included, both the Substring and the + Service Name Prefix must match for service to be returned. + If remote service has no Service Information, all Substring searches + will fail. + p2p_serv_disc_cancel_req <query identifier> Cancel a pending P2P service discovery request. This command takes a @@ -371,6 +537,11 @@ p2p_service_del upnp <version hex> <service> Remove a local UPnP service from internal SD query processing. +p2p_service_del asp <adv id> + +Removes the local asp service from internal SD query list. +For example: p2p_service_del asp 4d6fc7 + p2p_service_flush Remove all local services from internal SD query processing. @@ -605,6 +776,63 @@ remove_network <network id> Remove a network entry from configuration. +P2PS Events/Responses: + +P2PS-PROV-START: This events gets triggered when provisioning is issued for +either seeker or advertiser. + +For example, +P2PS-PROV-START 00:55:44:33:22:11 adv_id=111 adv_mac=00:55:44:33:22:11 conncap=1 session=1234567 session_mac=00:11:22:33:44:55 info='xxxx' + +Parameters definition: + MAC address - always + adv_id - always ASCII hex-encoded u32 + adv_mac - always MAC address that owns/registered the service + conncap - always mask of 0x01 (new), 0x02 (group client), 0x04 (group owner) + bits + session - always Session ID of the first session to be established + session_mac - always MAC address that owns/initiated the session + info - if available, UTF-8 string + Escaped single quote & backslash with a backslash: + \' == 0x27 == ', and \\ == 0x5c == \ + +P2PS-PROV-DONE: When provisioning is completed then this event gets triggered. + +For example, +P2PS-PROV-DONE 00:11:22:33:44:55 status=0 adv_id=111 adv_mac=00:55:44:33:22:11 conncap=1 session=1234567 session_mac=00:11:22:33:44:55 [dev_passwd_id=8 | go=p2p-wlan0-0 | join=11:22:33:44:55:66 | persist=0] + +Parameters definition: + MAC address - always main device address of peer. May be different from MAC + ultimately connected to. + status - always ascii hex-encoded u8 (0 == success, 12 == deferred success) + adv_id - always ascii hex-encoded u32 + adv_mac - always MAC address that owns/registered the service + conncap - always One of: 1 (new), 2 (group client), 4 (group owner) bits + session - always Session ID of the first session to be established + session_mac - always MAC address that owns/initiated the session + dev_passwd_id - only if conncap value == 1 (New GO negotiation) + 8 - "p2ps" password must be passed in p2p_connect command + 1 - "display" password must be passed in p2p_connect command + 5 - "keypad" password must be passed in p2p_connect command + join only - if conncap value == 2 (Client Only). Display password and "join" + must be passed in p2p_connect and address must be the MAC specified + go only - if conncap value == 4 (GO Only). Interface name must be set with a + password + persist - only if previous persistent group existed between peers and shall + be re-used. Group is restarted by sending "p2p_group_add persistent=0" + where value is taken from P2P-PROV-DONE + +Extended Events/Response + +P2P-DEVICE-FOUND 00:11:22:33:44:55 p2p_dev_addr=00:11:22:33:44:55 pri_dev_type=0-00000000-0 name='' config_methods=0x108 dev_capab=0x21 group_capab=0x0 adv_id=111 asp_svc=alt.example.chat + +Parameters definition: + adv_id - if ASP ASCII hex-encoded u32. If it is reporting the + "wildcard service", this value will be 0 + asp_svc - if ASP this is the service string. If it is reporting the + "wildcard service", this value will be org.wi-fi.wfds + + wpa_cli action script --------------------- diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c index 65532e3c..f2c60e7f 100644 --- a/wpa_supplicant/ap.c +++ b/wpa_supplicant/ap.c @@ -265,6 +265,17 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s, else if (wpa_s->conf->beacon_int) conf->beacon_int = wpa_s->conf->beacon_int; +#ifdef CONFIG_P2P + if (wpa_s->conf->p2p_go_ctwindow > conf->beacon_int) { + wpa_printf(MSG_INFO, + "CTWindow (%d) is bigger than beacon interval (%d) - avoid configuring it", + wpa_s->conf->p2p_go_ctwindow, conf->beacon_int); + conf->p2p_go_ctwindow = 0; + } else { + conf->p2p_go_ctwindow = wpa_s->conf->p2p_go_ctwindow; + } +#endif /* CONFIG_P2P */ + 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, @@ -1238,3 +1249,14 @@ int wpas_ap_wps_add_nfc_pw(struct wpa_supplicant *wpa_s, u16 pw_id, pw ? wpabuf_len(pw) : 0, 1); } #endif /* CONFIG_WPS_NFC */ + + +int wpas_ap_stop_ap(struct wpa_supplicant *wpa_s) +{ + struct hostapd_data *hapd; + + if (!wpa_s->ap_iface) + return -1; + hapd = wpa_s->ap_iface->bss[0]; + return hostapd_ctrl_iface_stop_ap(hapd); +} diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h index 4d80c7a7..6a118342 100644 --- a/wpa_supplicant/ap.h +++ b/wpa_supplicant/ap.h @@ -80,4 +80,6 @@ void wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, struct hostapd_config *conf); +int wpas_ap_stop_ap(struct wpa_supplicant *wpa_s); + #endif /* AP_H */ diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c index 17984396..b4c47e21 100644 --- a/wpa_supplicant/bss.c +++ b/wpa_supplicant/bss.c @@ -1,6 +1,6 @@ /* * BSS table - * Copyright (c) 2009-2012, Jouni Malinen <j@w1.fi> + * Copyright (c) 2009-2015, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -85,6 +85,7 @@ static struct wpa_bss_anqp * wpa_bss_anqp_clone(struct wpa_bss_anqp *anqp) #define ANQP_DUP(f) if (anqp->f) n->f = wpabuf_dup(anqp->f) #ifdef CONFIG_INTERWORKING + ANQP_DUP(capability_list); ANQP_DUP(venue_name); ANQP_DUP(network_auth_type); ANQP_DUP(roaming_consortium); @@ -94,6 +95,7 @@ static struct wpa_bss_anqp * wpa_bss_anqp_clone(struct wpa_bss_anqp *anqp) ANQP_DUP(domain_name); #endif /* CONFIG_INTERWORKING */ #ifdef CONFIG_HS20 + ANQP_DUP(hs20_capability_list); ANQP_DUP(hs20_operator_friendly_name); ANQP_DUP(hs20_wan_metrics); ANQP_DUP(hs20_connection_capability); @@ -154,6 +156,7 @@ static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp) } #ifdef CONFIG_INTERWORKING + wpabuf_free(anqp->capability_list); wpabuf_free(anqp->venue_name); wpabuf_free(anqp->network_auth_type); wpabuf_free(anqp->roaming_consortium); @@ -163,6 +166,7 @@ static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp) wpabuf_free(anqp->domain_name); #endif /* CONFIG_INTERWORKING */ #ifdef CONFIG_HS20 + wpabuf_free(anqp->hs20_capability_list); wpabuf_free(anqp->hs20_operator_friendly_name); wpabuf_free(anqp->hs20_wan_metrics); wpabuf_free(anqp->hs20_connection_capability); @@ -282,6 +286,8 @@ static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src, dst->noise = src->noise; dst->level = src->level; dst->tsf = src->tsf; + dst->est_throughput = src->est_throughput; + dst->snr = src->snr; calculate_update_time(fetch_time, src->age, &dst->last_update); } diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h index 4a624c58..634aa3cc 100644 --- a/wpa_supplicant/bss.h +++ b/wpa_supplicant/bss.h @@ -1,6 +1,6 @@ /* * BSS table - * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi> + * Copyright (c) 2009-2015, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -26,6 +26,7 @@ struct wpa_bss_anqp { /** Number of BSS entries referring to this ANQP data instance */ unsigned int users; #ifdef CONFIG_INTERWORKING + struct wpabuf *capability_list; struct wpabuf *venue_name; struct wpabuf *network_auth_type; struct wpabuf *roaming_consortium; @@ -35,6 +36,7 @@ struct wpa_bss_anqp { struct wpabuf *domain_name; #endif /* CONFIG_INTERWORKING */ #ifdef CONFIG_HS20 + struct wpabuf *hs20_capability_list; struct wpabuf *hs20_operator_friendly_name; struct wpabuf *hs20_wan_metrics; struct wpabuf *hs20_connection_capability; @@ -86,6 +88,10 @@ struct wpa_bss { u64 tsf; /** Time of the last update (i.e., Beacon or Probe Response RX) */ struct os_reltime last_update; + /** Estimated throughput in kbps */ + unsigned int est_throughput; + /** Signal-to-noise ratio in dB */ + int snr; /** ANQP data */ struct wpa_bss_anqp *anqp; /** Length of the following IE field in octets (from Probe Response) */ @@ -135,4 +141,10 @@ static inline int bss_is_dmg(const struct wpa_bss *bss) return bss->freq > 45000; } +static inline void wpa_bss_update_level(struct wpa_bss *bss, int new_level) +{ + if (bss != NULL && new_level < 0) + bss->level = new_level; +} + #endif /* BSS_H */ diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index 1ffc2dca..8e6cd200 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -1896,6 +1896,7 @@ static const struct parse_data ssid_fields[] = { { INT_RANGE(peerkey, 0, 1) }, { INT_RANGE(mixed_cell, 0, 1) }, { INT_RANGE(frequency, 0, 65000) }, + { INT_RANGE(fixed_freq, 0, 1) }, #ifdef CONFIG_MESH { FUNC(mesh_basic_rates) }, { INT(dot11MeshMaxRetries) }, @@ -3503,6 +3504,7 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface, config->p2p_intra_bss = DEFAULT_P2P_INTRA_BSS; config->p2p_go_max_inactivity = DEFAULT_P2P_GO_MAX_INACTIVITY; config->p2p_optimize_listen_chan = DEFAULT_P2P_OPTIMIZE_LISTEN_CHAN; + config->p2p_go_ctwindow = DEFAULT_P2P_GO_CTWINDOW; config->bss_max_count = DEFAULT_BSS_MAX_COUNT; config->bss_expiration_age = DEFAULT_BSS_EXPIRATION_AGE; config->bss_expiration_scan_count = DEFAULT_BSS_EXPIRATION_SCAN_COUNT; @@ -3556,6 +3558,8 @@ struct global_parse_data { char *name; int (*parser)(const struct global_parse_data *data, struct wpa_config *config, int line, const char *value); + int (*get)(const char *name, struct wpa_config *config, long offset, + char *buf, size_t buflen, int pretty_print); void *param1, *param2, *param3; unsigned int changed_flag; }; @@ -4015,22 +4019,55 @@ static int wpa_config_process_no_ctrl_interface( #endif /* CONFIG_CTRL_IFACE */ +static int wpa_config_get_int(const char *name, struct wpa_config *config, + long offset, char *buf, size_t buflen, + int pretty_print) +{ + int *val = (int *) (((u8 *) config) + (long) offset); + + if (pretty_print) + return os_snprintf(buf, buflen, "%s=%d\n", name, *val); + return os_snprintf(buf, buflen, "%d", *val); +} + + +static int wpa_config_get_str(const char *name, struct wpa_config *config, + long offset, char *buf, size_t buflen, + int pretty_print) +{ + char **val = (char **) (((u8 *) config) + (long) offset); + int res; + + if (pretty_print) + res = os_snprintf(buf, buflen, "%s=%s\n", name, + *val ? *val : "null"); + else if (!*val) + return -1; + else + res = os_snprintf(buf, buflen, "%s", *val); + if (os_snprintf_error(buflen, res)) + res = -1; + + return res; +} + + #ifdef OFFSET #undef OFFSET #endif /* OFFSET */ /* OFFSET: Get offset of a variable within the wpa_config structure */ #define OFFSET(v) ((void *) &((struct wpa_config *) 0)->v) -#define FUNC(f) #f, wpa_config_process_ ## f, OFFSET(f), NULL, NULL -#define FUNC_NO_VAR(f) #f, wpa_config_process_ ## f, NULL, NULL, NULL -#define _INT(f) #f, wpa_global_config_parse_int, OFFSET(f) +#define FUNC(f) #f, wpa_config_process_ ## f, NULL, OFFSET(f), NULL, NULL +#define FUNC_NO_VAR(f) #f, wpa_config_process_ ## f, NULL, NULL, NULL, NULL +#define _INT(f) #f, wpa_global_config_parse_int, wpa_config_get_int, OFFSET(f) #define INT(f) _INT(f), NULL, NULL #define INT_RANGE(f, min, max) _INT(f), (void *) min, (void *) max -#define _STR(f) #f, wpa_global_config_parse_str, OFFSET(f) +#define _STR(f) #f, wpa_global_config_parse_str, wpa_config_get_str, OFFSET(f) #define STR(f) _STR(f), NULL, NULL #define STR_RANGE(f, min, max) _STR(f), (void *) min, (void *) max -#define BIN(f) #f, wpa_global_config_parse_bin, OFFSET(f), NULL, NULL -#define IPV4(f) #f, wpa_global_config_parse_ipv4, OFFSET(f), NULL, NULL +#define BIN(f) #f, wpa_global_config_parse_bin, NULL, OFFSET(f), NULL, NULL +#define IPV4(f) #f, wpa_global_config_parse_ipv4, NULL, OFFSET(f), NULL, NULL static const struct global_parse_data global_fields[] = { #ifdef CONFIG_CTRL_IFACE @@ -4100,6 +4137,7 @@ static const struct global_parse_data global_fields[] = { { INT(p2p_go_ht40), 0 }, { INT(p2p_go_vht), 0 }, { INT(p2p_disabled), 0 }, + { INT_RANGE(p2p_go_ctwindow, 0, 127), 0 }, { INT(p2p_no_group_iface), 0 }, { INT_RANGE(p2p_ignore_shared_freq, 0, 1), 0 }, { IPV4(ip_addr_go), 0 }, @@ -4150,6 +4188,7 @@ static const struct global_parse_data global_fields[] = { { INT(preassoc_mac_addr), 0 }, { INT(key_mgmt_offload), 0}, { INT(passive_scan), 0 }, + { INT(reassoc_same_bss_optim), 0 }, }; #undef FUNC @@ -4164,6 +4203,50 @@ static const struct global_parse_data global_fields[] = { #define NUM_GLOBAL_FIELDS ARRAY_SIZE(global_fields) +int wpa_config_dump_values(struct wpa_config *config, char *buf, size_t buflen) +{ + int result = 0; + size_t i; + + for (i = 0; i < NUM_GLOBAL_FIELDS; i++) { + const struct global_parse_data *field = &global_fields[i]; + int tmp; + + if (!field->get) + continue; + + tmp = field->get(field->name, config, (long) field->param1, + buf, buflen, 1); + if (tmp < 0) + return -1; + buf += tmp; + buflen -= tmp; + result += tmp; + } + return result; +} + + +int wpa_config_get_value(const char *name, struct wpa_config *config, + char *buf, size_t buflen) +{ + size_t i; + + for (i = 0; i < NUM_GLOBAL_FIELDS; i++) { + const struct global_parse_data *field = &global_fields[i]; + + if (os_strcmp(name, field->name) != 0) + continue; + if (!field->get) + break; + return field->get(name, config, (long) field->param1, + buf, buflen, 0); + } + + return -1; +} + + int wpa_config_process_global(struct wpa_config *config, char *pos, int line) { size_t i; diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index 6adf1eb3..34b754e0 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -33,6 +33,7 @@ #define DEFAULT_RAND_ADDR_LIFETIME 60 #define DEFAULT_KEY_MGMT_OFFLOAD 1 #define DEFAULT_CERT_IN_CB 1 +#define DEFAULT_P2P_GO_CTWINDOW 0 #include "config_ssid.h" #include "wps/wps.h" @@ -942,6 +943,14 @@ struct wpa_config { int p2p_go_vht; /** + * p2p_go_ctwindow - CTWindow to use when operating as GO + * + * By default: 0 (no CTWindow). Values 0-127 can be used to indicate + * the length of the CTWindow in TUs. + */ + int p2p_go_ctwindow; + + /** * p2p_disabled - Whether P2P operations are disabled for this interface */ int p2p_disabled; @@ -1149,6 +1158,11 @@ struct wpa_config { * (scan_ssid=1) or P2P device discovery. */ int passive_scan; + + /** + * reassoc_same_bss_optim - Whether to optimize reassoc-to-same-BSS + */ + int reassoc_same_bss_optim; }; @@ -1167,6 +1181,11 @@ int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value, int line); int wpa_config_set_quoted(struct wpa_ssid *ssid, const char *var, const char *value); +int wpa_config_dump_values(struct wpa_config *config, char *buf, + size_t buflen); +int wpa_config_get_value(const char *name, struct wpa_config *config, + char *buf, size_t buflen); + char ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys); char * wpa_config_get(struct wpa_ssid *ssid, const char *var); char * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var); diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index b15207dc..3d3a6e40 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -11,6 +11,9 @@ */ #include "includes.h" +#ifdef ANDROID +#include <sys/stat.h> +#endif /* ANDROID */ #include "common.h" #include "config.h" @@ -20,9 +23,6 @@ #include "eap_peer/eap_methods.h" #include "eap_peer/eap.h" -#ifdef ANDROID -#include <sys/stat.h> -#endif static int newline_terminated(const char *buf, size_t buflen) { @@ -670,6 +670,8 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) STR(ssid); INT(scan_ssid); write_bssid(f, ssid); + write_str(f, "bssid_blacklist", ssid); + write_str(f, "bssid_whitelist", ssid); write_psk(f, ssid); write_proto(f, ssid); write_key_mgmt(f, ssid); @@ -721,6 +723,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) INTe(engine); INTe(engine2); INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS); + STR(openssl_ciphers); INTe(erp); #endif /* IEEE8021X_EAPOL */ for (i = 0; i < 4; i++) @@ -735,10 +738,13 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) INT_DEFe(sim_num, DEFAULT_USER_SELECTED_SIM); #endif /* IEEE8021X_EAPOL */ INT(mode); + INT(no_auto_peer); INT(frequency); + INT(fixed_freq); write_int(f, "proactive_key_caching", ssid->proactive_key_caching, -1); INT(disabled); INT(peerkey); + INT(mixed_cell); #ifdef CONFIG_IEEE80211W write_int(f, "ieee80211w", ssid->ieee80211w, MGMT_FRAME_PROTECTION_DEFAULT); @@ -749,6 +755,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) write_p2p_client_list(f, ssid); write_psk_list(f, ssid); #endif /* CONFIG_P2P */ + INT(ap_max_inactivity); INT(dtim_period); INT(beacon_int); #ifdef CONFIG_MACSEC @@ -765,6 +772,40 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) INT_DEF(dot11MeshConfirmTimeout, DEFAULT_MESH_CONFIRM_TIMEOUT); INT_DEF(dot11MeshHoldingTimeout, DEFAULT_MESH_HOLDING_TIMEOUT); #endif /* CONFIG_MESH */ + INT(wpa_ptk_rekey); + INT(ignore_broadcast_ssid); +#ifdef CONFIG_HT_OVERRIDES + INT_DEF(disable_ht, DEFAULT_DISABLE_HT); + INT_DEF(disable_ht40, DEFAULT_DISABLE_HT40); + INT_DEF(disable_sgi, DEFAULT_DISABLE_SGI); + INT_DEF(disable_ldpc, DEFAULT_DISABLE_LDPC); + INT(ht40_intolerant); + INT_DEF(disable_max_amsdu, DEFAULT_DISABLE_MAX_AMSDU); + INT_DEF(ampdu_factor, DEFAULT_AMPDU_FACTOR); + INT_DEF(ampdu_density, DEFAULT_AMPDU_DENSITY); + STR(ht_mcs); +#endif /* CONFIG_HT_OVERRIDES */ +#ifdef CONFIG_VHT_OVERRIDES + INT(disable_vht); + INT(vht_capa); + INT(vht_capa_mask); + INT_DEF(vht_rx_mcs_nss_1, -1); + INT_DEF(vht_rx_mcs_nss_2, -1); + INT_DEF(vht_rx_mcs_nss_3, -1); + INT_DEF(vht_rx_mcs_nss_4, -1); + INT_DEF(vht_rx_mcs_nss_5, -1); + INT_DEF(vht_rx_mcs_nss_6, -1); + INT_DEF(vht_rx_mcs_nss_7, -1); + INT_DEF(vht_rx_mcs_nss_8, -1); + INT_DEF(vht_tx_mcs_nss_1, -1); + INT_DEF(vht_tx_mcs_nss_2, -1); + INT_DEF(vht_tx_mcs_nss_3, -1); + INT_DEF(vht_tx_mcs_nss_4, -1); + INT_DEF(vht_tx_mcs_nss_5, -1); + INT_DEF(vht_tx_mcs_nss_6, -1); + INT_DEF(vht_tx_mcs_nss_7, -1); + INT_DEF(vht_tx_mcs_nss_8, -1); +#endif /* CONFIG_VHT_OVERRIDES */ #undef STR #undef INT @@ -1074,6 +1115,8 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) fprintf(f, "p2p_go_ht40=%u\n", config->p2p_go_ht40); if (config->p2p_go_vht) fprintf(f, "p2p_go_vht=%u\n", config->p2p_go_vht); + if (config->p2p_go_ctwindow != DEFAULT_P2P_GO_CTWINDOW) + fprintf(f, "p2p_go_ctwindow=%u\n", config->p2p_go_ctwindow); if (config->p2p_disabled) fprintf(f, "p2p_disabled=%u\n", config->p2p_disabled); if (config->p2p_no_group_iface) @@ -1232,7 +1275,11 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) config->mesh_max_inactivity); if (config->passive_scan) - fprintf(f, "cert_in_cb=%d\n", config->passive_scan); + fprintf(f, "passive_scan=%d\n", config->passive_scan); + + if (config->reassoc_same_bss_optim) + fprintf(f, "reassoc_same_bss_optim=%d\n", + config->reassoc_same_bss_optim); } #endif /* CONFIG_NO_CONFIG_WRITE */ @@ -1248,21 +1295,21 @@ int wpa_config_write(const char *name, struct wpa_config *config) struct wpa_config_blob *blob; #endif /* CONFIG_NO_CONFIG_BLOBS */ int ret = 0; - int tmp_len = os_strlen(name) + 5; /* allow space for .tmp suffix */ + const char *orig_name = name; + int tmp_len = os_strlen(name) + 5; /* allow space for .tmp suffix */ char *tmp_name = os_malloc(tmp_len); - if (tmp_name == NULL) - tmp_name = (char *)name; - else + if (tmp_name) { os_snprintf(tmp_name, tmp_len, "%s.tmp", name); + name = tmp_name; + } - wpa_printf(MSG_DEBUG, "Writing configuration file '%s'", tmp_name); + wpa_printf(MSG_DEBUG, "Writing configuration file '%s'", name); - f = fopen(tmp_name, "w"); + f = fopen(name, "w"); if (f == NULL) { - wpa_printf(MSG_DEBUG, "Failed to open '%s' for writing", tmp_name); - if (tmp_name != name) - os_free(tmp_name); + wpa_printf(MSG_DEBUG, "Failed to open '%s' for writing", name); + os_free(tmp_name); return -1; } @@ -1297,19 +1344,21 @@ int wpa_config_write(const char *name, struct wpa_config *config) fclose(f); - if (tmp_name != name) { + if (tmp_name) { int chmod_ret = 0; + #ifdef ANDROID - chmod_ret = chmod(tmp_name, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); -#endif - if (chmod_ret != 0 || rename(tmp_name, name) != 0) + chmod_ret = chmod(tmp_name, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); +#endif /* ANDROID */ + if (chmod_ret != 0 || rename(tmp_name, orig_name) != 0) ret = -1; os_free(tmp_name); } wpa_printf(MSG_DEBUG, "Configuration file '%s' written %ssuccessfully", - name, ret ? "un" : ""); + orig_name, ret ? "un" : ""); return ret; #else /* CONFIG_NO_CONFIG_WRITE */ return -1; diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h index f744895a..7c826cfd 100644 --- a/wpa_supplicant/config_ssid.h +++ b/wpa_supplicant/config_ssid.h @@ -420,6 +420,11 @@ struct wpa_ssid { int frequency; /** + * fixed_freq - Use fixed frequency for IBSS + */ + int fixed_freq; + + /** * mesh_basic_rates - BSS Basic rate set for mesh network * */ diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index c59ccc3c..ec198b29 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -498,6 +498,8 @@ static int wpa_supplicant_ctrl_iface_get(struct wpa_supplicant *wpa_s, #endif /* CONFIG_TESTING_GET_GTK */ } else if (os_strcmp(cmd, "tls_library") == 0) { res = tls_get_library_version(buf, buflen); + } else { + res = wpa_config_get_value(cmd, wpa_s->conf, buf, buflen); } if (os_snprintf_error(buflen, res)) @@ -2930,8 +2932,6 @@ static int wpa_supplicant_ctrl_iface_update_network( wpa_config_update_psk(ssid); else if (os_strcmp(name, "priority") == 0) wpa_config_update_prio_list(wpa_s->conf); - else if (os_strcmp(name, "no_auto_peer") == 0) - ssid->no_auto_peer = atoi(value); return 0; } @@ -2940,7 +2940,7 @@ static int wpa_supplicant_ctrl_iface_update_network( static int wpa_supplicant_ctrl_iface_set_network( struct wpa_supplicant *wpa_s, char *cmd) { - int id, ret, prev_bssid_set; + int id, ret, prev_bssid_set, prev_disabled; struct wpa_ssid *ssid; char *name, *value; u8 prev_bssid[ETH_ALEN]; @@ -2970,6 +2970,7 @@ static int wpa_supplicant_ctrl_iface_set_network( } prev_bssid_set = ssid->bssid_set; + prev_disabled = ssid->disabled; os_memcpy(prev_bssid, ssid->bssid, ETH_ALEN); ret = wpa_supplicant_ctrl_iface_update_network(wpa_s, ssid, name, value); @@ -2977,6 +2978,11 @@ static int wpa_supplicant_ctrl_iface_set_network( (ssid->bssid_set != prev_bssid_set || os_memcmp(ssid->bssid, prev_bssid, ETH_ALEN) != 0)) wpas_notify_network_bssid_set_changed(wpa_s, ssid); + + if (prev_disabled != ssid->disabled && + (prev_disabled == 2 || ssid->disabled == 2)) + wpas_notify_network_type_changed(wpa_s, ssid); + return ret; } @@ -4170,6 +4176,8 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, #ifdef CONFIG_INTERWORKING if ((mask & WPA_BSS_MASK_INTERNETW) && bss->anqp) { struct wpa_bss_anqp *anqp = bss->anqp; + pos = anqp_add_hex(pos, end, "anqp_capability_list", + anqp->capability_list); pos = anqp_add_hex(pos, end, "anqp_venue_name", anqp->venue_name); pos = anqp_add_hex(pos, end, "anqp_network_auth_type", @@ -4184,6 +4192,8 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, pos = anqp_add_hex(pos, end, "anqp_domain_name", anqp->domain_name); #ifdef CONFIG_HS20 + pos = anqp_add_hex(pos, end, "hs20_capability_list", + anqp->hs20_capability_list); pos = anqp_add_hex(pos, end, "hs20_operator_friendly_name", anqp->hs20_operator_friendly_name); pos = anqp_add_hex(pos, end, "hs20_wan_metrics", @@ -4208,6 +4218,21 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, } #endif /* CONFIG_MESH */ + if (mask & WPA_BSS_MASK_SNR) { + ret = os_snprintf(pos, end - pos, "snr=%d\n", bss->snr); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + } + + if (mask & WPA_BSS_MASK_EST_THROUGHPUT) { + ret = os_snprintf(pos, end - pos, "est_throughput=%d\n", + bss->est_throughput); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + } + if (mask & WPA_BSS_MASK_DELIM) { ret = os_snprintf(pos, end - pos, "====\n"); if (os_snprintf_error(end - pos, ret)) @@ -4717,7 +4742,7 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, /* <addr> <"pbc" | "pin" | PIN> [label|display|keypad|p2ps] * [persistent|persistent=<network id>] * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc] - * [ht40] [vht] */ + * [ht40] [vht] [auto] */ if (hwaddr_aton(cmd, addr)) return -1; @@ -5942,7 +5967,8 @@ static int ctrl_interworking_select(struct wpa_supplicant *wpa_s, char *param) } -static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst) +static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst, + int only_add) { u8 bssid[ETH_ALEN]; struct wpa_bss *bss; @@ -5980,7 +6006,7 @@ static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst) "Found another matching BSS entry with SSID"); } - return interworking_connect(wpa_s, bss); + return interworking_connect(wpa_s, bss, only_add); } @@ -7833,6 +7859,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "SET ", 4) == 0) { if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4)) reply_len = -1; + } else if (os_strncmp(buf, "DUMP", 4) == 0) { + reply_len = wpa_config_dump_values(wpa_s->conf, + reply, reply_size); } else if (os_strncmp(buf, "GET ", 4) == 0) { reply_len = wpa_supplicant_ctrl_iface_get(wpa_s, buf + 4, reply, reply_size); @@ -8115,8 +8144,19 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, if (ctrl_interworking_select(wpa_s, buf + 20) < 0) reply_len = -1; } else if (os_strncmp(buf, "INTERWORKING_CONNECT ", 21) == 0) { - if (ctrl_interworking_connect(wpa_s, buf + 21) < 0) + if (ctrl_interworking_connect(wpa_s, buf + 21, 0) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "INTERWORKING_ADD_NETWORK ", 25) == 0) { + int id; + + id = ctrl_interworking_connect(wpa_s, buf + 25, 1); + if (id < 0) reply_len = -1; + else { + reply_len = os_snprintf(reply, reply_size, "%d\n", id); + if (os_snprintf_error(reply_size, reply_len)) + reply_len = -1; + } } else if (os_strncmp(buf, "ANQP_GET ", 9) == 0) { if (get_anqp(wpa_s, buf + 9) < 0) reply_len = -1; @@ -8274,6 +8314,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) { if (ap_ctrl_iface_chanswitch(wpa_s, buf + 12)) reply_len = -1; + } else if (os_strcmp(buf, "STOP_AP") == 0) { + if (wpas_ap_stop_ap(wpa_s)) + reply_len = -1; #endif /* CONFIG_AP */ } else if (os_strcmp(buf, "SUSPEND") == 0) { wpas_notify_suspend(wpa_s->global); diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 539832ce..1c46d35d 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -175,6 +175,15 @@ void wpa_supplicant_stop_countermeasures(void *eloop_ctx, void *sock_ctx) wpa_s->countermeasures = 0; wpa_drv_set_countermeasures(wpa_s, 0); wpa_msg(wpa_s, MSG_INFO, "WPA: TKIP countermeasures stopped"); + + /* + * It is possible that the device is sched scanning, which means + * that a connection attempt will be done only when we receive + * scan results. However, in this case, it would be preferable + * to scan and connect immediately, so cancel the sched_scan and + * issue a regular scan flow. + */ + wpa_supplicant_cancel_sched_scan(wpa_s); wpa_supplicant_req_scan(wpa_s, 0, 0); } } @@ -1214,10 +1223,14 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s, #ifndef CONFIG_NO_ROAMING wpa_dbg(wpa_s, MSG_DEBUG, "Considering within-ESS reassociation"); - wpa_dbg(wpa_s, MSG_DEBUG, "Current BSS: " MACSTR " level=%d", - MAC2STR(current_bss->bssid), current_bss->level); - wpa_dbg(wpa_s, MSG_DEBUG, "Selected BSS: " MACSTR " level=%d", - MAC2STR(selected->bssid), selected->level); + wpa_dbg(wpa_s, MSG_DEBUG, "Current BSS: " MACSTR + " level=%d snr=%d est_throughput=%u", + MAC2STR(current_bss->bssid), current_bss->level, + current_bss->snr, current_bss->est_throughput); + wpa_dbg(wpa_s, MSG_DEBUG, "Selected BSS: " MACSTR + " level=%d snr=%d est_throughput=%u", + MAC2STR(selected->bssid), selected->level, + selected->snr, selected->est_throughput); if (wpa_s->current_ssid->bssid_set && os_memcmp(selected->bssid, wpa_s->current_ssid->bssid, ETH_ALEN) == @@ -1227,6 +1240,12 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s, return 1; } + if (selected->est_throughput > current_bss->est_throughput + 5000) { + wpa_dbg(wpa_s, MSG_DEBUG, + "Allow reassociation - selected BSS has better estimated throughput"); + return 1; + } + if (current_bss->level < 0 && current_bss->level > selected->level) { wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - Current BSS has better " "signal level"); @@ -1448,7 +1467,12 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s, int timeout_sec = wpa_s->scan_interval; int timeout_usec = 0; #ifdef CONFIG_P2P - if (wpas_p2p_scan_no_go_seen(wpa_s) == 1) + int res; + + res = wpas_p2p_scan_no_go_seen(wpa_s); + if (res == 2) + return 2; + if (res == 1) return 0; if (wpa_s->p2p_in_provisioning || @@ -1498,12 +1522,21 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s, } -static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, - union wpa_event_data *data) +static int wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, + union wpa_event_data *data) { struct wpa_supplicant *ifs; + int res; - if (_wpa_supplicant_event_scan_results(wpa_s, data, 1) != 0) { + res = _wpa_supplicant_event_scan_results(wpa_s, data, 1); + if (res == 2) { + /* + * Interface may have been removed, so must not dereference + * wpa_s after this. + */ + return 1; + } + if (res != 0) { /* * If no scan results could be fetched, then no need to * notify those interfaces that did not actually request @@ -1511,7 +1544,7 @@ static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, * interface, do not notify other interfaces to avoid concurrent * operations during a connection attempt. */ - return; + return 0; } /* @@ -1526,6 +1559,8 @@ static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, _wpa_supplicant_event_scan_results(ifs, data, 0); } } + + return 0; } #endif /* CONFIG_NO_SCAN_PROCESSING */ @@ -3092,7 +3127,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, wpa_dbg(wpa_s, MSG_DEBUG, "Scan completed in %ld.%06ld seconds", diff.sec, diff.usec); } - wpa_supplicant_event_scan_results(wpa_s, data); + if (wpa_supplicant_event_scan_results(wpa_s, data)) + break; /* interface may have been removed */ wpa_s->own_scan_running = 0; wpa_s->radio->external_scan_running = 0; radio_work_check_next(wpa_s); @@ -3409,6 +3445,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, data->signal_change.current_signal, data->signal_change.current_noise, data->signal_change.current_txrate); + wpa_bss_update_level(wpa_s->current_bss, + data->signal_change.current_signal); bgscan_notify_signal_change( wpa_s, data->signal_change.above_threshold, data->signal_change.current_signal, diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c index eb18ed2b..b9cd6819 100644 --- a/wpa_supplicant/hs20_supplicant.c +++ b/wpa_supplicant/hs20_supplicant.c @@ -380,6 +380,11 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s, wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR " HS Capability List", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "HS Capability List", pos, slen); + if (anqp) { + wpabuf_free(anqp->hs20_capability_list); + anqp->hs20_capability_list = + wpabuf_alloc_copy(pos, slen); + } break; case HS20_STYPE_OPERATOR_FRIENDLY_NAME: wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c index 5b66211a..90b29915 100644 --- a/wpa_supplicant/interworking.c +++ b/wpa_supplicant/interworking.c @@ -955,7 +955,7 @@ static int interworking_set_hs20_params(struct wpa_supplicant *wpa_s, static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s, struct wpa_cred *cred, - struct wpa_bss *bss) + struct wpa_bss *bss, int only_add) { #ifdef INTERWORKING_3GPP struct wpa_ssid *ssid; @@ -972,7 +972,7 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s, if (already_connected(wpa_s, cred, bss)) { wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR, MAC2STR(bss->bssid)); - return 0; + return wpa_s->current_ssid->id; } remove_duplicate_network(wpa_s, cred, bss); @@ -1049,9 +1049,10 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s, wpa_s->next_ssid = ssid; wpa_config_update_prio_list(wpa_s->conf); - interworking_reconnect(wpa_s); + if (!only_add) + interworking_reconnect(wpa_s); - return 0; + return ssid->id; fail: wpas_notify_network_removed(wpa_s, ssid); @@ -1499,7 +1500,7 @@ static int interworking_set_eap_params(struct wpa_ssid *ssid, static int interworking_connect_roaming_consortium( struct wpa_supplicant *wpa_s, struct wpa_cred *cred, - struct wpa_bss *bss) + struct wpa_bss *bss, int only_add) { struct wpa_ssid *ssid; @@ -1509,7 +1510,7 @@ static int interworking_connect_roaming_consortium( if (already_connected(wpa_s, cred, bss)) { wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR, MAC2STR(bss->bssid)); - return 0; + return wpa_s->current_ssid->id; } remove_duplicate_network(wpa_s, cred, bss); @@ -1545,9 +1546,10 @@ static int interworking_connect_roaming_consortium( wpa_s->next_ssid = ssid; wpa_config_update_prio_list(wpa_s->conf); - interworking_reconnect(wpa_s); + if (!only_add) + interworking_reconnect(wpa_s); - return 0; + return ssid->id; fail: wpas_notify_network_removed(wpa_s, ssid); @@ -1557,7 +1559,8 @@ fail: static int interworking_connect_helper(struct wpa_supplicant *wpa_s, - struct wpa_bss *bss, int allow_excluded) + struct wpa_bss *bss, int allow_excluded, + int only_add) { struct wpa_cred *cred, *cred_rc, *cred_3gpp; struct wpa_ssid *ssid; @@ -1659,11 +1662,12 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s, (cred == NULL || cred_prio_cmp(cred_rc, cred) >= 0) && (cred_3gpp == NULL || cred_prio_cmp(cred_rc, cred_3gpp) >= 0)) return interworking_connect_roaming_consortium(wpa_s, cred_rc, - bss); + bss, only_add); if (cred_3gpp && (cred == NULL || cred_prio_cmp(cred_3gpp, cred) >= 0)) { - return interworking_connect_3gpp(wpa_s, cred_3gpp, bss); + return interworking_connect_3gpp(wpa_s, cred_3gpp, bss, + only_add); } if (cred == NULL) { @@ -1801,9 +1805,10 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s, wpa_s->next_ssid = ssid; wpa_config_update_prio_list(wpa_s->conf); - interworking_reconnect(wpa_s); + if (!only_add) + interworking_reconnect(wpa_s); - return 0; + return ssid->id; fail: wpas_notify_network_removed(wpa_s, ssid); @@ -1813,9 +1818,10 @@ fail: } -int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) +int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, + int only_add) { - return interworking_connect_helper(wpa_s, bss, 1); + return interworking_connect_helper(wpa_s, bss, 1, only_add); } @@ -2495,7 +2501,7 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s) MAC2STR(selected->bssid)); wpa_msg(wpa_s, MSG_INFO, INTERWORKING_SELECTED MACSTR, MAC2STR(selected->bssid)); - interworking_connect(wpa_s, selected); + interworking_connect(wpa_s, selected, 0); } } @@ -2722,6 +2728,12 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, case ANQP_CAPABILITY_LIST: wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR " ANQP Capability list", MAC2STR(sa)); + wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Capability list", + pos, slen); + if (anqp) { + wpabuf_free(anqp->capability_list); + anqp->capability_list = wpabuf_alloc_copy(pos, slen); + } break; case ANQP_VENUE_NAME: wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR diff --git a/wpa_supplicant/interworking.h b/wpa_supplicant/interworking.h index 38ef745f..3743dc00 100644 --- a/wpa_supplicant/interworking.h +++ b/wpa_supplicant/interworking.h @@ -24,7 +24,8 @@ int interworking_fetch_anqp(struct wpa_supplicant *wpa_s); void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s); int interworking_select(struct wpa_supplicant *wpa_s, int auto_select, int *freqs); -int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss); +int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, + int only_add); void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s); int interworking_home_sp_cred(struct wpa_supplicant *wpa_s, struct wpa_cred *cred, diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c index da4cb03c..936002d9 100644 --- a/wpa_supplicant/mesh_rsn.c +++ b/wpa_supplicant/mesh_rsn.c @@ -27,6 +27,7 @@ #define MESH_AUTH_TIMEOUT 10 #define MESH_AUTH_RETRY 3 +#define MESH_AUTH_BLOCK_DURATION 3600 void mesh_auth_timer(void *eloop_ctx, void *user_data) { @@ -37,12 +38,28 @@ void mesh_auth_timer(void *eloop_ctx, void *user_data) wpa_printf(MSG_DEBUG, "AUTH: Re-authenticate with " MACSTR " (attempt %d) ", MAC2STR(sta->addr), sta->sae_auth_retry); + wpa_msg(wpa_s, MSG_INFO, MESH_SAE_AUTH_FAILURE "addr=" MACSTR, + MAC2STR(sta->addr)); if (sta->sae_auth_retry < MESH_AUTH_RETRY) { mesh_rsn_auth_sae_sta(wpa_s, sta); } else { + if (sta->sae_auth_retry > MESH_AUTH_RETRY) { + ap_free_sta(wpa_s->ifmsh->bss[0], sta); + return; + } + /* block the STA if exceeded the number of attempts */ wpa_mesh_set_plink_state(wpa_s, sta, PLINK_BLOCKED); sta->sae->state = SAE_NOTHING; + if (wpa_s->mesh_auth_block_duration < + MESH_AUTH_BLOCK_DURATION) + wpa_s->mesh_auth_block_duration += 60; + eloop_register_timeout(wpa_s->mesh_auth_block_duration, + 0, mesh_auth_timer, wpa_s, sta); + wpa_msg(wpa_s, MSG_INFO, MESH_SAE_AUTH_BLOCKED "addr=" + MACSTR " duration=%d", + MAC2STR(sta->addr), + wpa_s->mesh_auth_block_duration); } sta->sae_auth_retry++; } @@ -299,6 +316,7 @@ int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s, if (ret) return ret; + eloop_cancel_timeout(mesh_auth_timer, wpa_s, sta); rnd = rand() % MESH_AUTH_TIMEOUT; eloop_register_timeout(MESH_AUTH_TIMEOUT + rnd, 0, mesh_auth_timer, wpa_s, sta); diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c index bf1836a5..ea7dbdb1 100644 --- a/wpa_supplicant/notify.c +++ b/wpa_supplicant/notify.c @@ -764,3 +764,22 @@ void wpas_notify_network_bssid_set_changed(struct wpa_supplicant *wpa_s, wpa_drv_roaming(wpa_s, !ssid->bssid_set, ssid->bssid_set ? ssid->bssid : NULL); } + + +void wpas_notify_network_type_changed(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ +#ifdef CONFIG_P2P + if (ssid->disabled == 2) { + /* Changed from normal network profile to persistent group */ + ssid->disabled = 0; + wpas_dbus_unregister_network(wpa_s, ssid->id); + ssid->disabled = 2; + wpas_dbus_register_persistent_group(wpa_s, ssid); + } else { + /* Changed from persistent group to normal network profile */ + wpas_dbus_unregister_persistent_group(wpa_s, ssid->id); + wpas_dbus_register_network(wpa_s, ssid); + } +#endif /* CONFIG_P2P */ +} diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h index 7fb1f58e..b268332f 100644 --- a/wpa_supplicant/notify.h +++ b/wpa_supplicant/notify.h @@ -131,5 +131,7 @@ void wpas_notify_eap_status(struct wpa_supplicant *wpa_s, const char *status, const char *parameter); void wpas_notify_network_bssid_set_changed(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); +void wpas_notify_network_type_changed(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid); #endif /* NOTIFY_H */ diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 9e1d6656..5e6646ed 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -117,8 +117,8 @@ static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s); static void wpas_p2p_group_formation_timeout(void *eloop_ctx, void *timeout_ctx); static void wpas_p2p_group_freq_conflict(void *eloop_ctx, void *timeout_ctx); -static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s, - int group_added); +static int wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s, + int group_added); static void wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s); static void wpas_stop_listen(void *ctx); static void wpas_p2p_psk_failure_removal(void *eloop_ctx, void *timeout_ctx); @@ -1401,6 +1401,9 @@ static void wpas_p2p_send_action_tx_status(struct wpa_supplicant *wpa_s, wpa_s->pending_pd_before_join = 0; wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No ACK for PD Req " "during p2p_connect-auto"); + wpa_msg_global(wpa_s->parent, MSG_INFO, + P2P_EVENT_FALLBACK_TO_GO_NEG + "reason=no-ACK-to-PD-Req"); wpas_p2p_fallback_to_go_neg(wpa_s, 0); return; } @@ -1849,6 +1852,7 @@ static void wpas_p2p_clone_config(struct wpa_supplicant *dst, d->ignore_old_scan_res = s->ignore_old_scan_res; d->beacon_int = s->beacon_int; d->dtim_period = s->dtim_period; + d->p2p_go_ctwindow = s->p2p_go_ctwindow; d->disassoc_low_ack = s->disassoc_low_ack; d->disable_scan_offload = s->disable_scan_offload; d->passive_scan = s->passive_scan; @@ -3728,6 +3732,9 @@ static void wpas_prov_disc_fail(void *ctx, const u8 *peer, if (wpa_s->p2p_fallback_to_go_neg) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: PD for p2p_connect-auto " "failed - fall back to GO Negotiation"); + wpa_msg_global(wpa_s->parent, MSG_INFO, + P2P_EVENT_FALLBACK_TO_GO_NEG + "reason=PD-failed"); wpas_p2p_fallback_to_go_neg(wpa_s, 0); return; } @@ -5545,6 +5552,9 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s, if (join < 0) { wpa_printf(MSG_DEBUG, "P2P: Peer was not found to be " "running a GO -> use GO Negotiation"); + wpa_msg_global(wpa_s->parent, MSG_INFO, + P2P_EVENT_FALLBACK_TO_GO_NEG + "reason=peer-not-running-GO"); wpas_p2p_connect(wpa_s, wpa_s->pending_join_dev_addr, wpa_s->p2p_pin, wpa_s->p2p_wps_method, wpa_s->p2p_persistent_group, 0, 0, 0, @@ -5560,8 +5570,11 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s, wpa_printf(MSG_DEBUG, "P2P: Peer was found running GO%s -> " "try to join the group", join ? "" : " in older scan"); - if (!join) + if (!join) { + wpa_msg_global(wpa_s->parent, MSG_INFO, + P2P_EVENT_FALLBACK_TO_GO_NEG_ENABLED); wpa_s->p2p_fallback_to_go_neg = 1; + } } freq = p2p_get_oper_freq(wpa_s->global->p2p, @@ -8184,16 +8197,18 @@ void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s, } -static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s, - int group_added) +static int wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s, + int group_added) { struct wpa_supplicant *group = wpa_s; + int ret = 0; + if (wpa_s->global->p2p_group_formation) group = wpa_s->global->p2p_group_formation; wpa_s = wpa_s->parent; offchannel_send_action_done(wpa_s); if (group_added) - wpas_p2p_group_delete(group, P2P_GROUP_REMOVAL_SILENT); + ret = wpas_p2p_group_delete(group, P2P_GROUP_REMOVAL_SILENT); wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Fall back to GO Negotiation"); wpas_p2p_connect(wpa_s, wpa_s->pending_join_dev_addr, wpa_s->p2p_pin, wpa_s->p2p_wps_method, wpa_s->p2p_persistent_group, 0, @@ -8202,11 +8217,14 @@ static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s, wpa_s->p2p_pd_before_go_neg, wpa_s->p2p_go_ht40, wpa_s->p2p_go_vht); + return ret; } int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s) { + int res; + if (!wpa_s->p2p_fallback_to_go_neg || wpa_s->p2p_in_provisioning <= 5) return 0; @@ -8216,9 +8234,11 @@ int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s) wpa_dbg(wpa_s, MSG_DEBUG, "P2P: GO not found for p2p_connect-auto - " "fallback to GO Negotiation"); - wpas_p2p_fallback_to_go_neg(wpa_s, 1); + wpa_msg_global(wpa_s->parent, MSG_INFO, P2P_EVENT_FALLBACK_TO_GO_NEG + "reason=GO-not-found"); + res = wpas_p2p_fallback_to_go_neg(wpa_s, 1); - return 1; + return res == 1 ? 2 : 1; } diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index c1f3efc8..30a66572 100644 --- a/wpa_supplicant/scan.c +++ b/wpa_supplicant/scan.c @@ -1605,8 +1605,8 @@ static int wpa_scan_result_compar(const void *a, const void *b) struct wpa_scan_res **_wb = (void *) b; struct wpa_scan_res *wa = *_wa; struct wpa_scan_res *wb = *_wb; - int wpa_a, wpa_b, maxrate_a, maxrate_b; - int snr_a, snr_b; + int wpa_a, wpa_b; + int snr_a, snr_b, snr_a_full, snr_b_full; /* WPA/WPA2 support preferred */ wpa_a = wpa_scan_get_vendor_ie(wa, WPA_IE_VENDOR_TYPE) != NULL || @@ -1628,22 +1628,22 @@ static int wpa_scan_result_compar(const void *a, const void *b) return -1; if (wa->flags & wb->flags & WPA_SCAN_LEVEL_DBM) { - snr_a = MIN(wa->level - wa->noise, GREAT_SNR); - snr_b = MIN(wb->level - wb->noise, GREAT_SNR); + snr_a_full = wa->snr; + snr_a = MIN(wa->snr, GREAT_SNR); + snr_b_full = wb->snr; + snr_b = MIN(wa->snr, GREAT_SNR); } else { /* Level is not in dBm, so we can't calculate * SNR. Just use raw level (units unknown). */ - snr_a = wa->level; - snr_b = wb->level; + snr_a = snr_a_full = wa->level; + snr_b = snr_b_full = wb->level; } /* if SNR is close, decide by max rate or frequency band */ if ((snr_a && snr_b && abs(snr_b - snr_a) < 5) || (wa->qual && wb->qual && abs(wb->qual - wa->qual) < 10)) { - maxrate_a = wpa_scan_get_max_rate(wa); - maxrate_b = wpa_scan_get_max_rate(wb); - if (maxrate_a != maxrate_b) - return maxrate_b - maxrate_a; + if (wa->est_throughput != wb->est_throughput) + return wb->est_throughput - wa->est_throughput; if (IS_5GHZ(wa->freq) ^ IS_5GHZ(wb->freq)) return IS_5GHZ(wa->freq) ? -1 : 1; } @@ -1651,9 +1651,9 @@ static int wpa_scan_result_compar(const void *a, const void *b) /* all things being equal, use SNR; if SNRs are * identical, use quality values since some drivers may only report * that value and leave the signal level zero */ - if (snr_b == snr_a) + if (snr_b_full == snr_a_full) return wb->qual - wa->qual; - return snr_b - snr_a; + return snr_b_full - snr_a_full; #undef MIN } @@ -1720,20 +1720,21 @@ static void dump_scan_res(struct wpa_scan_results *scan_res) struct wpa_scan_res *r = scan_res->res[i]; u8 *pos; if (r->flags & WPA_SCAN_LEVEL_DBM) { - int snr = r->level - r->noise; int noise_valid = !(r->flags & WPA_SCAN_NOISE_INVALID); wpa_printf(MSG_EXCESSIVE, MACSTR " freq=%d qual=%d " - "noise=%d%s level=%d snr=%d%s flags=0x%x age=%u", + "noise=%d%s level=%d snr=%d%s flags=0x%x age=%u est=%u", MAC2STR(r->bssid), r->freq, r->qual, r->noise, noise_valid ? "" : "~", r->level, - snr, snr >= GREAT_SNR ? "*" : "", r->flags, - r->age); + r->snr, r->snr >= GREAT_SNR ? "*" : "", + r->flags, + r->age, r->est_throughput); } else { wpa_printf(MSG_EXCESSIVE, MACSTR " freq=%d qual=%d " - "noise=%d level=%d flags=0x%x age=%u", + "noise=%d level=%d flags=0x%x age=%u est=%u", MAC2STR(r->bssid), r->freq, r->qual, - r->noise, r->level, r->flags, r->age); + r->noise, r->level, r->flags, r->age, + r->est_throughput); } pos = (u8 *) (r + 1); if (r->ie_len) @@ -1808,6 +1809,180 @@ static void filter_scan_res(struct wpa_supplicant *wpa_s, #define DEFAULT_NOISE_FLOOR_2GHZ (-89) #define DEFAULT_NOISE_FLOOR_5GHZ (-92) +static void scan_snr(struct wpa_scan_res *res) +{ + if (res->flags & WPA_SCAN_NOISE_INVALID) { + res->noise = IS_5GHZ(res->freq) ? + DEFAULT_NOISE_FLOOR_5GHZ : + DEFAULT_NOISE_FLOOR_2GHZ; + } + + if (res->flags & WPA_SCAN_LEVEL_DBM) { + res->snr = res->level - res->noise; + } else { + /* Level is not in dBm, so we can't calculate + * SNR. Just use raw level (units unknown). */ + res->snr = res->level; + } +} + + +static unsigned int max_ht20_rate(int snr) +{ + if (snr < 6) + return 6500; /* HT20 MCS0 */ + if (snr < 8) + return 13000; /* HT20 MCS1 */ + if (snr < 13) + return 19500; /* HT20 MCS2 */ + if (snr < 17) + return 26000; /* HT20 MCS3 */ + if (snr < 20) + return 39000; /* HT20 MCS4 */ + if (snr < 23) + return 52000; /* HT20 MCS5 */ + if (snr < 24) + return 58500; /* HT20 MCS6 */ + return 65000; /* HT20 MCS7 */ +} + + +static unsigned int max_ht40_rate(int snr) +{ + if (snr < 3) + return 13500; /* HT40 MCS0 */ + if (snr < 6) + return 27000; /* HT40 MCS1 */ + if (snr < 10) + return 40500; /* HT40 MCS2 */ + if (snr < 15) + return 54000; /* HT40 MCS3 */ + if (snr < 17) + return 81000; /* HT40 MCS4 */ + if (snr < 22) + return 108000; /* HT40 MCS5 */ + if (snr < 22) + return 121500; /* HT40 MCS6 */ + return 135000; /* HT40 MCS7 */ +} + + +static unsigned int max_vht80_rate(int snr) +{ + if (snr < 1) + return 0; + if (snr < 2) + return 29300; /* VHT80 MCS0 */ + if (snr < 5) + return 58500; /* VHT80 MCS1 */ + if (snr < 9) + return 87800; /* VHT80 MCS2 */ + if (snr < 11) + return 117000; /* VHT80 MCS3 */ + if (snr < 15) + return 175500; /* VHT80 MCS4 */ + if (snr < 16) + return 234000; /* VHT80 MCS5 */ + if (snr < 18) + return 263300; /* VHT80 MCS6 */ + if (snr < 20) + return 292500; /* VHT80 MCS7 */ + if (snr < 22) + return 351000; /* VHT80 MCS8 */ + return 390000; /* VHT80 MCS9 */ +} + + +static void scan_est_throughput(struct wpa_supplicant *wpa_s, + struct wpa_scan_res *res) +{ + enum local_hw_capab capab = wpa_s->hw_capab; + int rate; /* max legacy rate in 500 kb/s units */ + const u8 *ie; + unsigned int est, tmp; + int snr = res->snr; + + if (res->est_throughput) + return; + + /* Get maximum legacy rate */ + rate = wpa_scan_get_max_rate(res); + + /* Limit based on estimated SNR */ + if (rate > 1 * 2 && snr < 1) + rate = 1 * 2; + else if (rate > 2 * 2 && snr < 4) + rate = 2 * 2; + else if (rate > 6 * 2 && snr < 5) + rate = 6 * 2; + else if (rate > 9 * 2 && snr < 6) + rate = 9 * 2; + else if (rate > 12 * 2 && snr < 7) + rate = 12 * 2; + else if (rate > 18 * 2 && snr < 10) + rate = 18 * 2; + else if (rate > 24 * 2 && snr < 11) + rate = 24 * 2; + else if (rate > 36 * 2 && snr < 15) + rate = 36 * 2; + else if (rate > 48 * 2 && snr < 19) + rate = 48 * 2; + else if (rate > 54 * 2 && snr < 21) + rate = 54 * 2; + est = rate * 500; + + if (capab == CAPAB_HT || capab == CAPAB_HT40 || capab == CAPAB_VHT) { + ie = wpa_scan_get_ie(res, WLAN_EID_HT_CAP); + if (ie) { + tmp = max_ht20_rate(snr); + if (tmp > est) + est = tmp; + } + } + + if (capab == CAPAB_HT40 || capab == CAPAB_VHT) { + ie = wpa_scan_get_ie(res, WLAN_EID_HT_OPERATION); + if (ie && ie[1] >= 2 && + (ie[3] & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) { + tmp = max_ht40_rate(snr); + if (tmp > est) + est = tmp; + } + } + + if (capab == CAPAB_VHT) { + /* Use +1 to assume VHT is always faster than HT */ + ie = wpa_scan_get_ie(res, WLAN_EID_VHT_CAP); + if (ie) { + tmp = max_ht20_rate(snr) + 1; + if (tmp > est) + est = tmp; + + ie = wpa_scan_get_ie(res, WLAN_EID_HT_OPERATION); + if (ie && ie[1] >= 2 && + (ie[3] & + HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) { + tmp = max_ht40_rate(snr) + 1; + if (tmp > est) + est = tmp; + } + + ie = wpa_scan_get_ie(res, WLAN_EID_VHT_OPERATION); + if (ie && ie[1] >= 1 && + (ie[2] & VHT_OPMODE_CHANNEL_WIDTH_MASK)) { + tmp = max_vht80_rate(snr) + 1; + if (tmp > est) + est = tmp; + } + } + } + + /* TODO: channel utilization and AP load (e.g., from AP Beacon) */ + + res->est_throughput = est; +} + + /** * wpa_supplicant_get_scan_results - Get scan results * @wpa_s: Pointer to wpa_supplicant data @@ -1844,12 +2019,8 @@ wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s, for (i = 0; i < scan_res->num; i++) { struct wpa_scan_res *scan_res_item = scan_res->res[i]; - if (scan_res_item->flags & WPA_SCAN_NOISE_INVALID) { - scan_res_item->noise = - IS_5GHZ(scan_res_item->freq) ? - DEFAULT_NOISE_FLOOR_5GHZ : - DEFAULT_NOISE_FLOOR_2GHZ; - } + scan_snr(scan_res_item); + scan_est_throughput(wpa_s, scan_res_item); } #ifdef CONFIG_WPS @@ -2036,7 +2207,7 @@ void wpa_scan_free_params(struct wpa_driver_scan_params *params) int wpas_start_pno(struct wpa_supplicant *wpa_s) { - int ret, interval; + int ret, interval, prio; size_t i, num_ssid, num_match_ssid; struct wpa_ssid *ssid; struct wpa_driver_scan_params params; @@ -2101,8 +2272,10 @@ int wpas_start_pno(struct wpa_supplicant *wpa_s) sizeof(struct wpa_driver_scan_filter)); if (params.filter_ssids == NULL) return -1; + i = 0; - ssid = wpa_s->conf->ssid; + prio = 0; + ssid = wpa_s->conf->pssid[prio]; while (ssid) { if (!wpas_network_disabled(wpa_s, ssid)) { if (ssid->scan_ssid && params.num_ssids < num_ssid) { @@ -2120,7 +2293,12 @@ int wpas_start_pno(struct wpa_supplicant *wpa_s) if (i == num_match_ssid) break; } - ssid = ssid->next; + if (ssid->pnext) + ssid = ssid->pnext; + else if (prio + 1 == wpa_s->conf->num_prio) + break; + else + ssid = wpa_s->conf->pssid[++prio]; } if (wpa_s->conf->filter_rssi) diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index 6c057072..17881137 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -207,6 +207,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, struct wpabuf *resp = NULL; u8 ext_capab[18]; int ext_capab_len; + int skip_auth; if (bss == NULL) { wpa_msg(wpa_s, MSG_ERROR, "SME: No scan result available for " @@ -215,6 +216,8 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, return; } + skip_auth = wpa_s->conf->reassoc_same_bss_optim && + wpa_s->reassoc_same_bss; wpa_s->current_bss = bss; os_memset(¶ms, 0, sizeof(params)); @@ -465,7 +468,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, sme_auth_handle_rrm(wpa_s, bss); #ifdef CONFIG_SAE - if (params.auth_alg == WPA_AUTH_ALG_SAE && + if (!skip_auth && params.auth_alg == WPA_AUTH_ALG_SAE && pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, ssid, 0) == 0) { wpa_dbg(wpa_s, MSG_DEBUG, @@ -474,7 +477,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, wpa_s->sme.sae_pmksa_caching = 1; } - if (params.auth_alg == WPA_AUTH_ALG_SAE) { + if (!skip_auth && params.auth_alg == WPA_AUTH_ALG_SAE) { if (start) resp = sme_auth_build_sae_commit(wpa_s, ssid, bss->bssid); @@ -532,6 +535,15 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_P2P */ + if (skip_auth) { + wpa_msg(wpa_s, MSG_DEBUG, + "SME: Skip authentication step on reassoc-to-same-BSS"); + wpabuf_free(resp); + sme_associate(wpa_s, ssid->mode, bss->bssid, WLAN_AUTH_OPEN); + return; + } + + wpa_s->sme.auth_alg = params.auth_alg; if (wpa_drv_authenticate(wpa_s, ¶ms) < 0) { wpa_msg(wpa_s, MSG_INFO, "SME: Authentication request to the " diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index 2f06c35a..5a0af0dc 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -658,6 +658,11 @@ static char ** wpa_cli_complete_set(const char *str, int pos) return NULL; } +static int wpa_cli_cmd_dump(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_ctrl_command(ctrl, "DUMP"); +} + static int wpa_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[]) { @@ -2309,6 +2314,13 @@ static int wpa_cli_cmd_interworking_connect(struct wpa_ctrl *ctrl, int argc, } +static int wpa_cli_cmd_interworking_add_network(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "INTERWORKING_ADD_NETWORK", 1, argc, argv); +} + + static int wpa_cli_cmd_anqp_get(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "ANQP_GET", 2, argc, argv); @@ -2609,6 +2621,9 @@ static struct wpa_cli_cmd wpa_cli_commands[] = { cli_cmd_flag_none, "= set variables (shows list of variables when run without " "arguments)" }, + { "dump", wpa_cli_cmd_dump, NULL, + cli_cmd_flag_none, + "= dump config variables" }, { "get", wpa_cli_cmd_get, NULL, cli_cmd_flag_none, "<name> = get information" }, @@ -2997,6 +3012,9 @@ static struct wpa_cli_cmd wpa_cli_commands[] = { { "interworking_connect", wpa_cli_cmd_interworking_connect, wpa_cli_complete_bss, cli_cmd_flag_none, "<BSSID> = connect using Interworking credentials" }, + { "interworking_add_network", wpa_cli_cmd_interworking_add_network, + wpa_cli_complete_bss, cli_cmd_flag_none, + "<BSSID> = connect using Interworking credentials" }, { "anqp_get", wpa_cli_cmd_anqp_get, wpa_cli_complete_bss, cli_cmd_flag_none, "<addr> <info id>[,<info id>]... = request ANQP information" }, diff --git a/wpa_supplicant/wpa_gui-qt4/wpagui.cpp b/wpa_supplicant/wpa_gui-qt4/wpagui.cpp index 62761764..bc6fa7f4 100644 --- a/wpa_supplicant/wpa_gui-qt4/wpagui.cpp +++ b/wpa_supplicant/wpa_gui-qt4/wpagui.cpp @@ -23,15 +23,14 @@ #include "userdatarequest.h" #include "networkconfig.h" -#if 1 -/* Silence stdout */ -#define printf wpagui_printf -static int wpagui_printf(const char *, ...) -{ - return 0; -} + +#ifndef QT_NO_DEBUG +#define debug(M, ...) qDebug("DEBUG %d: " M, __LINE__, ##__VA_ARGS__) +#else +#define debug(M, ...) do {} while (0) #endif + WpaGui::WpaGui(QApplication *_app, QWidget *parent, const char *, Qt::WFlags) : QMainWindow(parent), app(_app) { @@ -163,8 +162,8 @@ WpaGui::WpaGui(QApplication *_app, QWidget *parent, const char *, Qt::WFlags) timer->start(1000); if (openCtrlConnection(ctrl_iface) < 0) { - printf("Failed to open control connection to " - "wpa_supplicant.\n"); + debug("Failed to open control connection to " + "wpa_supplicant."); } updateStatus(); @@ -295,8 +294,8 @@ int WpaGui::openCtrlConnection(const char *ifname) if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) continue; - printf("Selected interface '%s'\n", - dent->d_name); + debug("Selected interface '%s'", + dent->d_name); ctrl_iface = strdup(dent->d_name); break; } @@ -373,7 +372,7 @@ int WpaGui::openCtrlConnection(const char *ifname) monitor_conn = NULL; } - printf("Trying to connect to '%s'\n", cfile); + debug("Trying to connect to '%s'", cfile); ctrl_conn = wpa_ctrl_open(cfile); if (ctrl_conn == NULL) { free(cfile); @@ -386,7 +385,7 @@ int WpaGui::openCtrlConnection(const char *ifname) return -1; } if (wpa_ctrl_attach(monitor_conn)) { - printf("Failed to attach to wpa_supplicant\n"); + debug("Failed to attach to wpa_supplicant"); wpa_ctrl_close(monitor_conn); monitor_conn = NULL; wpa_ctrl_close(ctrl_conn); @@ -447,9 +446,9 @@ int WpaGui::ctrlRequest(const char *cmd, char *buf, size_t *buflen) return -3; ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), buf, buflen, NULL); if (ret == -2) - printf("'%s' command timed out.\n", cmd); + debug("'%s' command timed out.", cmd); else if (ret < 0) - printf("'%s' command failed.\n", cmd); + debug("'%s' command failed.", cmd); return ret; } @@ -705,13 +704,13 @@ void WpaGui::updateNetworks() void WpaGui::helpIndex() { - printf("helpIndex\n"); + debug("helpIndex"); } void WpaGui::helpContents() { - printf("helpContents\n"); + debug("helpContents"); } @@ -806,9 +805,9 @@ void WpaGui::ping() len = sizeof(buf) - 1; if (ctrlRequest("PING", buf, &len) < 0) { - printf("PING failed - trying to reconnect\n"); + debug("PING failed - trying to reconnect"); if (openCtrlConnection(ctrl_iface) >= 0) { - printf("Reconnected successfully\n"); + debug("Reconnected successfully"); pingsToStatusUpdate = 0; } } @@ -1002,8 +1001,8 @@ void WpaGui::enableNetwork(const QString &sel) if (cmd.contains(QRegExp("^\\d+:"))) cmd.truncate(cmd.indexOf(':')); else if (!cmd.startsWith("all")) { - printf("Invalid editNetwork '%s'\n", - cmd.toAscii().constData()); + debug("Invalid editNetwork '%s'", + cmd.toAscii().constData()); return; } cmd.prepend("ENABLE_NETWORK "); @@ -1021,8 +1020,8 @@ void WpaGui::disableNetwork(const QString &sel) if (cmd.contains(QRegExp("^\\d+:"))) cmd.truncate(cmd.indexOf(':')); else if (!cmd.startsWith("all")) { - printf("Invalid editNetwork '%s'\n", - cmd.toAscii().constData()); + debug("Invalid editNetwork '%s'", + cmd.toAscii().constData()); return; } cmd.prepend("DISABLE_NETWORK "); @@ -1111,8 +1110,8 @@ void WpaGui::removeNetwork(const QString &sel) if (cmd.contains(QRegExp("^\\d+:"))) cmd.truncate(cmd.indexOf(':')); else if (!cmd.startsWith("all")) { - printf("Invalid editNetwork '%s'\n", - cmd.toAscii().constData()); + debug("Invalid editNetwork '%s'", + cmd.toAscii().constData()); return; } cmd.prepend("REMOVE_NETWORK "); @@ -1175,8 +1174,8 @@ int WpaGui::getNetworkDisabled(const QString &sel) size_t reply_len = sizeof(reply) - 1; int pos = cmd.indexOf(':'); if (pos < 0) { - printf("Invalid getNetworkDisabled '%s'\n", - cmd.toAscii().constData()); + debug("Invalid getNetworkDisabled '%s'", + cmd.toAscii().constData()); return -1; } cmd.truncate(pos); @@ -1267,8 +1266,8 @@ void WpaGui::saveConfig() void WpaGui::selectAdapter( const QString & sel ) { if (openCtrlConnection(sel.toAscii().constData()) < 0) - printf("Failed to open control connection to " - "wpa_supplicant.\n"); + debug("Failed to open control connection to " + "wpa_supplicant."); updateStatus(); updateNetworks(); } @@ -1700,13 +1699,13 @@ bool WpaGui::serviceRunning() scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT); if (!scm) { - printf("OpenSCManager failed: %d\n", (int) GetLastError()); + debug("OpenSCManager failed: %d", (int) GetLastError()); return false; } svc = OpenService(scm, WPASVC_NAME, SERVICE_QUERY_STATUS); if (!svc) { - printf("OpenService failed: %d\n\n", (int) GetLastError()); + debug("OpenService failed: %d", (int) GetLastError()); CloseServiceHandle(scm); return false; } diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 6ad09a87..05b785ea 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -1654,6 +1654,13 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, } +static int bss_is_ibss(struct wpa_bss *bss) +{ + return (bss->caps & (IEEE80211_CAP_ESS | IEEE80211_CAP_IBSS)) == + IEEE80211_CAP_IBSS; +} + + void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s, const struct wpa_ssid *ssid, struct hostapd_freq_params *freq) @@ -1662,19 +1669,53 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s, struct hostapd_hw_modes *mode = NULL; int ht40plus[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157, 184, 192 }; + int vht80[] = { 36, 52, 100, 116, 132, 149 }; struct hostapd_channel_data *pri_chan = NULL, *sec_chan = NULL; u8 channel; - int i, chan_idx, ht40 = -1, res; + int i, chan_idx, ht40 = -1, res, obss_scan = 1; unsigned int j; + struct hostapd_freq_params vht_freq; freq->freq = ssid->frequency; + for (j = 0; j < wpa_s->last_scan_res_used; j++) { + struct wpa_bss *bss = wpa_s->last_scan_res[j]; + + if (ssid->mode != WPAS_MODE_IBSS) + break; + + /* Don't adjust control freq in case of fixed_freq */ + if (ssid->fixed_freq) + break; + + if (!bss_is_ibss(bss)) + continue; + + if (ssid->ssid_len == bss->ssid_len && + os_memcmp(ssid->ssid, bss->ssid, bss->ssid_len) == 0) { + wpa_printf(MSG_DEBUG, + "IBSS already found in scan results, adjust control freq: %d", + bss->freq); + freq->freq = bss->freq; + obss_scan = 0; + break; + } + } + /* For IBSS check HT_IBSS flag */ if (ssid->mode == WPAS_MODE_IBSS && !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_HT_IBSS)) return; - hw_mode = ieee80211_freq_to_chan(ssid->frequency, &channel); + if (wpa_s->group_cipher == WPA_CIPHER_WEP40 || + wpa_s->group_cipher == WPA_CIPHER_WEP104 || + wpa_s->pairwise_cipher == WPA_CIPHER_TKIP) { + wpa_printf(MSG_DEBUG, + "IBSS: WEP/TKIP detected, do not try to enable HT"); + return; + } + + hw_mode = ieee80211_freq_to_chan(freq->freq, &channel); for (i = 0; wpa_s->hw.modes && i < wpa_s->hw.num_modes; i++) { if (wpa_s->hw.modes[i].mode == hw_mode) { mode = &wpa_s->hw.modes[i]; @@ -1745,7 +1786,7 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s, break; } - if (freq->sec_channel_offset) { + if (freq->sec_channel_offset && obss_scan) { struct wpa_scan_results *scan_res; scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0); @@ -1782,6 +1823,55 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s, wpa_printf(MSG_DEBUG, "IBSS/mesh: setup freq channel %d, sec_channel_offset %d", freq->channel, freq->sec_channel_offset); + + /* Not sure if mesh is ready for VHT */ + if (ssid->mode != WPAS_MODE_IBSS) + return; + + /* For IBSS check VHT_IBSS flag */ + if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_VHT_IBSS)) + return; + + vht_freq = *freq; + + vht_freq.vht_enabled = vht_supported(mode); + if (!vht_freq.vht_enabled) + return; + + /* setup center_freq1, bandwidth */ + for (j = 0; j < ARRAY_SIZE(vht80); j++) { + if (freq->channel >= vht80[j] && + freq->channel < vht80[j] + 16) + break; + } + + if (j == ARRAY_SIZE(vht80)) + return; + + for (i = vht80[j]; i < vht80[j] + 16; i += 4) { + struct hostapd_channel_data *chan; + + chan = hw_get_channel_chan(mode, i, NULL); + if (!chan) + return; + + /* Back to HT configuration if channel not usable */ + if (chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR)) + return; + } + + if (hostapd_set_freq_params(&vht_freq, mode->mode, freq->freq, + freq->channel, freq->ht_enabled, + vht_freq.vht_enabled, + freq->sec_channel_offset, + VHT_CHANWIDTH_80MHZ, + vht80[i] + 6, 0, 0) != 0) + return; + + *freq = vht_freq; + + wpa_printf(MSG_DEBUG, "IBSS: VHT setup freq cf1 %d, cf2 %d, bw %d", + freq->center_freq1, freq->center_freq2, freq->bandwidth); } @@ -2114,6 +2204,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) ibss_mesh_setup_freq(wpa_s, ssid, ¶ms.freq); if (ssid->mode == WPAS_MODE_IBSS) { + params.fixed_freq = ssid->fixed_freq; if (ssid->beacon_int) params.beacon_int = ssid->beacon_int; else @@ -3980,6 +4071,23 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, wpa_s->hw.modes = wpa_drv_get_hw_feature_data(wpa_s, &wpa_s->hw.num_modes, &wpa_s->hw.flags); + if (wpa_s->hw.modes) { + u16 i; + + for (i = 0; i < wpa_s->hw.num_modes; i++) { + if (wpa_s->hw.modes[i].vht_capab) { + wpa_s->hw_capab = CAPAB_VHT; + break; + } + + if (wpa_s->hw.modes[i].ht_capab & + HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) + wpa_s->hw_capab = CAPAB_HT40; + else if (wpa_s->hw.modes[i].ht_capab && + wpa_s->hw_capab == CAPAB_NO_HT_VHT) + wpa_s->hw_capab = CAPAB_HT; + } + } capa_res = wpa_drv_get_capa(wpa_s, &capa); if (capa_res == 0) { diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index c80a6209..7949a018 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -712,6 +712,7 @@ struct wpa_supplicant { int mesh_if_idx; unsigned int mesh_if_created:1; unsigned int mesh_ht_enabled:1; + int mesh_auth_block_duration; /* sec */ #endif /* CONFIG_MESH */ unsigned int off_channel_freq; @@ -887,6 +888,12 @@ struct wpa_supplicant { u16 num_modes; u16 flags; } hw; + enum local_hw_capab { + CAPAB_NO_HT_VHT, + CAPAB_HT, + CAPAB_HT40, + CAPAB_VHT, + } hw_capab; #ifdef CONFIG_MACSEC struct ieee802_1x_kay *kay; #endif /* CONFIG_MACSEC */ |
