aboutsummaryrefslogtreecommitdiff
path: root/src/p2p/p2p.c
diff options
context:
space:
mode:
authorDmitry Shmidt <dimitrysh@google.com>2015-06-23 11:21:28 -0700
committerDmitry Shmidt <dimitrysh@google.com>2015-06-23 11:21:28 -0700
commita3dc30964aa24aea2b518246f6812663a1103490 (patch)
tree8ac6b6c44b68ed0823ebf7fafd9b1ca85589d05f /src/p2p/p2p.c
parent7a53dbb56693ee9f55c0cab1a8297436511e8613 (diff)
downloadwpa_supplicant_8-a3dc30964aa24aea2b518246f6812663a1103490.tar.gz
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>
Diffstat (limited to 'src/p2p/p2p.c')
-rw-r--r--src/p2p/p2p.c173
1 files changed, 96 insertions, 77 deletions
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);