Cumulative patch from commit f43c1ae7989c38fe15756f12a9196a1cf798b4d7
f43c1ae P2P: Handle P2P Device dedicated interface parent removal
1ac977b nl8021: Allow sending wowlan configuration on any interface
4899702 nl80211: Remove android_genl_ctrl_resolve()
38dcc86 P2P: Consider ht/vht on P2P_GROUP_ADD command (with no params)
29292d5 ctrl_iface: Make p2p_ctrl_group_add() more robust
e4a80d8 P2P: Fix secondary channel selection for HT40
4e71758 dbus: Add RemoveClient method to remove a client from local GO
f0a79c9 D-Bus: Fix wpas_dbus_register_peer() documentation
95d62a6 D-Bus: Add missing params in WPS function documentation
790429b D-Bus: Fix function documentation for wpas_dbus_signal_p2p_go_neg_resp()
92fe746 D-Bus: Add function documentation for wpas_dbus_signal_p2p_go_neg_req()
e1dffa3 P2P: Fix PBC overlap detection
de7b02f P2P: Use the P2P Device interface in wpas_p2p_fallback_to_go_neg()
6b5147a P2P: Fix memory leak in p2p_process_nfc_connection_handover()
33ba27d EAP-FAST peer: Stop immediately on key derivation failure
144b6a0 OpenSSL: Fix memory leak on an openssl_tls_prf() error path
50a9efe P2PS: Fix Probe Response frame building in error cases
509f269 P2PS: Fix org.wi-fi.wfds matching when building the response
5fa5f84 P2PS: Add more debug prints for service info building
fdde3db P2PS: Remove unnecessary service hash filtering from p2p_reply_probe()
f2e0eec P2PS: Do not ignore other hashes if org.wi-fi.wfds hash is included
ebdc32f P2PS: Fix service hash matching for org.wi-fi.wfds
24533f7 P2PS: Fix p2p_find handling to allow "wildcard" with other hash values
f33a31b P2PS: Verify service name length in P2P_FIND command
129b621 P2PS: Fix P2P_FIND seek parameter parsing
83e520e P2PS: Add a wildcard with other advertised service info
c5d3cad P2PS: Re-factor p2p_buf_add_service_instance function
13f6f61 wpa_cli: Fix process termination in wpa_cli action mode case
b4c0f58 Clear allocated debug message buffers explicitly
14fd033 Clear control interface command explicitly from stack
d95c599 P2P: Fix group interface addition failure properly for concurrent case
e12c400 P2PS: Refactor p2p_data::query_hash and p2p_data::query_count use
4839da4 P2P: Add vendor elements into Invitation Response frames
886f583 P2PS: Delete p2ps_svc_found from struct p2p_data
3f048aa P2PS: Add a function to free a PD context
8f52409 P2P: Prefer direct Probe Response frames over GO's client list
4e8817f P2P: Use more precise device timestamping for group clients
0799b3f P2P: Specify frequency when sending Probe Response frame
5d180a7 drivers: Add freq parameter to send_mlme() function
5143e7e P2P: Fix return value of p2p_reply_probe() and p2p_probe_req_rx()
07c1e98 P2PS: Enable Probe Request frame processing by P2P Client
734ddf6 P2P: Add rx_freq parameter to Probe Request frame handler
e6012e8 P2P: Update target GO Device Address from BSS entry during join
a9a4841 Remove duplicated country code from operating class lists
132dfbe Fix removal of tagged interface and bridge when multiple BSS share them
e11776a Combine multiple function calls to a single statement
b649c0a dbus: Add Reconnect command to D-Bus Interface
f4a234a doc: Update D-Bus GONegotiationRequest Signal: add device_go_intent
0c9fb14 P2P: Add Operating class 125 for P2P supported channels
Change-Id: I782c1403985248ff994f484282efa6519fd369e9
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
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 */