aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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);
}