am a3dc3096: Cumulative patch from commit f43c1ae7989c38fe15756f12a9196a1cf798b4d7
* commit 'a3dc30964aa24aea2b518246f6812663a1103490':
Cumulative patch from commit f43c1ae7989c38fe15756f12a9196a1cf798b4d7
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index 10f50d8..49f43f1 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -892,6 +892,7 @@
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 3c7bd6f..d4fd36e 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -108,6 +108,7 @@
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 c3573a4..c14eeda 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -117,9 +117,6 @@
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 60c8f8c..f3f7edd 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -633,7 +633,7 @@
{
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 75cc24e..be5c7a8 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -49,6 +49,9 @@
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 b89a1f4..fd1c8dd 100644
--- a/src/ap/vlan_init.c
+++ b/src/ap/vlan_init.c
@@ -35,6 +35,90 @@
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 @@
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 @@
"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 @@
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 @@
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 @@
os_snprintf(vlan_ifname,
sizeof(vlan_ifname),
"vlan%d", vlan->vlan_id);
- if (vlan->clean & DVLAN_CLEAN_VLAN_PORT)
- br_delif(br_name, vlan_ifname);
- ifconfig_down(vlan_ifname);
- if (vlan->clean & DVLAN_CLEAN_VLAN)
+ clean = dyn_iface_put(hapd, vlan_ifname);
+
+ if (clean & DVLAN_CLEAN_VLAN_PORT)
+ br_delif(br_name, vlan_ifname);
+
+ 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 @@
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 56b1122..d69448b 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 @@
{ (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 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 @@
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 e23007a..82dd707 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -580,7 +580,7 @@
};
static const char *const cn_op_class_cc[] = {
- "CN", "CA", NULL
+ "CN", NULL
};
@@ -630,6 +630,10 @@
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 @@
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 8f28ca8..37ab000 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -2770,8 +2770,11 @@
}
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 0324339..d452d8c 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1940,10 +1940,12 @@
* @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 b8e7864..aaada0a 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -1840,7 +1840,7 @@
#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 84b98fb..14c52d2 100644
--- a/src/drivers/driver_hostap.c
+++ b/src/drivers/driver_hostap.c
@@ -266,7 +266,8 @@
}
-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 590731d..20f5321 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -87,7 +87,6 @@
#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_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 @@
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 b5071b4..acfe959 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -232,7 +232,6 @@
#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 3cc9a65..f3a39f6 100644
--- a/src/drivers/driver_nl80211_android.c
+++ b/src/drivers/driver_nl80211_android.c
@@ -188,33 +188,3 @@
}
-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 248b57b..f636e74 100644
--- a/src/eap_peer/eap_fast.c
+++ b/src/eap_peer/eap_fast.c
@@ -267,8 +267,8 @@
}
-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 @@
if (sks == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive "
"session_key_seed");
- return;
+ return -1;
}
/*
@@ -294,11 +294,12 @@
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 @@
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 @@
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 @@
} 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 c02044b..16ffac4 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -297,7 +297,7 @@
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 @@
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 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 @@
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 @@
/*
* 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 @@
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 @@
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 @@
* 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 @@
/* 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 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 @@
}
-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 @@
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 @@
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 @@
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 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 @@
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_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 @@
* 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 @@
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_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_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 @@
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 @@
"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 @@
"[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 @@
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 @@
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 @@
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 6b0ba80..67b8bdb 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -570,12 +570,14 @@
* 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 @@
* 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 @@
* @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 92c9206..6b6e770 100644
--- a/src/p2p/p2p_build.c
+++ b/src/p2p/p2p_build.c
@@ -353,10 +353,10 @@
/* 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 @@
}
+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;
+
+ 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;
+ }
+
+ return 0;
+}
+
+
+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;
+
+ 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;
+
+ if (info_len + *total_len > MAX_SVC_ADV_LEN) {
+ p2p_dbg(p2p,
+ "Unsufficient buffer, failed to add advertised service info");
+ return -1;
+ }
+
+ 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;
+ }
+
+ if (*ie_len) {
+ int ie_data_len = (*pos - *ie_len) - 1;
+
+ 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(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)];
+
+ 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);
+
+ 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 (remaining < svc_len) {
+ /* split svc_name between two or three IEs */
+ size_t front = remaining;
+ size_t back = svc_len - front;
+
+ if (front)
+ wpabuf_put_data(buf, svc_name, front);
+
+ 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 {
+ 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;
- struct wpabuf *tmp_buf;
- u8 *tag_len = NULL, *ie_len = NULL;
- size_t svc_len = 0, remaining = 0, total_len = 0;
+ 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)
+ 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) {
- u8 count = hash_count;
const u8 *test = hash;
+ u8 i;
- 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;
- }
-
- if (os_memcmp(test, adv->hash, P2PS_HASH_LEN) == 0)
- goto hash_match;
-
+ 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;
}
-
- /* 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));
- }
- }
-
- svc_len = os_strlen(adv->svc_name);
-
- if (7 + svc_len + total_len > MAX_SVC_ADV_LEN) {
- /* Can't fit... return wildcard */
- total_len = MAX_SVC_ADV_LEN + 1;
- break;
- }
-
- 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));
- }
-
- /* 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;
- }
-
- /* adv_id config_methods svc_string */
- total_len += sizeof(u32) + sizeof(u16) + sizeof(u8) + svc_len;
}
- if (tag_len)
- p2p_buf_update_ie_hdr(tmp_buf, tag_len);
-
- if (ie_len)
- WPA_PUT_LE16(ie_len, (u16) total_len);
-
-wild_hash:
- /* If all fit, return matching instances, otherwise the wildcard */
- if (total_len <= MAX_SVC_ADV_LEN) {
+ if (found)
wpabuf_put_buf(buf, tmp_buf);
- } 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_free(tmp_buf);
}
diff --git a/src/p2p/p2p_dev_disc.c b/src/p2p/p2p_dev_disc.c
index 86bae1a..98805fe 100644
--- a/src/p2p/p2p_dev_disc.c
+++ b/src/p2p/p2p_dev_disc.c
@@ -314,7 +314,7 @@
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 63837eb..19f1daa 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -379,7 +379,7 @@
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 289a62d..a1042d2 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 @@
#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 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 @@
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 @@
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 44a6bbf..f5454f7 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -134,6 +134,9 @@
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 @@
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 bc84269..86558f7 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -881,8 +881,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
/* 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 @@
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 f32751d..eee3c5a 100644
--- a/src/p2p/p2p_utils.c
+++ b/src/p2p/p2p_utils.c
@@ -101,6 +101,15 @@
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 82a8999..b7a6dba 100644
--- a/src/utils/wpa_debug.c
+++ b/src/utils/wpa_debug.c
@@ -307,7 +307,7 @@
"%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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 bfb69fc..f3960c5 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -485,8 +485,13 @@
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 2fe032d..239c3e8 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -4180,6 +4180,7 @@
{ 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 545a4bd..d8ca054 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -968,6 +968,18 @@
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 2508ca9..e946567 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -1131,6 +1131,9 @@
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 f32b7c9..0c5ea8f 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -4597,16 +4597,20 @@
/* 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_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(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 @@
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 22001cf..f49ba07 100644
--- a/wpa_supplicant/ctrl_iface_unix.c
+++ b/wpa_supplicant/ctrl_iface_unix.c
@@ -197,6 +197,13 @@
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 @@
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 fb674d4..a3bf1e3 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -603,6 +603,7 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
}
+/**
+ * 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 @@
/**
- *
- * 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 @@
/**
* 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 @@
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 @@
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 @@
/**
* 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 97db9a8..2a7e2cf 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -1601,6 +1601,30 @@
/**
+ * 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 9afdc05..50f72ec 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_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 56e9033..e9d60df 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -416,6 +416,64 @@
}
+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 d0953f1..2aecbbe 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_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 ffee1f7..1fcb180 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -286,11 +286,13 @@
}
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 80045e7..7be352d 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -2557,6 +2557,21 @@
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_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 @@
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 @@
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 9f5a198..1c93306 100644
--- a/wpa_supplicant/main.c
+++ b/wpa_supplicant/main.c
@@ -237,7 +237,7 @@
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 5c8a3b2..b9ebd38 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -126,6 +126,8 @@
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_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 @@
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 @@
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 @@
{
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 @@
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 @@
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 @@
#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 @@
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 @@
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 @@
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 @@
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 @@
}
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_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 @@
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 @@
"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 @@
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 @@
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 @@
*/
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 @@
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 0b9ebc0..1df34d0 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -66,7 +66,6 @@
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 @@
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 @@
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 97e575c..c5d8333 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -4099,45 +4099,49 @@
}
+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 e833c3a..8fba938 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -728,6 +728,30 @@
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 @@
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 bc6425d..dd5b245 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -66,17 +66,6 @@
*/
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 @@
* 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 @@
} 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 @@
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 a97c2a8..2db7914 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -1717,10 +1717,10 @@
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 @@
sel_uuid = NULL;
}
- dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
- struct wpabuf *ie;
- if (bss == selected)
+ 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;
- 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);
- 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 @@
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 @@
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 @@
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 @@
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);
}