aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Shmidt <dimitrysh@google.com>2015-06-23 11:21:28 -0700
committerDmitry Shmidt <dimitrysh@google.com>2015-06-23 11:21:28 -0700
commita3dc30964aa24aea2b518246f6812663a1103490 (patch)
tree8ac6b6c44b68ed0823ebf7fafd9b1ca85589d05f
parent7a53dbb56693ee9f55c0cab1a8297436511e8613 (diff)
downloadandroid_external_wpa_supplicant_8-a3dc30964aa24aea2b518246f6812663a1103490.tar.gz
android_external_wpa_supplicant_8-a3dc30964aa24aea2b518246f6812663a1103490.tar.bz2
android_external_wpa_supplicant_8-a3dc30964aa24aea2b518246f6812663a1103490.zip
Cumulative patch from commit f43c1ae7989c38fe15756f12a9196a1cf798b4d7
f43c1ae P2P: Handle P2P Device dedicated interface parent removal 1ac977b nl8021: Allow sending wowlan configuration on any interface 4899702 nl80211: Remove android_genl_ctrl_resolve() 38dcc86 P2P: Consider ht/vht on P2P_GROUP_ADD command (with no params) 29292d5 ctrl_iface: Make p2p_ctrl_group_add() more robust e4a80d8 P2P: Fix secondary channel selection for HT40 4e71758 dbus: Add RemoveClient method to remove a client from local GO f0a79c9 D-Bus: Fix wpas_dbus_register_peer() documentation 95d62a6 D-Bus: Add missing params in WPS function documentation 790429b D-Bus: Fix function documentation for wpas_dbus_signal_p2p_go_neg_resp() 92fe746 D-Bus: Add function documentation for wpas_dbus_signal_p2p_go_neg_req() e1dffa3 P2P: Fix PBC overlap detection de7b02f P2P: Use the P2P Device interface in wpas_p2p_fallback_to_go_neg() 6b5147a P2P: Fix memory leak in p2p_process_nfc_connection_handover() 33ba27d EAP-FAST peer: Stop immediately on key derivation failure 144b6a0 OpenSSL: Fix memory leak on an openssl_tls_prf() error path 50a9efe P2PS: Fix Probe Response frame building in error cases 509f269 P2PS: Fix org.wi-fi.wfds matching when building the response 5fa5f84 P2PS: Add more debug prints for service info building fdde3db P2PS: Remove unnecessary service hash filtering from p2p_reply_probe() f2e0eec P2PS: Do not ignore other hashes if org.wi-fi.wfds hash is included ebdc32f P2PS: Fix service hash matching for org.wi-fi.wfds 24533f7 P2PS: Fix p2p_find handling to allow "wildcard" with other hash values f33a31b P2PS: Verify service name length in P2P_FIND command 129b621 P2PS: Fix P2P_FIND seek parameter parsing 83e520e P2PS: Add a wildcard with other advertised service info c5d3cad P2PS: Re-factor p2p_buf_add_service_instance function 13f6f61 wpa_cli: Fix process termination in wpa_cli action mode case b4c0f58 Clear allocated debug message buffers explicitly 14fd033 Clear control interface command explicitly from stack d95c599 P2P: Fix group interface addition failure properly for concurrent case e12c400 P2PS: Refactor p2p_data::query_hash and p2p_data::query_count use 4839da4 P2P: Add vendor elements into Invitation Response frames 886f583 P2PS: Delete p2ps_svc_found from struct p2p_data 3f048aa P2PS: Add a function to free a PD context 8f52409 P2P: Prefer direct Probe Response frames over GO's client list 4e8817f P2P: Use more precise device timestamping for group clients 0799b3f P2P: Specify frequency when sending Probe Response frame 5d180a7 drivers: Add freq parameter to send_mlme() function 5143e7e P2P: Fix return value of p2p_reply_probe() and p2p_probe_req_rx() 07c1e98 P2PS: Enable Probe Request frame processing by P2P Client 734ddf6 P2P: Add rx_freq parameter to Probe Request frame handler e6012e8 P2P: Update target GO Device Address from BSS entry during join a9a4841 Remove duplicated country code from operating class lists 132dfbe Fix removal of tagged interface and bridge when multiple BSS share them e11776a Combine multiple function calls to a single statement b649c0a dbus: Add Reconnect command to D-Bus Interface f4a234a doc: Update D-Bus GONegotiationRequest Signal: add device_go_intent 0c9fb14 P2P: Add Operating class 125 for P2P supported channels Change-Id: I782c1403985248ff994f484282efa6519fd369e9 Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
-rw-r--r--hostapd/Android.mk1
-rw-r--r--hostapd/Makefile1
-rw-r--r--src/ap/ap_config.h3
-rw-r--r--src/ap/ap_drv_ops.c2
-rw-r--r--src/ap/hostapd.h3
-rw-r--r--src/ap/vlan_init.c121
-rw-r--r--src/common/common_module_tests.c37
-rw-r--r--src/common/ieee802_11_common.c11
-rw-r--r--src/crypto/tls_openssl.c5
-rw-r--r--src/drivers/driver.h4
-rw-r--r--src/drivers/driver_atheros.c2
-rw-r--r--src/drivers/driver_hostap.c3
-rw-r--r--src/drivers/driver_nl80211.c8
-rw-r--r--src/drivers/driver_nl80211.h1
-rw-r--r--src/drivers/driver_nl80211_android.c30
-rw-r--r--src/eap_peer/eap_fast.c32
-rw-r--r--src/p2p/p2p.c173
-rw-r--r--src/p2p/p2p.h13
-rw-r--r--src/p2p/p2p_build.c322
-rw-r--r--src/p2p/p2p_dev_disc.c2
-rw-r--r--src/p2p/p2p_go_neg.c2
-rw-r--r--src/p2p/p2p_i.h17
-rw-r--r--src/p2p/p2p_invitation.c6
-rw-r--r--src/p2p/p2p_pd.c24
-rw-r--r--src/p2p/p2p_utils.c9
-rw-r--r--src/utils/wpa_debug.c16
-rw-r--r--wpa_supplicant/ap.c7
-rw-r--r--wpa_supplicant/config.c1
-rw-r--r--wpa_supplicant/config.h12
-rw-r--r--wpa_supplicant/config_file.c3
-rw-r--r--wpa_supplicant/ctrl_iface.c71
-rw-r--r--wpa_supplicant/ctrl_iface_unix.c14
-rw-r--r--wpa_supplicant/dbus/dbus_new.c36
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers.c24
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers.h3
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers_p2p.c58
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers_p2p.h3
-rw-r--r--wpa_supplicant/driver_i.h6
-rw-r--r--wpa_supplicant/events.c32
-rw-r--r--wpa_supplicant/main.c2
-rw-r--r--wpa_supplicant/p2p_supplicant.c69
-rw-r--r--wpa_supplicant/p2p_supplicant.h5
-rw-r--r--wpa_supplicant/wpa_cli.c66
-rw-r--r--wpa_supplicant/wpa_supplicant.c27
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h26
-rw-r--r--wpa_supplicant/wps_supplicant.c57
46 files changed, 937 insertions, 433 deletions
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index 10f50d85..49f43f19 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -892,6 +892,7 @@ endif
OBJS_c = hostapd_cli.c src/common/wpa_ctrl.c src/utils/os_$(CONFIG_OS).c
OBJS_c += src/utils/eloop.c
+OBJS_c += src/utils/common.c
ifdef CONFIG_WPA_TRACE
OBJS_c += src/utils/trace.c
endif
diff --git a/hostapd/Makefile b/hostapd/Makefile
index 3c7bd6f9..d4fd36e0 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -108,6 +108,7 @@ LIBS_n += -lrt
endif
OBJS += ../src/utils/common.o
+OBJS_c += ../src/utils/common.o
OBJS += ../src/utils/wpa_debug.o
OBJS_c += ../src/utils/wpa_debug.o
OBJS += ../src/utils/wpabuf.o
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index c3573a48..c14eeda4 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -117,9 +117,6 @@ struct hostapd_vlan {
int dynamic_vlan;
#ifdef CONFIG_FULL_DYNAMIC_VLAN
-#define DVLAN_CLEAN_BR 0x1
-#define DVLAN_CLEAN_VLAN 0x2
-#define DVLAN_CLEAN_VLAN_PORT 0x4
#define DVLAN_CLEAN_WLAN_PORT 0x8
int clean;
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 60c8f8c7..f3f7edd1 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -633,7 +633,7 @@ int hostapd_drv_send_mlme(struct hostapd_data *hapd,
{
if (hapd->driver == NULL || hapd->driver->send_mlme == NULL)
return 0;
- return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack);
+ return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0);
}
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 75cc24ed..be5c7a89 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -49,6 +49,9 @@ struct hapd_interfaces {
struct hostapd_iface **iface;
size_t terminate_on_error;
+#ifndef CONFIG_NO_VLAN
+ struct dynamic_iface *vlan_priv;
+#endif /* CONFIG_NO_VLAN */
};
enum hostapd_chan_status {
diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c
index b89a1f43..fd1c8dda 100644
--- a/src/ap/vlan_init.c
+++ b/src/ap/vlan_init.c
@@ -35,6 +35,90 @@ struct full_dynamic_vlan {
int s; /* socket on which to listen for new/removed interfaces. */
};
+#define DVLAN_CLEAN_BR 0x1
+#define DVLAN_CLEAN_VLAN 0x2
+#define DVLAN_CLEAN_VLAN_PORT 0x4
+
+struct dynamic_iface {
+ char ifname[IFNAMSIZ + 1];
+ int usage;
+ int clean;
+ struct dynamic_iface *next;
+};
+
+
+/* Increment ref counter for ifname and add clean flag.
+ * If not in list, add it only if some flags are given.
+ */
+static void dyn_iface_get(struct hostapd_data *hapd, const char *ifname,
+ int clean)
+{
+ struct dynamic_iface *next, **dynamic_ifaces;
+ struct hapd_interfaces *interfaces;
+
+ interfaces = hapd->iface->interfaces;
+ dynamic_ifaces = &interfaces->vlan_priv;
+
+ for (next = *dynamic_ifaces; next; next = next->next) {
+ if (os_strcmp(ifname, next->ifname) == 0)
+ break;
+ }
+
+ if (next) {
+ next->usage++;
+ next->clean |= clean;
+ return;
+ }
+
+ if (!clean)
+ return;
+
+ next = os_zalloc(sizeof(*next));
+ if (!next)
+ return;
+ os_strlcpy(next->ifname, ifname, sizeof(next->ifname));
+ next->usage = 1;
+ next->clean = clean;
+ next->next = *dynamic_ifaces;
+ *dynamic_ifaces = next;
+}
+
+
+/* Decrement reference counter for given ifname.
+ * Return clean flag iff reference counter was decreased to zero, else zero
+ */
+static int dyn_iface_put(struct hostapd_data *hapd, const char *ifname)
+{
+ struct dynamic_iface *next, *prev = NULL, **dynamic_ifaces;
+ struct hapd_interfaces *interfaces;
+ int clean;
+
+ interfaces = hapd->iface->interfaces;
+ dynamic_ifaces = &interfaces->vlan_priv;
+
+ for (next = *dynamic_ifaces; next; next = next->next) {
+ if (os_strcmp(ifname, next->ifname) == 0)
+ break;
+ prev = next;
+ }
+
+ if (!next)
+ return 0;
+
+ next->usage--;
+ if (next->usage)
+ return 0;
+
+ if (prev)
+ prev->next = next->next;
+ else
+ *dynamic_ifaces = next->next;
+ clean = next->clean;
+ os_free(next);
+
+ return clean;
+}
+
static int ifconfig_helper(const char *if_name, int up)
{
@@ -482,6 +566,7 @@ static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
struct hostapd_vlan *vlan = hapd->conf->vlan;
char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
int vlan_naming = hapd->conf->ssid.vlan_naming;
+ int clean;
wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
@@ -502,8 +587,8 @@ static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
"brvlan%d", vlan->vlan_id);
}
- if (!br_addbr(br_name))
- vlan->clean |= DVLAN_CLEAN_BR;
+ dyn_iface_get(hapd, br_name,
+ br_addbr(br_name) ? 0 : DVLAN_CLEAN_BR);
ifconfig_up(br_name);
@@ -519,13 +604,16 @@ static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
sizeof(vlan_ifname),
"vlan%d", vlan->vlan_id);
+ clean = 0;
ifconfig_up(tagged_interface);
if (!vlan_add(tagged_interface, vlan->vlan_id,
vlan_ifname))
- vlan->clean |= DVLAN_CLEAN_VLAN;
+ clean |= DVLAN_CLEAN_VLAN;
if (!br_addif(br_name, vlan_ifname))
- vlan->clean |= DVLAN_CLEAN_VLAN_PORT;
+ clean |= DVLAN_CLEAN_VLAN_PORT;
+
+ dyn_iface_get(hapd, vlan_ifname, clean);
ifconfig_up(vlan_ifname);
}
@@ -549,13 +637,15 @@ static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
int vlan_naming = hapd->conf->ssid.vlan_naming;
+ int clean;
wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname);
first = prev = vlan;
while (vlan) {
- if (os_strcmp(ifname, vlan->ifname) == 0) {
+ if (os_strcmp(ifname, vlan->ifname) == 0 &&
+ vlan->configured) {
if (hapd->conf->vlan_bridge[0]) {
os_snprintf(br_name, sizeof(br_name), "%s%d",
hapd->conf->vlan_bridge,
@@ -583,20 +673,27 @@ static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
os_snprintf(vlan_ifname,
sizeof(vlan_ifname),
"vlan%d", vlan->vlan_id);
- if (vlan->clean & DVLAN_CLEAN_VLAN_PORT)
+
+ clean = dyn_iface_put(hapd, vlan_ifname);
+
+ if (clean & DVLAN_CLEAN_VLAN_PORT)
br_delif(br_name, vlan_ifname);
- ifconfig_down(vlan_ifname);
- if (vlan->clean & DVLAN_CLEAN_VLAN)
+ if (clean & DVLAN_CLEAN_VLAN) {
+ ifconfig_down(vlan_ifname);
vlan_rem(vlan_ifname);
+ }
}
- if ((vlan->clean & DVLAN_CLEAN_BR) &&
+ clean = dyn_iface_put(hapd, br_name);
+ if ((clean & DVLAN_CLEAN_BR) &&
br_getnumports(br_name) == 0) {
ifconfig_down(br_name);
br_delbr(br_name);
}
+ }
+ if (os_strcmp(ifname, vlan->ifname) == 0) {
if (vlan == first) {
hapd->conf->vlan = vlan->next;
} else {
@@ -975,8 +1072,12 @@ int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
if (vlan == NULL)
return 1;
- if (vlan->dynamic_vlan == 0)
+ if (vlan->dynamic_vlan == 0) {
hostapd_vlan_if_remove(hapd, vlan->ifname);
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+ vlan_dellink(vlan->ifname, hapd);
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+ }
return 0;
}
diff --git a/src/common/common_module_tests.c b/src/common/common_module_tests.c
index 56b11220..d69448bd 100644
--- a/src/common/common_module_tests.c
+++ b/src/common/common_module_tests.c
@@ -1,6 +1,6 @@
/*
* common module tests
- * Copyright (c) 2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2014-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,6 +10,8 @@
#include "utils/common.h"
#include "ieee802_11_common.h"
+#include "ieee802_11_defs.h"
+#include "gas.h"
#include "wpa_common.h"
@@ -46,6 +48,10 @@ static const struct ieee802_11_parse_test_data parse_tests[] = {
{ (u8 *) "\x6e\x00", 2, ParseOK, 1 },
{ (u8 *) "\xc7\x00", 2, ParseOK, 1 },
{ (u8 *) "\xc7\x01\x00", 3, ParseOK, 1 },
+ { (u8 *) "\x03\x00\x2a\x00\x36\x00\x37\x00\x38\x00\x2d\x00\x3d\x00\xbf\x00\xc0\x00",
+ 18, ParseOK, 9 },
+ { (u8 *) "\x8b\x00", 2, ParseOK, 1 },
+ { (u8 *) "\xdd\x04\x00\x90\x4c\x04", 6, ParseUnknown, 1 },
{ NULL, 0, ParseOK, 0 }
};
@@ -158,6 +164,34 @@ static int rsn_ie_parse_tests(void)
}
+static int gas_tests(void)
+{
+ struct wpabuf *buf;
+
+ wpa_printf(MSG_INFO, "gas tests");
+ gas_anqp_set_len(NULL);
+
+ buf = wpabuf_alloc(1);
+ if (buf == NULL)
+ return -1;
+ gas_anqp_set_len(buf);
+ wpabuf_free(buf);
+
+ buf = wpabuf_alloc(20);
+ if (buf == NULL)
+ return -1;
+ wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
+ wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_REQ);
+ wpabuf_put_u8(buf, 0);
+ wpabuf_put_be32(buf, 0);
+ wpabuf_put_u8(buf, 0);
+ gas_anqp_set_len(buf);
+ wpabuf_free(buf);
+
+ return 0;
+}
+
+
int common_module_tests(void)
{
int ret = 0;
@@ -165,6 +199,7 @@ int common_module_tests(void)
wpa_printf(MSG_INFO, "common module tests");
if (ieee802_11_parse_tests() < 0 ||
+ gas_tests() < 0 ||
rsn_ie_parse_tests() < 0)
ret = -1;
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index e23007a8..82dd7074 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -580,7 +580,7 @@ static const char *const jp_op_class_cc[] = {
};
static const char *const cn_op_class_cc[] = {
- "CN", "CA", NULL
+ "CN", NULL
};
@@ -630,6 +630,10 @@ static int ieee80211_chan_to_freq_us(u8 op_class, u8 chan)
if (chan < 149 || chan > 161)
return -1;
return 5000 + 5 * chan;
+ case 5: /* channels 149,153,157,161,165 */
+ if (chan < 149 || chan > 165)
+ return -1;
+ return 5000 + 5 * chan;
case 34: /* 60 GHz band, channels 1..3 */
if (chan < 1 || chan > 3)
return -1;
@@ -782,12 +786,15 @@ static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan)
return -1;
return 5000 + 5 * chan;
case 124: /* channels 149,153,157,161 */
- case 125: /* channels 149,153,157,161,165,169 */
case 126: /* channels 149,157; 40 MHz */
case 127: /* channels 153,161; 40 MHz */
if (chan < 149 || chan > 161)
return -1;
return 5000 + 5 * chan;
+ case 125: /* channels 149,153,157,161,165,169 */
+ if (chan < 149 || chan > 169)
+ return -1;
+ return 5000 + 5 * chan;
case 128: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
case 130: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
if (chan < 36 || chan > 161)
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index 8f28ca82..37ab0005 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -2770,8 +2770,11 @@ static int openssl_tls_prf(void *tls_ctx, struct tls_connection *conn,
}
rnd = os_malloc(2 * SSL3_RANDOM_SIZE);
- if (rnd == NULL)
+ if (!rnd) {
+ os_free(tmp_out);
return -1;
+ }
+
if (server_random_first) {
os_memcpy(rnd, ssl->s3->server_random, SSL3_RANDOM_SIZE);
os_memcpy(rnd + SSL3_RANDOM_SIZE, ssl->s3->client_random,
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 03243399..d452d8ca 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1940,10 +1940,12 @@ struct wpa_driver_ops {
* @data: IEEE 802.11 management frame with IEEE 802.11 header
* @data_len: Size of the management frame
* @noack: Do not wait for this frame to be acked (disable retries)
+ * @freq: Frequency (in MHz) to send the frame on, or 0 to let the
+ * driver decide
* Returns: 0 on success, -1 on failure
*/
int (*send_mlme)(void *priv, const u8 *data, size_t data_len,
- int noack);
+ int noack, unsigned int freq);
/**
* update_ft_ies - Update FT (IEEE 802.11r) IEs
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index b8e78643..aaada0a4 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -1840,7 +1840,7 @@ static int atheros_set_ap(void *priv, struct wpa_driver_ap_params *params)
#ifdef CONFIG_IEEE80211R
static int atheros_send_mgmt(void *priv, const u8 *frm, size_t data_len,
- int noack)
+ int noack, unsigned int freq)
{
struct atheros_driver_data *drv = priv;
u8 buf[1510];
diff --git a/src/drivers/driver_hostap.c b/src/drivers/driver_hostap.c
index 84b98fb8..14c52d2c 100644
--- a/src/drivers/driver_hostap.c
+++ b/src/drivers/driver_hostap.c
@@ -266,7 +266,8 @@ static int hostap_init_sockets(struct hostap_driver_data *drv, u8 *own_addr)
}
-static int hostap_send_mlme(void *priv, const u8 *msg, size_t len, int noack)
+static int hostap_send_mlme(void *priv, const u8 *msg, size_t len, int noack,
+ unsigned int freq)
{
struct hostap_driver_data *drv = priv;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) msg;
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 590731d2..20f53218 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -87,7 +87,6 @@ static void nl80211_handle_destroy(struct nl_handle *handle)
#undef nl_socket_set_nonblocking
#define nl_socket_set_nonblocking(h) android_nl_socket_set_nonblocking(h)
-#define genl_ctrl_resolve android_genl_ctrl_resolve
#endif /* ANDROID */
@@ -7245,11 +7244,12 @@ static int driver_nl80211_if_remove(void *priv, enum wpa_driver_if_type type,
static int driver_nl80211_send_mlme(void *priv, const u8 *data,
- size_t data_len, int noack)
+ size_t data_len, int noack,
+ unsigned int freq)
{
struct i802_bss *bss = priv;
return wpa_driver_nl80211_send_mlme(bss, data, data_len, noack,
- 0, 0, 0, 0);
+ freq, 0, 0, 0);
}
@@ -7807,7 +7807,7 @@ static int nl80211_set_wowlan(void *priv,
wpa_printf(MSG_DEBUG, "nl80211: Setting wowlan");
- if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_WOWLAN)) ||
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_SET_WOWLAN)) ||
!(wowlan_triggers = nla_nest_start(msg,
NL80211_ATTR_WOWLAN_TRIGGERS)) ||
(triggers->any &&
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index b5071b4a..acfe959e 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -232,7 +232,6 @@ int process_bss_event(struct nl_msg *msg, void *arg);
#ifdef ANDROID
int android_nl_socket_set_nonblocking(struct nl_handle *handle);
-int android_genl_ctrl_resolve(struct nl_handle *handle, const char *name);
int android_pno_start(struct i802_bss *bss,
struct wpa_driver_scan_params *params);
int android_pno_stop(struct i802_bss *bss);
diff --git a/src/drivers/driver_nl80211_android.c b/src/drivers/driver_nl80211_android.c
index 3cc9a658..f3a39f66 100644
--- a/src/drivers/driver_nl80211_android.c
+++ b/src/drivers/driver_nl80211_android.c
@@ -188,33 +188,3 @@ int android_nl_socket_set_nonblocking(struct nl_handle *handle)
}
-int android_genl_ctrl_resolve(struct nl_handle *handle, const char *name)
-{
- /*
- * Android ICS has very minimal genl_ctrl_resolve() implementation, so
- * need to work around that.
- */
- struct nl_cache *cache = NULL;
- struct genl_family *nl80211 = NULL;
- int id = -1;
-
- if (genl_ctrl_alloc_cache(handle, &cache) < 0) {
- wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
- "netlink cache");
- goto fail;
- }
-
- nl80211 = genl_ctrl_search_by_name(cache, name);
- if (nl80211 == NULL)
- goto fail;
-
- id = genl_family_get_id(nl80211);
-
-fail:
- if (nl80211)
- genl_family_put(nl80211);
- if (cache)
- nl_cache_free(cache);
-
- return id;
-}
diff --git a/src/eap_peer/eap_fast.c b/src/eap_peer/eap_fast.c
index 248b57b2..f636e74d 100644
--- a/src/eap_peer/eap_fast.c
+++ b/src/eap_peer/eap_fast.c
@@ -267,8 +267,8 @@ static int eap_fast_derive_msk(struct eap_fast_data *data)
}
-static void eap_fast_derive_key_auth(struct eap_sm *sm,
- struct eap_fast_data *data)
+static int eap_fast_derive_key_auth(struct eap_sm *sm,
+ struct eap_fast_data *data)
{
u8 *sks;
@@ -281,7 +281,7 @@ static void eap_fast_derive_key_auth(struct eap_sm *sm,
if (sks == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive "
"session_key_seed");
- return;
+ return -1;
}
/*
@@ -294,11 +294,12 @@ static void eap_fast_derive_key_auth(struct eap_sm *sm,
data->simck_idx = 0;
os_memcpy(data->simck, sks, EAP_FAST_SIMCK_LEN);
os_free(sks);
+ return 0;
}
-static void eap_fast_derive_key_provisioning(struct eap_sm *sm,
- struct eap_fast_data *data)
+static int eap_fast_derive_key_provisioning(struct eap_sm *sm,
+ struct eap_fast_data *data)
{
os_free(data->key_block_p);
data->key_block_p = (struct eap_fast_key_block_provisioning *)
@@ -307,7 +308,7 @@ static void eap_fast_derive_key_provisioning(struct eap_sm *sm,
sizeof(*data->key_block_p));
if (data->key_block_p == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive key block");
- return;
+ return -1;
}
/*
* RFC 4851, Section 5.2:
@@ -326,15 +327,19 @@ static void eap_fast_derive_key_provisioning(struct eap_sm *sm,
wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: client_challenge",
data->key_block_p->client_challenge,
sizeof(data->key_block_p->client_challenge));
+ return 0;
}
-static void eap_fast_derive_keys(struct eap_sm *sm, struct eap_fast_data *data)
+static int eap_fast_derive_keys(struct eap_sm *sm, struct eap_fast_data *data)
{
+ int res;
+
if (data->anon_provisioning)
- eap_fast_derive_key_provisioning(sm, data);
+ res = eap_fast_derive_key_provisioning(sm, data);
else
- eap_fast_derive_key_auth(sm, data);
+ res = eap_fast_derive_key_auth(sm, data);
+ return res;
}
@@ -1586,7 +1591,14 @@ static struct wpabuf * eap_fast_process(struct eap_sm *sm, void *priv,
} else
data->anon_provisioning = 0;
data->resuming = 0;
- eap_fast_derive_keys(sm, data);
+ if (eap_fast_derive_keys(sm, data) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-FAST: Could not derive keys");
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ wpabuf_free(resp);
+ return NULL;
+ }
}
if (res == 2) {
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index c02044b1..16ffac43 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -297,7 +297,7 @@ static void p2p_listen_in_find(struct p2p_data *p2p, int dev_disc)
return;
}
- ies = p2p_build_probe_resp_ies(p2p);
+ ies = p2p_build_probe_resp_ies(p2p, NULL, 0);
if (ies == NULL)
return;
@@ -346,7 +346,7 @@ int p2p_listen(struct p2p_data *p2p, unsigned int timeout)
return 0;
}
- ies = p2p_build_probe_resp_ies(p2p);
+ ies = p2p_build_probe_resp_ies(p2p, NULL, 0);
if (ies == NULL)
return -1;
@@ -468,7 +468,8 @@ static void p2p_copy_client_info(struct p2p_device *dev,
static int p2p_add_group_clients(struct p2p_data *p2p, const u8 *go_dev_addr,
const u8 *go_interface_addr, int freq,
- const u8 *gi, size_t gi_len)
+ const u8 *gi, size_t gi_len,
+ struct os_reltime *rx_time)
{
struct p2p_group_info info;
size_t c;
@@ -536,10 +537,11 @@ static int p2p_add_group_clients(struct p2p_data *p2p, const u8 *go_dev_addr,
os_memcpy(dev->interface_addr, cli->p2p_interface_addr,
ETH_ALEN);
- os_get_reltime(&dev->last_seen);
+ os_memcpy(&dev->last_seen, rx_time, sizeof(struct os_reltime));
os_memcpy(dev->member_in_go_dev, go_dev_addr, ETH_ALEN);
os_memcpy(dev->member_in_go_iface, go_interface_addr,
ETH_ALEN);
+ dev->flags |= P2P_DEV_LAST_SEEN_AS_GROUP_CLIENT;
}
return 0;
@@ -758,22 +760,30 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
/*
* Update the device entry only if the new peer
- * entry is newer than the one previously stored.
+ * entry is newer than the one previously stored, or if
+ * the device was previously seen as a P2P Client in a group
+ * and the new entry isn't older than a threshold.
*/
if (dev->last_seen.sec > 0 &&
- os_reltime_before(rx_time, &dev->last_seen)) {
- p2p_dbg(p2p, "Do not update peer entry based on old frame (rx_time=%u.%06u last_seen=%u.%06u)",
+ os_reltime_before(rx_time, &dev->last_seen) &&
+ (!(dev->flags & P2P_DEV_LAST_SEEN_AS_GROUP_CLIENT) ||
+ os_reltime_expired(&dev->last_seen, rx_time,
+ P2P_DEV_GROUP_CLIENT_RESP_THRESHOLD))) {
+ p2p_dbg(p2p,
+ "Do not update peer entry based on old frame (rx_time=%u.%06u last_seen=%u.%06u flags=0x%x)",
(unsigned int) rx_time->sec,
(unsigned int) rx_time->usec,
(unsigned int) dev->last_seen.sec,
- (unsigned int) dev->last_seen.usec);
+ (unsigned int) dev->last_seen.usec,
+ dev->flags);
p2p_parse_free(&msg);
return -1;
}
os_memcpy(&dev->last_seen, rx_time, sizeof(struct os_reltime));
- dev->flags &= ~(P2P_DEV_PROBE_REQ_ONLY | P2P_DEV_GROUP_CLIENT_ONLY);
+ dev->flags &= ~(P2P_DEV_PROBE_REQ_ONLY | P2P_DEV_GROUP_CLIENT_ONLY |
+ P2P_DEV_LAST_SEEN_AS_GROUP_CLIENT);
if (os_memcmp(addr, p2p_dev_addr, ETH_ALEN) != 0)
os_memcpy(dev->interface_addr, addr, ETH_ALEN);
@@ -844,7 +854,8 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
if (scan_res) {
p2p_add_group_clients(p2p, p2p_dev_addr, addr, freq,
- msg.group_info, msg.group_info_len);
+ msg.group_info, msg.group_info_len,
+ rx_time);
}
p2p_parse_free(&msg);
@@ -1128,6 +1139,8 @@ static int p2ps_gen_hash(struct p2p_data *p2p, const char *str, u8 *hash)
adv_array = (u8 *) str_buf;
adv_len = os_strlen(str);
+ if (adv_len >= sizeof(str_buf))
+ return 0;
for (i = 0; str[i] && i < adv_len; i++) {
if (str[i] >= 'A' && str[i] <= 'Z')
@@ -1183,27 +1196,25 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
* An empty seek string means no hash values, but still an ASP
* search.
*/
+ p2p_dbg(p2p, "ASP search");
p2p->p2ps_seek_count = 0;
p2p->p2ps_seek = 1;
} else if (seek && seek_count <= P2P_MAX_QUERY_HASH) {
u8 buf[P2PS_HASH_LEN];
- int i;
+ int i, count = 0;
- p2p->p2ps_seek_count = seek_count;
for (i = 0; i < seek_count; i++) {
if (!p2ps_gen_hash(p2p, seek[i], buf))
continue;
- /* If asking for wildcard, don't do others */
- if (os_memcmp(buf, p2p->wild_card_hash,
- P2PS_HASH_LEN) == 0) {
- p2p->p2ps_seek_count = 0;
- break;
- }
-
- os_memcpy(&p2p->query_hash[i * P2PS_HASH_LEN], buf,
- P2PS_HASH_LEN);
+ p2p_dbg(p2p, "Seek service %s hash " MACSTR,
+ seek[i], MAC2STR(buf));
+ os_memcpy(&p2p->p2ps_seek_hash[count * P2PS_HASH_LEN],
+ buf, P2PS_HASH_LEN);
+ count++;
}
+
+ p2p->p2ps_seek_count = count;
p2p->p2ps_seek = 1;
} else {
p2p->p2ps_seek_count = 0;
@@ -1213,7 +1224,8 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
/* Special case to perform wildcard search */
if (p2p->p2ps_seek_count == 0 && p2p->p2ps_seek) {
p2p->p2ps_seek_count = 1;
- os_memcpy(&p2p->query_hash, p2p->wild_card_hash, P2PS_HASH_LEN);
+ os_memcpy(&p2p->p2ps_seek_hash, p2p->wild_card_hash,
+ P2PS_HASH_LEN);
}
p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
@@ -1381,7 +1393,7 @@ static int p2p_prepare_channel_pref(struct p2p_data *p2p,
static void p2p_prepare_channel_best(struct p2p_data *p2p)
{
u8 op_class, op_channel;
- const int op_classes_5ghz[] = { 124, 115, 0 };
+ const int op_classes_5ghz[] = { 124, 125, 115, 0 };
const int op_classes_ht40[] = { 126, 127, 116, 117, 0 };
const int op_classes_vht[] = { 128, 0 };
@@ -2148,7 +2160,9 @@ int p2p_match_dev_type(struct p2p_data *p2p, struct wpabuf *wps)
}
-struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p)
+struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p,
+ const u8 *query_hash,
+ u8 query_count)
{
struct wpabuf *buf;
u8 *len;
@@ -2163,7 +2177,7 @@ struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p)
if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P])
extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P]);
- if (p2p->query_count)
+ if (query_count)
extra += MAX_SVC_ADV_IE_LEN;
buf = wpabuf_alloc(1000 + extra);
@@ -2200,9 +2214,8 @@ struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p)
p2p_buf_add_device_info(buf, p2p, NULL);
p2p_buf_update_ie_hdr(buf, len);
- if (p2p->query_count) {
- p2p_buf_add_service_instance(buf, p2p, p2p->query_count,
- p2p->query_hash,
+ if (query_count) {
+ p2p_buf_add_service_instance(buf, p2p, query_count, query_hash,
p2p->p2ps_adv_list);
}
@@ -2213,18 +2226,21 @@ struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p)
static int p2p_service_find_asp(struct p2p_data *p2p, const u8 *hash)
{
struct p2ps_advertisement *adv_data;
+ int any_wfa;
p2p_dbg(p2p, "ASP find - ASP list: %p", p2p->p2ps_adv_list);
- /* Wildcard always matches if we have actual services */
- if (os_memcmp(hash, p2p->wild_card_hash, P2PS_HASH_LEN) == 0)
- return p2p->p2ps_adv_list != NULL;
+ /* Wildcard org.wi-fi.wfds matches any WFA spec defined service */
+ any_wfa = os_memcmp(hash, p2p->wild_card_hash, P2PS_HASH_LEN) == 0;
adv_data = p2p->p2ps_adv_list;
while (adv_data) {
- p2p_dbg(p2p, "ASP hash: %x =? %x", hash[0], adv_data->hash[0]);
if (os_memcmp(hash, adv_data->hash, P2PS_HASH_LEN) == 0)
- return 1;
+ return 1; /* exact hash match */
+ if (any_wfa &&
+ os_strncmp(adv_data->svc_name, P2PS_WILD_HASH_STR,
+ os_strlen(P2PS_WILD_HASH_STR)) == 0)
+ return 1; /* WFA service match */
adv_data = adv_data->next;
}
@@ -2234,13 +2250,15 @@ static int p2p_service_find_asp(struct p2p_data *p2p, const u8 *hash)
static enum p2p_probe_req_status
p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
- const u8 *bssid, const u8 *ie, size_t ie_len)
+ const u8 *bssid, const u8 *ie, size_t ie_len,
+ unsigned int rx_freq)
{
struct ieee802_11_elems elems;
struct wpabuf *buf;
struct ieee80211_mgmt *resp;
struct p2p_message msg;
struct wpabuf *ies;
+ u8 channel, op_class;
if (ieee802_11_parse_elems((u8 *) ie, ie_len, &elems, 0) ==
ParseFailed) {
@@ -2292,53 +2310,29 @@ p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
return P2P_PREQ_NOT_P2P;
}
- p2p->p2ps_svc_found = 0;
-
if (msg.service_hash && msg.service_hash_count) {
const u8 *hash = msg.service_hash;
- u8 *dest = p2p->query_hash;
u8 i;
+ int p2ps_svc_found = 0;
- p2p->query_count = 0;
for (i = 0; i < msg.service_hash_count; i++) {
if (p2p_service_find_asp(p2p, hash)) {
- p2p->p2ps_svc_found = 1;
-
- if (!os_memcmp(hash, p2p->wild_card_hash,
- P2PS_HASH_LEN)) {
- /* We found match(es) but wildcard
- * will return all */
- p2p->query_count = 1;
- os_memcpy(p2p->query_hash, hash,
- P2PS_HASH_LEN);
- break;
- }
-
- /* Save each matching hash */
- if (p2p->query_count < P2P_MAX_QUERY_HASH) {
- os_memcpy(dest, hash, P2PS_HASH_LEN);
- dest += P2PS_HASH_LEN;
- p2p->query_count++;
- } else {
- /* We found match(es) but too many to
- * return all */
- p2p->query_count = 0;
- break;
- }
+ p2p_dbg(p2p, "Service Hash match found: "
+ MACSTR, MAC2STR(hash));
+ p2ps_svc_found = 1;
+ break;
}
hash += P2PS_HASH_LEN;
}
- p2p_dbg(p2p, "ASP adv found: %d", p2p->p2ps_svc_found);
-
/* Probed hash unknown */
- if (!p2p->p2ps_svc_found) {
+ if (!p2ps_svc_found) {
+ p2p_dbg(p2p, "No Service Hash match found");
p2p_parse_free(&msg);
return P2P_PREQ_NOT_PROCESSED;
}
} else {
/* This is not a P2PS Probe Request */
- p2p->query_count = 0;
p2p_dbg(p2p, "No P2PS Hash in Probe Request");
if (!p2p->in_listen || !p2p->drv_in_listen) {
@@ -2367,11 +2361,11 @@ p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
p2p_parse_free(&msg);
return P2P_PREQ_NOT_PROCESSED;
}
- p2p_parse_free(&msg);
if (!p2p->cfg->send_probe_resp) {
/* Response generated elsewhere */
p2p_dbg(p2p, "Probe Resp generated elsewhere - do not generate additional response");
+ p2p_parse_free(&msg);
return P2P_PREQ_NOT_PROCESSED;
}
@@ -2383,7 +2377,9 @@ p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
* really only used for discovery purposes, not to learn exact BSS
* parameters.
*/
- ies = p2p_build_probe_resp_ies(p2p);
+ ies = p2p_build_probe_resp_ies(p2p, msg.service_hash,
+ msg.service_hash_count);
+ p2p_parse_free(&msg);
if (ies == NULL)
return P2P_PREQ_NOT_PROCESSED;
@@ -2423,32 +2419,50 @@ p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
wpabuf_put_u8(buf, 480 / 5);
wpabuf_put_u8(buf, 540 / 5);
+ if (!rx_freq) {
+ channel = p2p->cfg->channel;
+ } else if (p2p_freq_to_channel(rx_freq, &op_class, &channel)) {
+ wpabuf_free(ies);
+ wpabuf_free(buf);
+ return P2P_PREQ_NOT_PROCESSED;
+ }
+
wpabuf_put_u8(buf, WLAN_EID_DS_PARAMS);
wpabuf_put_u8(buf, 1);
- wpabuf_put_u8(buf, p2p->cfg->channel);
+ wpabuf_put_u8(buf, channel);
wpabuf_put_buf(buf, ies);
wpabuf_free(ies);
- p2p->cfg->send_probe_resp(p2p->cfg->cb_ctx, buf);
+ p2p->cfg->send_probe_resp(p2p->cfg->cb_ctx, buf, rx_freq);
wpabuf_free(buf);
- return P2P_PREQ_NOT_PROCESSED;
+ return P2P_PREQ_PROCESSED;
}
enum p2p_probe_req_status
p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
- const u8 *bssid, const u8 *ie, size_t ie_len)
+ const u8 *bssid, const u8 *ie, size_t ie_len,
+ unsigned int rx_freq)
{
enum p2p_probe_req_status res;
p2p_add_dev_from_probe_req(p2p, addr, ie, ie_len);
- res = p2p_reply_probe(p2p, addr, dst, bssid, ie, ie_len);
- p2p->query_count = 0;
+ res = p2p_reply_probe(p2p, addr, dst, bssid, ie, ie_len, rx_freq);
+ if (res != P2P_PREQ_PROCESSED && res != P2P_PREQ_NOT_PROCESSED)
+ return res;
+ /*
+ * Activate a pending GO Negotiation/Invite flow if a received Probe
+ * Request frame is from an expected peer. Some devices may share the
+ * same address for P2P and non-P2P STA running simultaneously. The
+ * P2P_PREQ_PROCESSED and P2P_PREQ_NOT_PROCESSED p2p_reply_probe()
+ * return values verified above ensure we are handling a Probe Request
+ * frame from a P2P peer.
+ */
if ((p2p->state == P2P_CONNECT || p2p->state == P2P_CONNECT_LISTEN) &&
p2p->go_neg_peer &&
os_memcmp(addr, p2p->go_neg_peer->info.p2p_device_addr, ETH_ALEN)
@@ -2458,7 +2472,7 @@ p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
p2p_dbg(p2p, "Found GO Negotiation peer - try to start GO negotiation from timeout");
eloop_cancel_timeout(p2p_go_neg_start, p2p, NULL);
eloop_register_timeout(0, 0, p2p_go_neg_start, p2p, NULL);
- return P2P_PREQ_PROCESSED;
+ return res;
}
if ((p2p->state == P2P_INVITE || p2p->state == P2P_INVITE_LISTEN) &&
@@ -2470,7 +2484,7 @@ p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
p2p_dbg(p2p, "Found Invite peer - try to start Invite from timeout");
eloop_cancel_timeout(p2p_invite_start, p2p, NULL);
eloop_register_timeout(0, 0, p2p_invite_start, p2p, NULL);
- return P2P_PREQ_PROCESSED;
+ return res;
}
return res;
@@ -2937,7 +2951,7 @@ void p2p_deinit(struct p2p_data *p2p)
os_free(p2p->cfg->serial_number);
os_free(p2p->cfg->pref_chan);
os_free(p2p->groups);
- os_free(p2p->p2ps_prov);
+ p2ps_prov_free(p2p);
wpabuf_free(p2p->sd_resp);
os_free(p2p->after_scan_tx);
p2p_remove_wps_vendor_extensions(p2p);
@@ -4143,7 +4157,7 @@ int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
"country=%c%c\n"
"oper_freq=%d\n"
"req_config_methods=0x%x\n"
- "flags=%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n"
+ "flags=%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n"
"status=%d\n"
"invitation_reqs=%u\n",
(int) (now.sec - dev->last_seen.sec),
@@ -4187,6 +4201,8 @@ int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
"[FORCE_FREQ]" : "",
dev->flags & P2P_DEV_PD_FOR_JOIN ?
"[PD_FOR_JOIN]" : "",
+ dev->flags & P2P_DEV_LAST_SEEN_AS_GROUP_CLIENT ?
+ "[LAST_SEEN_AS_GROUP_CLIENT]" : "",
dev->status,
dev->invitation_reqs);
if (os_snprintf_error(end - pos, res))
@@ -5238,6 +5254,7 @@ int p2p_process_nfc_connection_handover(struct p2p_data *p2p,
if (!msg.oob_go_neg_channel) {
p2p_dbg(p2p, "OOB GO Negotiation Channel attribute not included");
+ p2p_parse_free(&msg);
return -1;
}
@@ -5249,6 +5266,7 @@ int p2p_process_nfc_connection_handover(struct p2p_data *p2p,
msg.oob_go_neg_channel[4]);
if (freq < 0) {
p2p_dbg(p2p, "Unknown peer OOB GO Neg channel");
+ p2p_parse_free(&msg);
return -1;
}
role = msg.oob_go_neg_channel[5];
@@ -5269,6 +5287,7 @@ int p2p_process_nfc_connection_handover(struct p2p_data *p2p,
p2p->cfg->channel);
if (freq < 0) {
p2p_dbg(p2p, "Own listen channel not known");
+ p2p_parse_free(&msg);
return -1;
}
p2p_dbg(p2p, "Use own Listen channel as OOB GO Neg channel: %u MHz", freq);
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 6b0ba800..67b8bdb6 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -570,12 +570,14 @@ struct p2p_config {
* send_probe_resp - Transmit a Probe Response frame
* @ctx: Callback context from cb_ctx
* @buf: Probe Response frame (including the header and body)
+ * @freq: Forced frequency (in MHz) to use or 0.
* Returns: 0 on success, -1 on failure
*
* This function is used to reply to Probe Request frames that were
* indicated with a call to p2p_probe_req_rx(). The response is to be
- * sent on the same channel or to be dropped if the driver is not
- * anymore listening to Probe Request frames.
+ * sent on the same channel, unless otherwise specified, or to be
+ * dropped if the driver is not listening to Probe Request frames
+ * anymore.
*
* Alternatively, the responsibility for building the Probe Response
* frames in Listen state may be in another system component in which
@@ -586,7 +588,8 @@ struct p2p_config {
* Request frames must be indicated by calling p2p_probe_req_rx() even
* if this send_probe_resp() is not used.
*/
- int (*send_probe_resp)(void *ctx, const struct wpabuf *buf);
+ int (*send_probe_resp)(void *ctx, const struct wpabuf *buf,
+ unsigned int freq);
/**
* send_action - Transmit an Action frame
@@ -1463,11 +1466,13 @@ enum p2p_probe_req_status {
* @bssid: BSSID if available or %NULL
* @ie: Information elements from the Probe Request frame body
* @ie_len: Length of ie buffer in octets
+ * @rx_freq: Probe Request frame RX frequency
* Returns: value indicating the type and status of the probe request
*/
enum p2p_probe_req_status
p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
- const u8 *bssid, const u8 *ie, size_t ie_len);
+ const u8 *bssid, const u8 *ie, size_t ie_len,
+ unsigned int rx_freq);
/**
* p2p_rx_action - Report received Action frame
diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c
index 92c92066..6b6e7701 100644
--- a/src/p2p/p2p_build.c
+++ b/src/p2p/p2p_build.c
@@ -353,10 +353,10 @@ void p2p_buf_add_service_hash(struct wpabuf *buf, struct p2p_data *p2p)
/* Service Hash */
wpabuf_put_u8(buf, P2P_ATTR_SERVICE_HASH);
wpabuf_put_le16(buf, p2p->p2ps_seek_count * P2PS_HASH_LEN);
- wpabuf_put_data(buf, p2p->query_hash,
+ wpabuf_put_data(buf, p2p->p2ps_seek_hash,
p2p->p2ps_seek_count * P2PS_HASH_LEN);
wpa_hexdump(MSG_DEBUG, "P2P: * Service Hash",
- p2p->query_hash, p2p->p2ps_seek_count * P2PS_HASH_LEN);
+ p2p->p2ps_seek_hash, p2p->p2ps_seek_count * P2PS_HASH_LEN);
}
@@ -404,152 +404,222 @@ void p2p_buf_add_advertisement_id(struct wpabuf *buf, u32 id, const u8 *mac)
}
-void p2p_buf_add_service_instance(struct wpabuf *buf, struct p2p_data *p2p,
- u8 hash_count, const u8 *hash,
- struct p2ps_advertisement *adv_list)
+static int p2ps_wildcard_hash(struct p2p_data *p2p,
+ const u8 *hash, u8 hash_count)
+{
+ u8 i;
+ const u8 *test = hash;
+
+ for (i = 0; i < hash_count; i++) {
+ if (os_memcmp(test, p2p->wild_card_hash, P2PS_HASH_LEN) == 0)
+ return 1;
+ test += P2PS_HASH_LEN;
+ }
+
+ return 0;
+}
+
+
+static int p2p_wfa_service_adv(struct p2p_data *p2p)
{
struct p2ps_advertisement *adv;
- struct wpabuf *tmp_buf;
- u8 *tag_len = NULL, *ie_len = NULL;
- size_t svc_len = 0, remaining = 0, total_len = 0;
- if (!adv_list || !hash)
- return;
+ for (adv = p2p->p2ps_adv_list; adv; adv = adv->next) {
+ if (os_strncmp(adv->svc_name, P2PS_WILD_HASH_STR,
+ os_strlen(P2PS_WILD_HASH_STR)) == 0)
+ return 1;
+ }
- /* Allocate temp buffer, allowing for overflow of 1 instance */
- tmp_buf = wpabuf_alloc(MAX_SVC_ADV_IE_LEN + 256 + P2PS_HASH_LEN);
- if (!tmp_buf)
- return;
+ return 0;
+}
- for (adv = adv_list; adv && total_len <= MAX_SVC_ADV_LEN;
- adv = adv->next) {
- u8 count = hash_count;
- const u8 *test = hash;
- while (count--) {
- /* Check for wildcard */
- if (os_memcmp(test, p2p->wild_card_hash,
- P2PS_HASH_LEN) == 0) {
- total_len = MAX_SVC_ADV_LEN + 1;
- goto wild_hash;
- }
+static int p2p_buf_add_service_info(struct wpabuf *buf, struct p2p_data *p2p,
+ u32 adv_id, u16 config_methods,
+ const char *svc_name, u8 **ie_len, u8 **pos,
+ size_t *total_len, u8 *attr_len)
+{
+ size_t svc_len;
+ size_t remaining;
+ size_t info_len;
- if (os_memcmp(test, adv->hash, P2PS_HASH_LEN) == 0)
- goto hash_match;
+ p2p_dbg(p2p, "Add service info for %s (adv_id=%u)", svc_name, adv_id);
+ svc_len = os_strlen(svc_name);
+ info_len = sizeof(adv_id) + sizeof(config_methods) + sizeof(u8) +
+ svc_len;
- test += P2PS_HASH_LEN;
- }
+ if (info_len + *total_len > MAX_SVC_ADV_LEN) {
+ p2p_dbg(p2p,
+ "Unsufficient buffer, failed to add advertised service info");
+ return -1;
+ }
- /* No matches found - Skip this Adv Instance */
- continue;
-
-hash_match:
- if (!tag_len) {
- tag_len = p2p_buf_add_ie_hdr(tmp_buf);
- remaining = 255 - 4;
- if (!ie_len) {
- wpabuf_put_u8(tmp_buf,
- P2P_ATTR_ADVERTISED_SERVICE);
- ie_len = wpabuf_put(tmp_buf, sizeof(u16));
- remaining -= (sizeof(u8) + sizeof(u16));
- }
- }
+ if (svc_len > 255) {
+ p2p_dbg(p2p,
+ "Invalid service name length (%u bytes), failed to add advertised service info",
+ (unsigned int) svc_len);
+ return -1;
+ }
- svc_len = os_strlen(adv->svc_name);
+ if (*ie_len) {
+ int ie_data_len = (*pos - *ie_len) - 1;
- if (7 + svc_len + total_len > MAX_SVC_ADV_LEN) {
- /* Can't fit... return wildcard */
- total_len = MAX_SVC_ADV_LEN + 1;
- break;
+ if (ie_data_len < 0 || ie_data_len > 255) {
+ p2p_dbg(p2p,
+ "Invalid IE length, failed to add advertised service info");
+ return -1;
}
+ remaining = 255 - ie_data_len;
+ } else {
+ /*
+ * Adding new P2P IE header takes 6 extra bytes:
+ * - 2 byte IE header (1 byte IE id and 1 byte length)
+ * - 4 bytes of IE_VENDOR_TYPE are reduced from 255 below
+ */
+ *ie_len = p2p_buf_add_ie_hdr(buf);
+ remaining = 255 - 4;
+ }
- if (remaining <= (sizeof(adv->id) +
- sizeof(adv->config_methods))) {
- size_t front = remaining;
- size_t back = (sizeof(adv->id) +
- sizeof(adv->config_methods)) - front;
- u8 holder[sizeof(adv->id) +
- sizeof(adv->config_methods)];
-
- /* This works even if front or back == 0 */
- WPA_PUT_LE32(holder, adv->id);
- WPA_PUT_BE16(&holder[sizeof(adv->id)],
- adv->config_methods);
- wpabuf_put_data(tmp_buf, holder, front);
- p2p_buf_update_ie_hdr(tmp_buf, tag_len);
- tag_len = p2p_buf_add_ie_hdr(tmp_buf);
- wpabuf_put_data(tmp_buf, &holder[front], back);
- remaining = 255 - (sizeof(adv->id) +
- sizeof(adv->config_methods)) - back;
- } else {
- wpabuf_put_le32(tmp_buf, adv->id);
- wpabuf_put_be16(tmp_buf, adv->config_methods);
- remaining -= (sizeof(adv->id) +
- sizeof(adv->config_methods));
- }
+ if (remaining < sizeof(u32) + sizeof(u16) + sizeof(u8)) {
+ /*
+ * Split adv_id, config_methods, and svc_name_len between two
+ * IEs.
+ */
+ size_t front = remaining;
+ size_t back = sizeof(u32) + sizeof(u16) + sizeof(u8) - front;
+ u8 holder[sizeof(u32) + sizeof(u16) + sizeof(u8)];
- /* We are guaranteed at least one byte for svc_len */
- wpabuf_put_u8(tmp_buf, svc_len);
- remaining -= sizeof(u8);
-
- if (remaining < svc_len) {
- size_t front = remaining;
- size_t back = svc_len - front;
-
- wpabuf_put_data(tmp_buf, adv->svc_name, front);
- p2p_buf_update_ie_hdr(tmp_buf, tag_len);
- tag_len = p2p_buf_add_ie_hdr(tmp_buf);
-
- /* In rare cases, we must split across 3 attributes */
- if (back > 255 - 4) {
- wpabuf_put_data(tmp_buf,
- &adv->svc_name[front], 255 - 4);
- back -= 255 - 4;
- front += 255 - 4;
- p2p_buf_update_ie_hdr(tmp_buf, tag_len);
- tag_len = p2p_buf_add_ie_hdr(tmp_buf);
- }
-
- wpabuf_put_data(tmp_buf, &adv->svc_name[front], back);
- remaining = 255 - 4 - back;
- } else {
- wpabuf_put_data(tmp_buf, adv->svc_name, svc_len);
- remaining -= svc_len;
- }
+ WPA_PUT_LE32(holder, adv_id);
+ WPA_PUT_BE16(&holder[sizeof(u32)], config_methods);
+ holder[sizeof(u32) + sizeof(u16)] = svc_len;
+
+ if (front)
+ wpabuf_put_data(buf, holder, front);
+
+ p2p_buf_update_ie_hdr(buf, *ie_len);
+ *ie_len = p2p_buf_add_ie_hdr(buf);
- /* adv_id config_methods svc_string */
- total_len += sizeof(u32) + sizeof(u16) + sizeof(u8) + svc_len;
+ wpabuf_put_data(buf, &holder[front], back);
+ remaining = 255 - 4 - (sizeof(u32) + sizeof(u16) + sizeof(u8)) -
+ back;
+ } else {
+ wpabuf_put_le32(buf, adv_id);
+ wpabuf_put_be16(buf, config_methods);
+ wpabuf_put_u8(buf, svc_len);
+ remaining -= sizeof(adv_id) + sizeof(config_methods) +
+ sizeof(u8);
}
- if (tag_len)
- p2p_buf_update_ie_hdr(tmp_buf, tag_len);
+ if (remaining < svc_len) {
+ /* split svc_name between two or three IEs */
+ size_t front = remaining;
+ size_t back = svc_len - front;
- if (ie_len)
- WPA_PUT_LE16(ie_len, (u16) total_len);
+ if (front)
+ wpabuf_put_data(buf, svc_name, front);
-wild_hash:
- /* If all fit, return matching instances, otherwise the wildcard */
- if (total_len <= MAX_SVC_ADV_LEN) {
- wpabuf_put_buf(buf, tmp_buf);
+ p2p_buf_update_ie_hdr(buf, *ie_len);
+ *ie_len = p2p_buf_add_ie_hdr(buf);
+
+ /* In rare cases, we must split across 3 attributes */
+ if (back > 255 - 4) {
+ wpabuf_put_data(buf, &svc_name[front], 255 - 4);
+ back -= 255 - 4;
+ front += 255 - 4;
+ p2p_buf_update_ie_hdr(buf, *ie_len);
+ *ie_len = p2p_buf_add_ie_hdr(buf);
+ }
+
+ wpabuf_put_data(buf, &svc_name[front], back);
+ remaining = 255 - 4 - back;
} else {
- char *wild_card = P2PS_WILD_HASH_STR;
- u8 wild_len;
-
- /* Insert wildcard instance */
- tag_len = p2p_buf_add_ie_hdr(buf);
- wpabuf_put_u8(buf, P2P_ATTR_ADVERTISED_SERVICE);
- ie_len = wpabuf_put(buf, sizeof(u16));
-
- wild_len = (u8) os_strlen(wild_card);
- wpabuf_put_le32(buf, 0);
- wpabuf_put_be16(buf, 0);
- wpabuf_put_u8(buf, wild_len);
- wpabuf_put_data(buf, wild_card, wild_len);
-
- WPA_PUT_LE16(ie_len, 4 + 2 + 1 + wild_len);
- p2p_buf_update_ie_hdr(buf, tag_len);
+ wpabuf_put_data(buf, svc_name, svc_len);
+ remaining -= svc_len;
}
+ p2p_buf_update_ie_hdr(buf, *ie_len);
+
+ /* set *ie_len to NULL if a new IE has to be added on the next call */
+ if (!remaining)
+ *ie_len = NULL;
+
+ /* set *pos to point to the next byte to update */
+ *pos = wpabuf_put(buf, 0);
+
+ *total_len += info_len;
+ WPA_PUT_LE16(attr_len, (u16) *total_len);
+ return 0;
+}
+
+
+void p2p_buf_add_service_instance(struct wpabuf *buf, struct p2p_data *p2p,
+ u8 hash_count, const u8 *hash,
+ struct p2ps_advertisement *adv_list)
+{
+ struct p2ps_advertisement *adv;
+ int p2ps_wildcard, found = 0;
+ size_t total_len;
+ struct wpabuf *tmp_buf = NULL;
+ u8 *pos, *attr_len, *ie_len = NULL;
+
+ if (!adv_list || !hash || !hash_count)
+ return;
+
+ wpa_hexdump(MSG_DEBUG, "P2PS: Probe Request service hash values",
+ hash, hash_count * P2PS_HASH_LEN);
+ p2ps_wildcard = p2ps_wildcard_hash(p2p, hash, hash_count) &&
+ p2p_wfa_service_adv(p2p);
+
+ /* Allocate temp buffer, allowing for overflow of 1 instance */
+ tmp_buf = wpabuf_alloc(MAX_SVC_ADV_IE_LEN + 256 + P2PS_HASH_LEN);
+ if (!tmp_buf)
+ return;
+
+ /*
+ * Attribute data can be split into a number of IEs. Start with the
+ * first IE and the attribute headers here.
+ */
+ ie_len = p2p_buf_add_ie_hdr(tmp_buf);
+
+ total_len = 0;
+
+ wpabuf_put_u8(tmp_buf, P2P_ATTR_ADVERTISED_SERVICE);
+ attr_len = wpabuf_put(tmp_buf, sizeof(u16));
+ WPA_PUT_LE16(attr_len, (u16) total_len);
+ p2p_buf_update_ie_hdr(tmp_buf, ie_len);
+ pos = wpabuf_put(tmp_buf, 0);
+
+ if (p2ps_wildcard) {
+ /* org.wi-fi.wfds match found */
+ p2p_buf_add_service_info(tmp_buf, p2p, 0, 0, P2PS_WILD_HASH_STR,
+ &ie_len, &pos, &total_len, attr_len);
+ found++;
+ }
+
+ /* add advertised service info of matching services */
+ for (adv = adv_list; adv && total_len <= MAX_SVC_ADV_LEN;
+ adv = adv->next) {
+ const u8 *test = hash;
+ u8 i;
+
+ for (i = 0; i < hash_count; i++) {
+ /* exact name hash match */
+ if (os_memcmp(test, adv->hash, P2PS_HASH_LEN) == 0 &&
+ p2p_buf_add_service_info(tmp_buf, p2p,
+ adv->id,
+ adv->config_methods,
+ adv->svc_name,
+ &ie_len, &pos,
+ &total_len,
+ attr_len))
+ break;
+ found++;
+ test += P2PS_HASH_LEN;
+ }
+ }
+
+ if (found)
+ wpabuf_put_buf(buf, tmp_buf);
wpabuf_free(tmp_buf);
}
diff --git a/src/p2p/p2p_dev_disc.c b/src/p2p/p2p_dev_disc.c
index 86bae1a2..98805fee 100644
--- a/src/p2p/p2p_dev_disc.c
+++ b/src/p2p/p2p_dev_disc.c
@@ -314,7 +314,7 @@ void p2p_process_go_disc_req(struct p2p_data *p2p, const u8 *da, const u8 *sa,
p2p_dbg(p2p, "Received GO Discoverability Request - remain awake for 100 TU");
- ies = p2p_build_probe_resp_ies(p2p);
+ ies = p2p_build_probe_resp_ies(p2p, NULL, 0);
if (ies == NULL)
return;
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index 63837ebc..19f1daaf 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -379,7 +379,7 @@ void p2p_reselect_channel(struct p2p_data *p2p,
int freq;
u8 op_reg_class, op_channel;
unsigned int i;
- const int op_classes_5ghz[] = { 124, 115, 0 };
+ const int op_classes_5ghz[] = { 124, 125, 115, 0 };
const int op_classes_ht40[] = { 126, 127, 116, 117, 0 };
const int op_classes_vht[] = { 128, 0 };
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 289a62d3..a1042d23 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -14,6 +14,12 @@
#define P2P_GO_NEG_CNF_MAX_RETRY_COUNT 1
+/*
+ * A threshold (in seconds) to prefer a direct Probe Response frame from a P2P
+ * Device over the P2P Client Info received from a GO.
+ */
+#define P2P_DEV_GROUP_CLIENT_RESP_THRESHOLD 1
+
enum p2p_role_indication;
/*
@@ -107,6 +113,8 @@ struct p2p_device {
#define P2P_DEV_WAIT_INV_REQ_ACK BIT(19)
#define P2P_DEV_P2PS_REPORTED BIT(20)
#define P2P_DEV_PD_PEER_P2PS BIT(21)
+#define P2P_DEV_LAST_SEEN_AS_GROUP_CLIENT BIT(22)
+
unsigned int flags;
int status; /* enum p2p_status_code */
@@ -506,11 +514,9 @@ struct p2p_data {
struct p2ps_advertisement *p2ps_adv_list;
struct p2ps_provision *p2ps_prov;
u8 wild_card_hash[P2PS_HASH_LEN];
- u8 query_hash[P2P_MAX_QUERY_HASH * P2PS_HASH_LEN];
- u8 query_count;
u8 p2ps_seek;
+ u8 p2ps_seek_hash[P2P_MAX_QUERY_HASH * P2PS_HASH_LEN];
u8 p2ps_seek_count;
- u8 p2ps_svc_found;
#ifdef CONFIG_WIFI_DISPLAY
struct wpabuf *wfd_ie_beacon;
@@ -795,6 +801,7 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
int join, int force_freq);
void p2p_reset_pending_pd(struct p2p_data *p2p);
+void p2ps_prov_free(struct p2p_data *p2p);
/* p2p_invitation.c */
void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
@@ -840,7 +847,9 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer);
int p2p_match_dev_type(struct p2p_data *p2p, struct wpabuf *wps);
int dev_type_list_match(const u8 *dev_type, const u8 *req_dev_type[],
size_t num_req_dev_type);
-struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p);
+struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p,
+ const u8 *query_hash,
+ u8 query_count);
void p2p_build_ssid(struct p2p_data *p2p, u8 *ssid, size_t *ssid_len);
int p2p_send_action(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
const u8 *src, const u8 *bssid, const u8 *buf,
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index 44a6bbfd..f5454f70 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -134,6 +134,9 @@ static struct wpabuf * p2p_build_invitation_resp(struct p2p_data *p2p,
extra = wpabuf_len(wfd_ie);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_INV_RESP])
+ extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_INV_RESP]);
+
buf = wpabuf_alloc(1000 + extra);
if (buf == NULL)
return NULL;
@@ -158,6 +161,9 @@ static struct wpabuf * p2p_build_invitation_resp(struct p2p_data *p2p,
wpabuf_put_buf(buf, wfd_ie);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_INV_RESP])
+ wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_INV_RESP]);
+
return buf;
}
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index bc84269e..86558f70 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -881,8 +881,7 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
P2P_PROV_DISC_REJECTED,
adv_id, adv_mac, NULL);
p2p_parse_free(&msg);
- os_free(p2p->p2ps_prov);
- p2p->p2ps_prov = NULL;
+ p2ps_prov_free(p2p);
goto out;
}
@@ -920,8 +919,7 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
conncap, passwd_id, msg.persistent_ssid,
msg.persistent_ssid_len, 1, 0, NULL);
}
- os_free(p2p->p2ps_prov);
- p2p->p2ps_prov = NULL;
+ p2ps_prov_free(p2p);
}
if (status != P2P_SC_SUCCESS &&
@@ -933,8 +931,7 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
p2p->p2ps_prov->session_mac,
group_mac, adv_id, p2p->p2ps_prov->session_id,
0, 0, NULL, 0, 1, 0, NULL);
- os_free(p2p->p2ps_prov);
- p2p->p2ps_prov = NULL;
+ p2ps_prov_free(p2p);
}
if (status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
@@ -950,8 +947,7 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
if (!deferred_sess_resp) {
p2p_parse_free(&msg);
- os_free(p2p->p2ps_prov);
- p2p->p2ps_prov = NULL;
+ p2ps_prov_free(p2p);
goto out;
}
utf8_escape((char *) msg.session_info, info_len,
@@ -978,8 +974,7 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
P2P_PROV_DISC_REJECTED, 0,
NULL, NULL);
p2p_parse_free(&msg);
- os_free(p2p->p2ps_prov);
- p2p->p2ps_prov = NULL;
+ p2ps_prov_free(p2p);
goto out;
}
@@ -1120,7 +1115,7 @@ int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
/* Reset provisioning info */
dev->wps_prov_info = 0;
- os_free(p2p->p2ps_prov);
+ p2ps_prov_free(p2p);
p2p->p2ps_prov = p2ps_prov;
dev->req_config_methods = config_methods;
@@ -1176,3 +1171,10 @@ void p2p_reset_pending_pd(struct p2p_data *p2p)
p2p->pd_retries = 0;
p2p->pd_force_freq = 0;
}
+
+
+void p2ps_prov_free(struct p2p_data *p2p)
+{
+ os_free(p2p->p2ps_prov);
+ p2p->p2ps_prov = NULL;
+}
diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c
index f32751d7..eee3c5a6 100644
--- a/src/p2p/p2p_utils.c
+++ b/src/p2p/p2p_utils.c
@@ -101,6 +101,15 @@ int p2p_freq_to_channel(unsigned int freq, u8 *op_class, u8 *channel)
return 0;
}
+ if (freq >= 5745 && freq <= 5845) {
+ if ((freq - 5000) % 5)
+ return -1;
+
+ *op_class = 125; /* 5 GHz, channels 149..169 */
+ *channel = (freq - 5000) / 5;
+ return 0;
+ }
+
if (freq >= 58320 && freq <= 64800) {
if ((freq - 58320) % 2160)
return -1;
diff --git a/src/utils/wpa_debug.c b/src/utils/wpa_debug.c
index 82a89998..b7a6dbae 100644
--- a/src/utils/wpa_debug.c
+++ b/src/utils/wpa_debug.c
@@ -307,7 +307,7 @@ static void _wpa_hexdump(int level, const char *title, const u8 *buf,
"%s - hexdump(len=%lu):%s%s",
title, (long unsigned int) len, display,
len > slen ? " ..." : "");
- os_free(strbuf);
+ bin_clear_free(strbuf, 1 + 3 * slen);
return;
}
#else /* CONFIG_ANDROID_LOG */
@@ -339,7 +339,7 @@ static void _wpa_hexdump(int level, const char *title, const u8 *buf,
syslog(syslog_priority(level), "%s - hexdump(len=%lu):%s",
title, (unsigned long) len, display);
- os_free(strbuf);
+ bin_clear_free(strbuf, 1 + 3 * len);
return;
}
#endif /* CONFIG_DEBUG_SYSLOG */
@@ -636,7 +636,7 @@ void wpa_msg(void *ctx, int level, const char *fmt, ...)
wpa_printf(level, "%s%s", prefix, buf);
if (wpa_msg_cb)
wpa_msg_cb(ctx, level, WPA_MSG_PER_INTERFACE, buf, len);
- os_free(buf);
+ bin_clear_free(buf, buflen);
}
@@ -664,7 +664,7 @@ void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...)
len = vsnprintf(buf, buflen, fmt, ap);
va_end(ap);
wpa_msg_cb(ctx, level, WPA_MSG_PER_INTERFACE, buf, len);
- os_free(buf);
+ bin_clear_free(buf, buflen);
}
@@ -691,7 +691,7 @@ void wpa_msg_global(void *ctx, int level, const char *fmt, ...)
wpa_printf(level, "%s", buf);
if (wpa_msg_cb)
wpa_msg_cb(ctx, level, WPA_MSG_GLOBAL, buf, len);
- os_free(buf);
+ bin_clear_free(buf, buflen);
}
@@ -719,7 +719,7 @@ void wpa_msg_global_ctrl(void *ctx, int level, const char *fmt, ...)
len = vsnprintf(buf, buflen, fmt, ap);
va_end(ap);
wpa_msg_cb(ctx, level, WPA_MSG_GLOBAL, buf, len);
- os_free(buf);
+ bin_clear_free(buf, buflen);
}
@@ -746,7 +746,7 @@ void wpa_msg_no_global(void *ctx, int level, const char *fmt, ...)
wpa_printf(level, "%s", buf);
if (wpa_msg_cb)
wpa_msg_cb(ctx, level, WPA_MSG_NO_GLOBAL, buf, len);
- os_free(buf);
+ bin_clear_free(buf, buflen);
}
#endif /* CONFIG_NO_WPA_MSG */
@@ -789,6 +789,6 @@ void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level,
MAC2STR(addr), buf);
else
wpa_printf(MSG_DEBUG, "hostapd_logger: %s", buf);
- os_free(buf);
+ bin_clear_free(buf, buflen);
}
#endif /* CONFIG_NO_HOSTAPD_LOGGER */
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index bfb69fc8..f3960c5e 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -485,8 +485,13 @@ static int ap_probe_req_rx(void *ctx, const u8 *sa, const u8 *da,
int ssi_signal)
{
struct wpa_supplicant *wpa_s = ctx;
+ unsigned int freq = 0;
+
+ if (wpa_s->ap_iface)
+ freq = wpa_s->ap_iface->freq;
+
return wpas_p2p_probe_req_rx(wpa_s, sa, da, bssid, ie, ie_len,
- ssi_signal);
+ freq, ssi_signal);
}
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 2fe032d8..239c3e87 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -4180,6 +4180,7 @@ static const struct global_parse_data global_fields[] = {
{ IPV4(ip_addr_mask), 0 },
{ IPV4(ip_addr_start), 0 },
{ IPV4(ip_addr_end), 0 },
+ { INT_RANGE(p2p_cli_probe, 0, 1), 0 },
#endif /* CONFIG_P2P */
{ FUNC(country), CFG_CHANGED_COUNTRY },
{ INT(bss_max_count), 0 },
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 545a4bd7..d8ca054f 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -968,6 +968,18 @@ struct wpa_config {
int p2p_no_group_iface;
/**
+ * p2p_cli_probe - Enable/disable P2P CLI probe request handling
+ *
+ * If this parameter is set to 1, a connected P2P Client will receive
+ * and handle Probe Request frames. Setting this parameter to 0
+ * disables this option. Default value: 0.
+ *
+ * Note: Setting this property at run time takes effect on the following
+ * interface state transition to/from the WPA_COMPLETED state.
+ */
+ int p2p_cli_probe;
+
+ /**
* okc - Whether to enable opportunistic key caching by default
*
* By default, OKC is disabled unless enabled by the per-network
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 2508ca9c..e9465671 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -1131,6 +1131,9 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
if (config->p2p_ignore_shared_freq)
fprintf(f, "p2p_ignore_shared_freq=%u\n",
config->p2p_ignore_shared_freq);
+ if (config->p2p_cli_probe)
+ fprintf(f, "p2p_cli_probe=%u\n",
+ config->p2p_cli_probe);
#endif /* CONFIG_P2P */
if (config->country[0] && config->country[1]) {
fprintf(f, "country=%c%c\n",
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index f32b7c92..0c5ea8f5 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -4597,16 +4597,20 @@ static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd)
/* Must be searched for last, because it adds nul termination */
pos = os_strstr(cmd, " seek=");
+ if (pos)
+ pos += 6;
while (pos && seek_count < P2P_MAX_QUERY_HASH + 1) {
char *term;
- term = os_strchr(pos + 1, ' ');
- _seek[seek_count++] = pos + 6;
+ _seek[seek_count++] = pos;
seek = _seek;
- pos = os_strstr(pos + 6, " seek=");
-
- if (term)
- *term = '\0';
+ term = os_strchr(pos, ' ');
+ if (!term)
+ break;
+ *term = '\0';
+ pos = os_strstr(term + 1, "seek=");
+ if (pos)
+ pos += 5;
}
if (seek_count > P2P_MAX_QUERY_HASH) {
seek[0] = NULL;
@@ -5501,13 +5505,10 @@ static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd)
static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
- char *cmd, int freq, int ht40,
- int vht)
+ int id, int freq, int ht40, int vht)
{
- int id;
struct wpa_ssid *ssid;
- id = atoi(cmd);
ssid = wpa_config_get_network(wpa_s->conf, id);
if (ssid == NULL || ssid->disabled != 2) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
@@ -5523,31 +5524,35 @@ static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
{
- int freq = 0, ht40, vht;
- char *pos;
+ int freq = 0, persistent = 0, group_id = -1;
+ int vht = wpa_s->conf->p2p_go_vht;
+ int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
+ char *token, *context = NULL;
- pos = os_strstr(cmd, "freq=");
- if (pos)
- freq = atoi(pos + 5);
+ while ((token = str_token(cmd, " ", &context))) {
+ if (sscanf(token, "freq=%d", &freq) == 1 ||
+ sscanf(token, "persistent=%d", &group_id) == 1) {
+ continue;
+ } else if (os_strcmp(token, "ht40") == 0) {
+ ht40 = 1;
+ } else if (os_strcmp(token, "vht") == 0) {
+ vht = 1;
+ ht40 = 1;
+ } else if (os_strcmp(token, "persistent") == 0) {
+ persistent = 1;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "CTRL: Invalid P2P_GROUP_ADD parameter: '%s'",
+ token);
+ return -1;
+ }
+ }
- vht = (os_strstr(cmd, "vht") != NULL) || wpa_s->conf->p2p_go_vht;
- ht40 = (os_strstr(cmd, "ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
- vht;
+ if (group_id >= 0)
+ return p2p_ctrl_group_add_persistent(wpa_s, group_id,
+ freq, ht40, vht);
- if (os_strncmp(cmd, "persistent=", 11) == 0)
- return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq,
- ht40, vht);
- if (os_strcmp(cmd, "persistent") == 0 ||
- os_strncmp(cmd, "persistent ", 11) == 0)
- return wpas_p2p_group_add(wpa_s, 1, freq, ht40, vht);
- if (os_strncmp(cmd, "freq=", 5) == 0)
- return wpas_p2p_group_add(wpa_s, 0, freq, ht40, vht);
- if (ht40)
- return wpas_p2p_group_add(wpa_s, 0, freq, ht40, vht);
-
- wpa_printf(MSG_DEBUG, "CTRL: Invalid P2P_GROUP_ADD parameters '%s'",
- cmd);
- return -1;
+ return wpas_p2p_group_add(wpa_s, persistent, freq, ht40, vht);
}
@@ -8194,7 +8199,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
if (wpas_p2p_group_remove(wpa_s, buf + 17))
reply_len = -1;
} else if (os_strcmp(buf, "P2P_GROUP_ADD") == 0) {
- if (wpas_p2p_group_add(wpa_s, 0, 0, 0, 0))
+ if (p2p_ctrl_group_add(wpa_s, ""))
reply_len = -1;
} else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) {
if (p2p_ctrl_group_add(wpa_s, buf + 14))
diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c
index 22001cf6..f49ba07e 100644
--- a/wpa_supplicant/ctrl_iface_unix.c
+++ b/wpa_supplicant/ctrl_iface_unix.c
@@ -197,6 +197,13 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
reply_buf = wpa_supplicant_ctrl_iface_process(wpa_s, buf,
&reply_len);
reply = reply_buf;
+
+ /*
+ * There could be some password/key material in the command, so
+ * clear the buffer explicitly now that it is not needed
+ * anymore.
+ */
+ os_memset(buf, 0, res);
}
if (!reply && reply_len == 1) {
@@ -846,6 +853,13 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
reply_buf = wpa_supplicant_global_ctrl_iface_process(
global, buf, &reply_len);
reply = reply_buf;
+
+ /*
+ * There could be some password/key material in the command, so
+ * clear the buffer explicitly now that it is not needed
+ * anymore.
+ */
+ os_memset(buf, 0, res);
}
if (!reply && reply_len == 1) {
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index fb674d47..a3bf1e3d 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -603,6 +603,7 @@ void wpas_dbus_signal_wps_event_success(struct wpa_supplicant *wpa_s)
/**
* wpas_dbus_signal_wps_event_fail - Signals Fail WPS event
* @wpa_s: %wpa_supplicant network interface data
+ * @fail: WPS failure information
*
* Sends Event dbus signal with name "fail" and dictionary containing
* "msg field with fail message number (int32) as arguments
@@ -644,6 +645,7 @@ void wpas_dbus_signal_wps_event_fail(struct wpa_supplicant *wpa_s,
/**
* wpas_dbus_signal_wps_event_m2d - Signals M2D WPS event
* @wpa_s: %wpa_supplicant network interface data
+ * @m2d: M2D event data information
*
* Sends Event dbus signal with name "m2d" and dictionary containing
* fields of wps_event_m2d structure.
@@ -709,6 +711,7 @@ void wpas_dbus_signal_wps_event_m2d(struct wpa_supplicant *wpa_s,
/**
* wpas_dbus_signal_wps_cred - Signals new credentials
* @wpa_s: %wpa_supplicant network interface data
+ * @cred: WPS Credential information
*
* Sends signal with credentials in directory argument
*/
@@ -1100,6 +1103,16 @@ error:
}
+/**
+ * wpas_dbus_signal_p2p_go_neg_req - Signal P2P GO Negotiation Request RX
+ * @wpa_s: %wpa_supplicant network interface data
+ * @src: Source address of the message triggering this notification
+ * @dev_passwd_id: WPS Device Password Id
+ * @go_intent: Peer's GO Intent value
+ *
+ * Sends signal to notify that a peer P2P Device is requesting group owner
+ * negotiation with us.
+ */
void wpas_dbus_signal_p2p_go_neg_req(struct wpa_supplicant *wpa_s,
const u8 *src, u16 dev_passwd_id,
u8 go_intent)
@@ -1297,10 +1310,9 @@ void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
/**
- *
- * Method to emit GONegotiation Success or Failure signals based
- * on status.
- * @status: Status of the GO neg request. 0 for success, other for errors.
+ * wpas_dbus_signal_p2p_go_neg_resp - Emit GONegotiation Success/Failure signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @res: Result of the GO Neg Request
*/
void wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s,
struct p2p_go_neg_results *res)
@@ -1801,6 +1813,7 @@ static void wpas_dbus_signal_persistent_group_removed(
/**
* wpas_dbus_signal_p2p_wps_failed - Signals WpsFailed event
* @wpa_s: %wpa_supplicant network interface data
+ * @fail: WPS failure information
*
* Sends Event dbus signal with name "fail" and dictionary containing
* "msg" field with fail message number (int32) as arguments
@@ -2552,6 +2565,12 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
END_ARGS
}
},
+ { "Reconnect", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_reconnect,
+ {
+ END_ARGS
+ }
+ },
{ "RemoveNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
(WPADBusMethodHandler) wpas_dbus_handler_remove_network,
{
@@ -2715,6 +2734,13 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
END_ARGS
}
},
+ { "RemoveClient", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ (WPADBusMethodHandler) wpas_dbus_handler_p2p_remove_client,
+ {
+ { "args", "a{sv}", ARG_IN },
+ END_ARGS
+ }
+ },
{ "Flush", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
(WPADBusMethodHandler) wpas_dbus_handler_p2p_flush,
{
@@ -3502,7 +3528,7 @@ void wpas_dbus_signal_peer_device_lost(struct wpa_supplicant *wpa_s,
/**
* wpas_dbus_register_peer - Register a discovered peer object with dbus
* @wpa_s: wpa_supplicant interface structure
- * @ssid: network configuration data
+ * @dev_addr: P2P Device Address of the peer
* Returns: 0 on success, -1 on failure
*
* Registers network representing object with dbus
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 97db9a87..2a7e2cf9 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -1601,6 +1601,30 @@ DBusMessage * wpas_dbus_handler_reattach(DBusMessage *message,
/**
+ * wpas_dbus_handler_reconnect - Reconnect if disconnected
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: InterfaceDisabled DBus error message if disabled
+ * or NULL otherwise.
+ *
+ * Handler function for "Reconnect" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_reconnect(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
+ return dbus_message_new_error(message,
+ WPAS_DBUS_ERROR_IFACE_DISABLED,
+ "This interface is disabled");
+ }
+
+ if (wpa_s->disconnected)
+ wpas_request_connection(wpa_s);
+ return NULL;
+}
+
+
+/**
* wpas_dbus_handler_remove_network - Remove a configured network
* @message: Pointer to incoming dbus message
* @wpa_s: wpa_supplicant structure for a network interface
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index 9afdc059..50f72ec5 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -107,6 +107,9 @@ DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message,
DBusMessage * wpas_dbus_handler_reattach(DBusMessage *message,
struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_reconnect(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
struct wpa_supplicant *wpa_s);
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index 56e90334..e9d60df2 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -416,6 +416,64 @@ static dbus_bool_t wpa_dbus_p2p_check_enabled(struct wpa_supplicant *wpa_s,
}
+DBusMessage * wpas_dbus_handler_p2p_remove_client(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ DBusMessageIter iter_dict;
+ DBusMessage *reply = NULL;
+ DBusMessageIter iter;
+ struct wpa_dbus_dict_entry entry;
+ char *peer_object_path = NULL;
+ char *interface_addr = NULL;
+ u8 peer_addr[ETH_ALEN];
+
+ if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL))
+ return reply;
+
+ dbus_message_iter_init(message, &iter);
+
+ if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
+ goto err;
+
+ while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+ if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+ goto err;
+
+ if (os_strcmp(entry.key, "peer") == 0 &&
+ entry.type == DBUS_TYPE_OBJECT_PATH) {
+ os_free(peer_object_path);
+ peer_object_path = os_strdup(entry.str_value);
+ wpa_dbus_dict_entry_clear(&entry);
+ } else if (os_strcmp(entry.key, "iface") == 0 &&
+ entry.type == DBUS_TYPE_STRING) {
+ os_free(interface_addr);
+ interface_addr = os_strdup(entry.str_value);
+ wpa_dbus_dict_entry_clear(&entry);
+ } else {
+ wpa_dbus_dict_entry_clear(&entry);
+ goto err;
+ }
+ }
+
+ if ((!peer_object_path && !interface_addr) ||
+ (peer_object_path &&
+ (parse_peer_object_path(peer_object_path, peer_addr) < 0 ||
+ !p2p_peer_known(wpa_s->global->p2p, peer_addr))) ||
+ (interface_addr && hwaddr_aton(interface_addr, peer_addr) < 0))
+ goto err;
+
+ wpas_p2p_remove_client(wpa_s, peer_addr, interface_addr != NULL);
+ reply = NULL;
+out:
+ os_free(peer_object_path);
+ os_free(interface_addr);
+ return reply;
+err:
+ reply = wpas_dbus_error_invalid_args(message, "Invalid address format");
+ goto out;
+}
+
+
DBusMessage * wpas_dbus_handler_p2p_flush(DBusMessage *message,
struct wpa_supplicant *wpa_s)
{
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.h b/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
index d0953f18..2aecbbe4 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
@@ -56,6 +56,9 @@ DBusMessage *wpas_dbus_handler_p2p_invite(
DBusMessage *wpas_dbus_handler_p2p_disconnect(
DBusMessage *message, struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_p2p_remove_client(
+ DBusMessage *message, struct wpa_supplicant *wpa_s);
+
DBusMessage *wpas_dbus_handler_p2p_flush(
DBusMessage *message, struct wpa_supplicant *wpa_s);
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index ffee1f7d..1fcb1806 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -286,11 +286,13 @@ static inline int wpa_drv_set_country(struct wpa_supplicant *wpa_s,
}
static inline int wpa_drv_send_mlme(struct wpa_supplicant *wpa_s,
- const u8 *data, size_t data_len, int noack)
+ const u8 *data, size_t data_len, int noack,
+ unsigned int freq)
{
if (wpa_s->driver->send_mlme)
return wpa_s->driver->send_mlme(wpa_s->drv_priv,
- data, data_len, noack);
+ data, data_len, noack,
+ freq);
return -1;
}
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 80045e72..7be352db 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -2557,6 +2557,21 @@ wpa_supplicant_event_interface_status(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_INFO, "Failed to initialize the "
"driver after interface was added");
}
+
+#ifdef CONFIG_P2P
+ if (!wpa_s->global->p2p &&
+ !wpa_s->global->p2p_disabled &&
+ !wpa_s->conf->p2p_disabled &&
+ (wpa_s->drv_flags &
+ WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
+ wpas_p2p_add_p2pdev_interface(
+ wpa_s, wpa_s->global->params.conf_p2p_dev) < 0) {
+ wpa_printf(MSG_INFO,
+ "P2P: Failed to enable P2P Device interface");
+ /* Try to continue without. P2P will be disabled. */
+ }
+#endif /* CONFIG_P2P */
+
break;
case EVENT_INTERFACE_REMOVED:
wpa_dbg(wpa_s, MSG_DEBUG, "Configured interface was removed");
@@ -2565,6 +2580,21 @@ wpa_supplicant_event_interface_status(struct wpa_supplicant *wpa_s,
wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED);
l2_packet_deinit(wpa_s->l2);
wpa_s->l2 = NULL;
+
+#ifdef CONFIG_P2P
+ if (wpa_s->global->p2p &&
+ wpa_s->global->p2p_init_wpa_s->parent == wpa_s &&
+ (wpa_s->drv_flags &
+ WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Removing P2P Device interface");
+ wpa_supplicant_remove_iface(
+ wpa_s->global, wpa_s->global->p2p_init_wpa_s,
+ 0);
+ wpa_s->global->p2p_init_wpa_s = NULL;
+ }
+#endif /* CONFIG_P2P */
+
#ifdef CONFIG_TERMINATE_ONLASTIF
/* check if last interface */
if (!any_interfaces(wpa_s->global->ifaces))
@@ -3495,6 +3525,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
wpas_p2p_probe_req_rx(
wpa_s, src, mgmt->da,
mgmt->bssid, ie, ie_len,
+ data->rx_mgmt.freq,
data->rx_mgmt.ssi_signal);
break;
}
@@ -3566,6 +3597,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
data->rx_probe_req.bssid,
data->rx_probe_req.ie,
data->rx_probe_req.ie_len,
+ 0,
data->rx_probe_req.ssi_signal);
break;
case EVENT_REMAIN_ON_CHANNEL:
diff --git a/wpa_supplicant/main.c b/wpa_supplicant/main.c
index 9f5a198e..1c933069 100644
--- a/wpa_supplicant/main.c
+++ b/wpa_supplicant/main.c
@@ -237,7 +237,7 @@ int main(int argc, char *argv[])
goto out;
#ifdef CONFIG_P2P
case 'm':
- iface->conf_p2p_dev = optarg;
+ params.conf_p2p_dev = optarg;
break;
#endif /* CONFIG_P2P */
case 'o':
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 5c8a3b21..b9ebd380 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -126,6 +126,8 @@ static void wpas_p2p_psk_failure_removal(void *eloop_ctx, void *timeout_ctx);
static void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s);
static int wpas_p2p_add_group_interface(struct wpa_supplicant *wpa_s,
enum wpa_driver_if_type type);
+static void wpas_p2p_group_formation_failed(struct wpa_supplicant *wpa_s,
+ int already_deleted);
/*
@@ -1231,7 +1233,7 @@ static void wpas_p2p_group_started(struct wpa_supplicant *wpa_s,
static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
- int success)
+ int success, int already_deleted)
{
struct wpa_ssid *ssid;
int client;
@@ -1256,6 +1258,8 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
if (!success) {
wpa_msg_global(wpa_s->parent, MSG_INFO,
P2P_EVENT_GROUP_FORMATION_FAILURE);
+ if (already_deleted)
+ return;
wpas_p2p_group_delete(wpa_s,
P2P_GROUP_REMOVAL_FORMATION_FAILED);
return;
@@ -1874,6 +1878,7 @@ static void wpas_p2p_clone_config(struct wpa_supplicant *dst,
d->wps_nfc_dh_privkey = wpabuf_dup(s->wps_nfc_dh_privkey);
d->wps_nfc_dh_pubkey = wpabuf_dup(s->wps_nfc_dh_pubkey);
}
+ d->p2p_cli_probe = s->p2p_cli_probe;
}
@@ -2019,17 +2024,18 @@ static void wpas_p2p_group_formation_timeout(void *eloop_ctx,
{
struct wpa_supplicant *wpa_s = eloop_ctx;
wpa_printf(MSG_DEBUG, "P2P: Group Formation timed out");
- wpas_p2p_group_formation_failed(wpa_s);
+ wpas_p2p_group_formation_failed(wpa_s, 0);
}
-void wpas_p2p_group_formation_failed(struct wpa_supplicant *wpa_s)
+static void wpas_p2p_group_formation_failed(struct wpa_supplicant *wpa_s,
+ int already_deleted)
{
eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
wpa_s->parent, NULL);
if (wpa_s->global->p2p)
p2p_group_formation_failed(wpa_s->global->p2p);
- wpas_group_formation_completed(wpa_s, 0);
+ wpas_group_formation_completed(wpa_s, 0, already_deleted);
}
@@ -2110,7 +2116,7 @@ static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
wpas_p2p_remove_pending_group_interface(wpa_s);
eloop_cancel_timeout(wpas_p2p_long_listen_timeout,
wpa_s, NULL);
- wpas_p2p_group_formation_failed(wpa_s);
+ wpas_p2p_group_formation_failed(wpa_s, 1);
return;
}
if (group_wpa_s != wpa_s) {
@@ -2384,15 +2390,24 @@ static void wpas_stop_listen(void *ctx)
wpa_s->roc_waiting_drv_freq = 0;
}
wpa_drv_set_ap_wps_ie(wpa_s, NULL, NULL, NULL);
- wpa_drv_probe_req_report(wpa_s, 0);
+
+ /*
+ * Don't cancel Probe Request RX reporting for a connected P2P Client
+ * handling Probe Request frames.
+ */
+ if (!wpa_s->p2p_cli_probe)
+ wpa_drv_probe_req_report(wpa_s, 0);
+
wpas_p2p_listen_work_done(wpa_s);
}
-static int wpas_send_probe_resp(void *ctx, const struct wpabuf *buf)
+static int wpas_send_probe_resp(void *ctx, const struct wpabuf *buf,
+ unsigned int freq)
{
struct wpa_supplicant *wpa_s = ctx;
- return wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1);
+ return wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1,
+ freq);
}
@@ -3116,6 +3131,7 @@ static const struct p2p_oper_class_map op_class[] = {
#endif
{ HOSTAPD_MODE_IEEE80211A, 115, 36, 48, 4, BW20 },
{ HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20 },
+ { HOSTAPD_MODE_IEEE80211A, 125, 149, 169, 4, BW20 },
{ HOSTAPD_MODE_IEEE80211A, 116, 36, 44, 8, BW40PLUS },
{ HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS },
{ HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8, BW40PLUS },
@@ -3305,7 +3321,8 @@ int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
if (o->mode != HOSTAPD_MODE_IEEE80211A ||
- o->bw == BW20 || ch != channel)
+ (o->bw != BW40PLUS && o->bw != BW40MINUS) ||
+ ch != channel)
continue;
ret = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw);
if (ret == ALLOWED)
@@ -3455,7 +3472,6 @@ int wpas_p2p_add_p2pdev_interface(struct wpa_supplicant *wpa_s,
iface.confname = wpa_s->confname;
iface.ctrl_interface = wpa_s->conf->ctrl_interface;
}
- iface.conf_p2p_dev = NULL;
p2pdev_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface, wpa_s);
if (!p2pdev_wpa_s) {
@@ -4410,10 +4426,25 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
wpa_s->pending_join_iface_addr);
}
if (bss) {
+ u8 dev_addr[ETH_ALEN];
+
freq = bss->freq;
wpa_printf(MSG_DEBUG, "P2P: Target GO operating frequency "
"from BSS table: %d MHz (SSID %s)", freq,
wpa_ssid_txt(bss->ssid, bss->ssid_len));
+ if (p2p_parse_dev_addr((const u8 *) (bss + 1), bss->ie_len,
+ dev_addr) == 0 &&
+ os_memcmp(wpa_s->pending_join_dev_addr,
+ wpa_s->pending_join_iface_addr, ETH_ALEN) == 0 &&
+ os_memcmp(dev_addr, wpa_s->pending_join_dev_addr,
+ ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Update target GO device address based on BSS entry: " MACSTR " (was " MACSTR ")",
+ MAC2STR(dev_addr),
+ MAC2STR(wpa_s->pending_join_dev_addr));
+ os_memcpy(wpa_s->pending_join_dev_addr, dev_addr,
+ ETH_ALEN);
+ }
}
if (freq > 0) {
u16 method;
@@ -5226,6 +5257,7 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
wpa_s->conf->p2p_oper_reg_class == 116 ||
wpa_s->conf->p2p_oper_reg_class == 117 ||
wpa_s->conf->p2p_oper_reg_class == 124 ||
+ wpa_s->conf->p2p_oper_reg_class == 125 ||
wpa_s->conf->p2p_oper_reg_class == 126 ||
wpa_s->conf->p2p_oper_reg_class == 127) &&
freq_included(channels,
@@ -5721,7 +5753,7 @@ void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
}
if (wpa_s->global->p2p)
p2p_wps_success_cb(wpa_s->global->p2p, peer_addr);
- wpas_group_formation_completed(wpa_s, 1);
+ wpas_group_formation_completed(wpa_s, 1, 0);
}
@@ -5997,7 +6029,8 @@ int wpas_p2p_assoc_req_ie(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s, const u8 *addr,
const u8 *dst, const u8 *bssid,
- const u8 *ie, size_t ie_len, int ssi_signal)
+ const u8 *ie, size_t ie_len,
+ unsigned int rx_freq, int ssi_signal)
{
if (wpa_s->global->p2p_disabled)
return 0;
@@ -6005,7 +6038,7 @@ int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s, const u8 *addr,
return 0;
switch (p2p_probe_req_rx(wpa_s->global->p2p, addr, dst, bssid,
- ie, ie_len)) {
+ ie, ie_len, rx_freq)) {
case P2P_PREQ_NOT_P2P:
wpas_notify_preq(wpa_s, addr, dst, bssid, ie, ie_len,
ssi_signal);
@@ -6737,7 +6770,7 @@ int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s)
"session overlap");
if (wpa_s != wpa_s->parent)
wpa_msg_ctrl(wpa_s->parent, MSG_INFO, WPS_EVENT_OVERLAP);
- wpas_p2p_group_formation_failed(wpa_s);
+ wpas_p2p_group_formation_failed(wpa_s, 0);
return 1;
}
@@ -6847,7 +6880,7 @@ int wpas_p2p_cancel(struct wpa_supplicant *wpa_s)
eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
wpa_s->parent, NULL);
if (wpa_s->p2p_in_provisioning) {
- wpas_group_formation_completed(wpa_s, 0);
+ wpas_group_formation_completed(wpa_s, 0, 0);
break;
}
wpas_p2p_group_delete(wpa_s,
@@ -6857,7 +6890,7 @@ int wpas_p2p_cancel(struct wpa_supplicant *wpa_s)
wpa_printf(MSG_DEBUG, "P2P: Interface %s in invitation found - cancelling",
wpa_s->ifname);
found = 1;
- wpas_p2p_group_formation_failed(wpa_s);
+ wpas_p2p_group_formation_failed(wpa_s, 0);
}
}
@@ -7053,7 +7086,7 @@ void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
*/
if (wpa_s->global->p2p)
p2p_wps_success_cb(wpa_s->global->p2p, addr);
- wpas_group_formation_completed(wpa_s, 1);
+ wpas_group_formation_completed(wpa_s, 1, 0);
}
}
if (!wpa_s->p2p_go_group_formation_completed) {
@@ -7078,7 +7111,7 @@ static int wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
if (wpa_s->global->p2p_group_formation)
group = wpa_s->global->p2p_group_formation;
- wpa_s = wpa_s->parent;
+ wpa_s = wpa_s->global->p2p_init_wpa_s;
offchannel_send_action_done(wpa_s);
if (group_added)
ret = wpas_p2p_group_delete(group, P2P_GROUP_REMOVAL_SILENT);
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 0b9ebc0b..1df34d08 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -66,7 +66,6 @@ int wpas_p2p_listen_start(struct wpa_supplicant *wpa_s, unsigned int timeout);
int wpas_p2p_assoc_req_ie(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
u8 *buf, size_t len, int p2p_group);
void wpas_p2p_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ies);
-void wpas_p2p_group_formation_failed(struct wpa_supplicant *wpa_s);
u64 wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst,
const struct wpabuf *tlvs);
u64 wpas_p2p_sd_request_asp(struct wpa_supplicant *wpa_s, const u8 *dst, u8 id,
@@ -158,7 +157,7 @@ void wpas_p2p_update_config(struct wpa_supplicant *wpa_s);
int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s, const u8 *addr,
const u8 *dst, const u8 *bssid,
const u8 *ie, size_t ie_len,
- int ssi_signal);
+ unsigned int rx_freq, int ssi_signal);
void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
int registrar);
void wpas_p2p_update_channel_list(struct wpa_supplicant *wpa_s);
@@ -212,7 +211,7 @@ static inline int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s,
const u8 *addr,
const u8 *dst, const u8 *bssid,
const u8 *ie, size_t ie_len,
- int ssi_signal)
+ unsigned int rx_freq, int ssi_signal)
{
return 0;
}
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 97e575ca..c5d83331 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -4099,45 +4099,49 @@ static void wpa_cli_interactive(void)
}
+static void wpa_cli_action_ping(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_ctrl *ctrl = eloop_ctx;
+ char buf[256];
+ size_t len;
+
+ /* verify that connection is still working */
+ len = sizeof(buf) - 1;
+ if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
+ wpa_cli_action_cb) < 0 ||
+ len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
+ printf("wpa_supplicant did not reply to PING command - exiting\n");
+ eloop_terminate();
+ return;
+ }
+ eloop_register_timeout(ping_interval, 0, wpa_cli_action_ping,
+ ctrl, NULL);
+}
+
+
+static void wpa_cli_action_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct wpa_ctrl *ctrl = eloop_ctx;
+
+ wpa_cli_recv_pending(ctrl, 1);
+}
+
+
static void wpa_cli_action(struct wpa_ctrl *ctrl)
{
#ifdef CONFIG_ANSI_C_EXTRA
/* TODO: ANSI C version(?) */
printf("Action processing not supported in ANSI C build.\n");
#else /* CONFIG_ANSI_C_EXTRA */
- fd_set rfds;
- int fd, res;
- struct timeval tv;
- char buf[256]; /* note: large enough to fit in unsolicited messages */
- size_t len;
+ int fd;
fd = wpa_ctrl_get_fd(ctrl);
-
- while (!wpa_cli_quit) {
- FD_ZERO(&rfds);
- FD_SET(fd, &rfds);
- tv.tv_sec = ping_interval;
- tv.tv_usec = 0;
- res = select(fd + 1, &rfds, NULL, NULL, &tv);
- if (res < 0 && errno != EINTR) {
- perror("select");
- break;
- }
-
- if (FD_ISSET(fd, &rfds))
- wpa_cli_recv_pending(ctrl, 1);
- else {
- /* verify that connection is still working */
- len = sizeof(buf) - 1;
- if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
- wpa_cli_action_cb) < 0 ||
- len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
- printf("wpa_supplicant did not reply to PING "
- "command - exiting\n");
- break;
- }
- }
- }
+ eloop_register_timeout(ping_interval, 0, wpa_cli_action_ping,
+ ctrl, NULL);
+ eloop_register_read_sock(fd, wpa_cli_action_receive, ctrl, NULL);
+ eloop_run();
+ eloop_cancel_timeout(wpa_cli_action_ping, ctrl, NULL);
+ eloop_unregister_read_sock(fd);
#endif /* CONFIG_ANSI_C_EXTRA */
}
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index e833c3ac..8fba9382 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -728,6 +728,30 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
wpa_s->normal_scans = 0;
}
+#ifdef CONFIG_P2P
+ /*
+ * P2PS client has to reply to Probe Request frames received on the
+ * group operating channel. Enable Probe Request frame reporting for
+ * P2P connected client in case p2p_cli_probe configuration property is
+ * set to 1.
+ */
+ if (wpa_s->conf->p2p_cli_probe && wpa_s->current_ssid &&
+ wpa_s->current_ssid->mode == WPAS_MODE_INFRA &&
+ wpa_s->current_ssid->p2p_group) {
+ if (state == WPA_COMPLETED && !wpa_s->p2p_cli_probe) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Enable CLI Probe Request RX reporting");
+ wpa_s->p2p_cli_probe =
+ wpa_drv_probe_req_report(wpa_s, 1) >= 0;
+ } else if (state != WPA_COMPLETED && wpa_s->p2p_cli_probe) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Disable CLI Probe Request RX reporting");
+ wpa_s->p2p_cli_probe = 0;
+ wpa_drv_probe_req_report(wpa_s, 0);
+ }
+ }
+#endif /* CONFIG_P2P */
+
if (state != WPA_SCANNING)
wpa_supplicant_notify_scanning(wpa_s, 0);
@@ -4427,7 +4451,8 @@ struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
if (wpa_s->global->p2p == NULL &&
!wpa_s->global->p2p_disabled && !wpa_s->conf->p2p_disabled &&
(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
- wpas_p2p_add_p2pdev_interface(wpa_s, iface->conf_p2p_dev) < 0) {
+ wpas_p2p_add_p2pdev_interface(
+ wpa_s, wpa_s->global->params.conf_p2p_dev) < 0) {
wpa_printf(MSG_INFO,
"P2P: Failed to enable P2P Device interface");
/* Try to continue without. P2P will be disabled. */
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index bc6425d6..dd5b245c 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -66,17 +66,6 @@ struct wpa_interface {
*/
const char *confanother;
-#ifdef CONFIG_P2P
- /**
- * conf_p2p_dev - Configuration file used to hold the
- * P2P Device configuration parameters.
- *
- * This can also be %NULL. In such a case, if a P2P Device dedicated
- * interfaces is created, the main configuration file will be used.
- */
- const char *conf_p2p_dev;
-#endif /* CONFIG_P2P */
-
/**
* ctrl_interface - Control interface parameter
*
@@ -227,6 +216,18 @@ struct wpa_params {
* its internal entropy store over restarts.
*/
char *entropy_file;
+
+#ifdef CONFIG_P2P
+ /**
+ * conf_p2p_dev - Configuration file used to hold the
+ * P2P Device configuration parameters.
+ *
+ * This can also be %NULL. In such a case, if a P2P Device dedicated
+ * interfaces is created, the main configuration file will be used.
+ */
+ const char *conf_p2p_dev;
+#endif /* CONFIG_P2P */
+
};
struct p2p_srv_bonjour {
@@ -366,6 +367,8 @@ struct wps_ap_info {
} type;
unsigned int tries;
struct os_reltime last_attempt;
+ unsigned int pbc_active;
+ u8 uuid[WPS_UUID_LEN];
};
struct wpa_ssid_value {
@@ -818,6 +821,7 @@ struct wpa_supplicant {
unsigned int p2p_peer_oob_pk_hash_known:1;
unsigned int p2p_disable_ip_addr_req:1;
unsigned int p2ps_join_addr_valid:1;
+ unsigned int p2p_cli_probe:1;
int p2p_persistent_go_freq;
int p2p_persistent_id;
int p2p_go_intent;
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index a97c2a8d..2db79149 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -1717,10 +1717,10 @@ int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s,
int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
struct wpa_bss *selected, struct wpa_ssid *ssid)
{
- const u8 *sel_uuid, *uuid;
+ const u8 *sel_uuid;
struct wpabuf *wps_ie;
int ret = 0;
- struct wpa_bss *bss;
+ size_t i;
if (!eap_is_wps_pbc_enrollee(&ssid->eap))
return 0;
@@ -1741,40 +1741,28 @@ int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
sel_uuid = NULL;
}
- dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
- struct wpabuf *ie;
- if (bss == selected)
- continue;
- ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
- if (!ie)
- continue;
- if (!wps_is_selected_pbc_registrar(ie)) {
- wpabuf_free(ie);
+ for (i = 0; i < wpa_s->num_wps_ap; i++) {
+ struct wps_ap_info *ap = &wpa_s->wps_ap[i];
+
+ if (!ap->pbc_active ||
+ os_memcmp(selected->bssid, ap->bssid, ETH_ALEN) == 0)
continue;
- }
+
wpa_printf(MSG_DEBUG, "WPS: Another BSS in active PBC mode: "
- MACSTR, MAC2STR(bss->bssid));
- uuid = wps_get_uuid_e(ie);
+ MACSTR, MAC2STR(ap->bssid));
wpa_hexdump(MSG_DEBUG, "WPS: UUID of the other BSS",
- uuid, UUID_LEN);
- if (os_memcmp(selected->bssid, bss->bssid, ETH_ALEN) == 0) {
- wpabuf_free(ie);
- continue;
- }
- if (sel_uuid == NULL || uuid == NULL ||
- os_memcmp(sel_uuid, uuid, UUID_LEN) != 0) {
+ ap->uuid, UUID_LEN);
+ if (sel_uuid == NULL ||
+ os_memcmp(sel_uuid, ap->uuid, UUID_LEN) != 0) {
ret = 1; /* PBC overlap */
wpa_msg(wpa_s, MSG_INFO, "WPS: PBC overlap detected: "
MACSTR " and " MACSTR,
MAC2STR(selected->bssid),
- MAC2STR(bss->bssid));
- wpabuf_free(ie);
+ MAC2STR(ap->bssid));
break;
}
/* TODO: verify that this is reasonable dual-band situation */
-
- wpabuf_free(ie);
}
wpabuf_free(wps_ie);
@@ -2798,7 +2786,8 @@ static void wpas_wps_update_ap_info_bss(struct wpa_supplicant *wpa_s,
struct wpabuf *wps;
enum wps_ap_info_type type;
struct wps_ap_info *ap;
- int r;
+ int r, pbc_active;
+ const u8 *uuid;
if (wpa_scan_get_vendor_ie(res, WPS_IE_VENDOR_TYPE) == NULL)
return;
@@ -2815,7 +2804,8 @@ static void wpas_wps_update_ap_info_bss(struct wpa_supplicant *wpa_s,
else
type = WPS_AP_NOT_SEL_REG;
- wpabuf_free(wps);
+ uuid = wps_get_uuid_e(wps);
+ pbc_active = wps_is_selected_pbc_registrar(wps);
ap = wpas_wps_get_ap_info(wpa_s, res->bssid);
if (ap) {
@@ -2827,13 +2817,16 @@ static void wpas_wps_update_ap_info_bss(struct wpa_supplicant *wpa_s,
if (type != WPS_AP_NOT_SEL_REG)
wpa_blacklist_del(wpa_s, ap->bssid);
}
- return;
+ ap->pbc_active = pbc_active;
+ if (uuid)
+ os_memcpy(ap->uuid, uuid, WPS_UUID_LEN);
+ goto out;
}
ap = os_realloc_array(wpa_s->wps_ap, wpa_s->num_wps_ap + 1,
sizeof(struct wps_ap_info));
if (ap == NULL)
- return;
+ goto out;
wpa_s->wps_ap = ap;
ap = &wpa_s->wps_ap[wpa_s->num_wps_ap];
@@ -2842,8 +2835,14 @@ static void wpas_wps_update_ap_info_bss(struct wpa_supplicant *wpa_s,
os_memset(ap, 0, sizeof(*ap));
os_memcpy(ap->bssid, res->bssid, ETH_ALEN);
ap->type = type;
+ ap->pbc_active = pbc_active;
+ if (uuid)
+ os_memcpy(ap->uuid, uuid, WPS_UUID_LEN);
wpa_printf(MSG_DEBUG, "WPS: AP " MACSTR " type %d added",
MAC2STR(ap->bssid), ap->type);
+
+out:
+ wpabuf_free(wps);
}