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>
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 95fbe78..0f82af9 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -105,6 +105,7 @@
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 @@
$(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 @@
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 5c1e4f9..a1d96fb 100644
--- a/wpa_supplicant/README-P2P
+++ b/wpa_supplicant/README-P2P
@@ -73,7 +73,7 @@
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 @@
(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 @@
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 @@
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 @@
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 [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 @@
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 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 65532e3..f2c60e7 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -265,6 +265,17 @@
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 @@
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 4d80c7a..6a11834 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -80,4 +80,6 @@
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 1798439..b4c47e2 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 @@
#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 @@
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 @@
}
#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 @@
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 @@
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 4a624c5..634aa3c 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 @@
/** 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 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 @@
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 @@
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 1ffc2dc..8e6cd20 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1896,6 +1896,7 @@
{ 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 @@
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 @@
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 @@
#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 @@
{ 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 @@
{ 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 @@
#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 6adf1eb..34b754e 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 @@
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 @@
* (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 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 b15207d..3d3a6e4 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 f744895..7c826cf 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -420,6 +420,11 @@
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 c59ccc3..ec198b2 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -498,6 +498,8 @@
#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 @@
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_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 @@
}
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 @@
(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 @@
#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 @@
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 @@
}
#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 @@
/* <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_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 @@
"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 @@
} 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 @@
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 @@
} 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 539832c..1c46d35 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -175,6 +175,15 @@
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 @@
#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 @@
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 @@
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 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 @@
* interface, do not notify other interfaces to avoid concurrent
* operations during a connection attempt.
*/
- return;
+ return 0;
}
/*
@@ -1526,6 +1559,8 @@
_wpa_supplicant_event_scan_results(ifs, data, 0);
}
}
+
+ return 0;
}
#endif /* CONFIG_NO_SCAN_PROCESSING */
@@ -3092,7 +3127,8 @@
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 @@
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 eb18ed2..b9cd681 100644
--- a/wpa_supplicant/hs20_supplicant.c
+++ b/wpa_supplicant/hs20_supplicant.c
@@ -380,6 +380,11 @@
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 5b66211..90b2991 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -955,7 +955,7 @@
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 @@
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 @@
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_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 @@
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 @@
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 @@
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 @@
(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 @@
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 @@
}
-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 @@
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 @@
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 38ef745..3743dc0 100644
--- a/wpa_supplicant/interworking.h
+++ b/wpa_supplicant/interworking.h
@@ -24,7 +24,8 @@
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 da4cb03..936002d 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 @@
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 @@
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 bf1836a..ea7dbdb 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -764,3 +764,22 @@
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 7fb1f58..b268332 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -131,5 +131,7 @@
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 9e1d665..5e6646e 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -117,8 +117,8 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
-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 @@
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 @@
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 c1f3efc..30a6657 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -1605,8 +1605,8 @@
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 @@
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 @@
/* 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 @@
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 @@
#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 @@
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 @@
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 @@
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 @@
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 6c05707..1788113 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -207,6 +207,7 @@
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 @@
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 @@
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 @@
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 @@
}
#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 2f06c35..5a0af0d 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -658,6 +658,11 @@
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_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 @@
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 @@
{ "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 6276176..bc6fa7f 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 @@
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 @@
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 @@
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 @@
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 @@
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::helpIndex()
{
- printf("helpIndex\n");
+ debug("helpIndex");
}
void WpaGui::helpContents()
{
- printf("helpContents\n");
+ debug("helpContents");
}
@@ -806,9 +805,9 @@
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 @@
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 @@
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 @@
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 @@
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::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 @@
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 6ad09a8..05b785e 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -1654,6 +1654,13 @@
}
+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 @@
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 @@
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 @@
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 @@
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 @@
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 c80a620..7949a01 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -712,6 +712,7 @@
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 @@
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 */