1e5b75505Sopenharmony_ci/*
2e5b75505Sopenharmony_ci * Wi-Fi Direct - P2P service discovery
3e5b75505Sopenharmony_ci * Copyright (c) 2009, Atheros Communications
4e5b75505Sopenharmony_ci *
5e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license.
6e5b75505Sopenharmony_ci * See README for more details.
7e5b75505Sopenharmony_ci */
8e5b75505Sopenharmony_ci
9e5b75505Sopenharmony_ci#include "includes.h"
10e5b75505Sopenharmony_ci
11e5b75505Sopenharmony_ci#include "common.h"
12e5b75505Sopenharmony_ci#include "common/ieee802_11_defs.h"
13e5b75505Sopenharmony_ci#include "common/gas.h"
14e5b75505Sopenharmony_ci#include "p2p_i.h"
15e5b75505Sopenharmony_ci#include "p2p.h"
16e5b75505Sopenharmony_ci
17e5b75505Sopenharmony_ci
18e5b75505Sopenharmony_ci#ifdef CONFIG_WIFI_DISPLAY
19e5b75505Sopenharmony_cistatic int wfd_wsd_supported(struct wpabuf *wfd)
20e5b75505Sopenharmony_ci{
21e5b75505Sopenharmony_ci	const u8 *pos, *end;
22e5b75505Sopenharmony_ci	u8 subelem;
23e5b75505Sopenharmony_ci	u16 len;
24e5b75505Sopenharmony_ci
25e5b75505Sopenharmony_ci	if (wfd == NULL)
26e5b75505Sopenharmony_ci		return 0;
27e5b75505Sopenharmony_ci
28e5b75505Sopenharmony_ci	pos = wpabuf_head(wfd);
29e5b75505Sopenharmony_ci	end = pos + wpabuf_len(wfd);
30e5b75505Sopenharmony_ci
31e5b75505Sopenharmony_ci	while (end - pos >= 3) {
32e5b75505Sopenharmony_ci		subelem = *pos++;
33e5b75505Sopenharmony_ci		len = WPA_GET_BE16(pos);
34e5b75505Sopenharmony_ci		pos += 2;
35e5b75505Sopenharmony_ci		if (len > end - pos)
36e5b75505Sopenharmony_ci			break;
37e5b75505Sopenharmony_ci
38e5b75505Sopenharmony_ci		if (subelem == WFD_SUBELEM_DEVICE_INFO && len >= 6) {
39e5b75505Sopenharmony_ci			u16 info = WPA_GET_BE16(pos);
40e5b75505Sopenharmony_ci			return !!(info & 0x0040);
41e5b75505Sopenharmony_ci		}
42e5b75505Sopenharmony_ci
43e5b75505Sopenharmony_ci		pos += len;
44e5b75505Sopenharmony_ci	}
45e5b75505Sopenharmony_ci
46e5b75505Sopenharmony_ci	return 0;
47e5b75505Sopenharmony_ci}
48e5b75505Sopenharmony_ci#endif /* CONFIG_WIFI_DISPLAY */
49e5b75505Sopenharmony_ci
50e5b75505Sopenharmony_cistruct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p,
51e5b75505Sopenharmony_ci					 struct p2p_device *dev)
52e5b75505Sopenharmony_ci{
53e5b75505Sopenharmony_ci	struct p2p_sd_query *q;
54e5b75505Sopenharmony_ci	int wsd = 0;
55e5b75505Sopenharmony_ci	int count = 0;
56e5b75505Sopenharmony_ci
57e5b75505Sopenharmony_ci	if (!(dev->info.dev_capab & P2P_DEV_CAPAB_SERVICE_DISCOVERY))
58e5b75505Sopenharmony_ci		return NULL; /* peer does not support SD */
59e5b75505Sopenharmony_ci#ifdef CONFIG_WIFI_DISPLAY
60e5b75505Sopenharmony_ci	if (wfd_wsd_supported(dev->info.wfd_subelems))
61e5b75505Sopenharmony_ci		wsd = 1;
62e5b75505Sopenharmony_ci#endif /* CONFIG_WIFI_DISPLAY */
63e5b75505Sopenharmony_ci
64e5b75505Sopenharmony_ci	for (q = p2p->sd_queries; q; q = q->next) {
65e5b75505Sopenharmony_ci		/* Use WSD only if the peer indicates support or it */
66e5b75505Sopenharmony_ci		if (q->wsd && !wsd)
67e5b75505Sopenharmony_ci			continue;
68e5b75505Sopenharmony_ci		/* if the query is a broadcast query */
69e5b75505Sopenharmony_ci		if (q->for_all_peers) {
70e5b75505Sopenharmony_ci			/*
71e5b75505Sopenharmony_ci			 * check if there are any broadcast queries pending for
72e5b75505Sopenharmony_ci			 * this device
73e5b75505Sopenharmony_ci			 */
74e5b75505Sopenharmony_ci			if (dev->sd_pending_bcast_queries <= 0)
75e5b75505Sopenharmony_ci				return NULL;
76e5b75505Sopenharmony_ci			/* query number that needs to be send to the device */
77e5b75505Sopenharmony_ci			if (count == dev->sd_pending_bcast_queries - 1)
78e5b75505Sopenharmony_ci				goto found;
79e5b75505Sopenharmony_ci			count++;
80e5b75505Sopenharmony_ci		}
81e5b75505Sopenharmony_ci		if (!q->for_all_peers &&
82e5b75505Sopenharmony_ci		    os_memcmp(q->peer, dev->info.p2p_device_addr, ETH_ALEN) ==
83e5b75505Sopenharmony_ci		    0)
84e5b75505Sopenharmony_ci			goto found;
85e5b75505Sopenharmony_ci	}
86e5b75505Sopenharmony_ci
87e5b75505Sopenharmony_ci	return NULL;
88e5b75505Sopenharmony_ci
89e5b75505Sopenharmony_cifound:
90e5b75505Sopenharmony_ci	if (dev->sd_reqs > 100) {
91e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Too many SD request attempts to " MACSTR
92e5b75505Sopenharmony_ci			" - skip remaining queries",
93e5b75505Sopenharmony_ci			MAC2STR(dev->info.p2p_device_addr));
94e5b75505Sopenharmony_ci		return NULL;
95e5b75505Sopenharmony_ci	}
96e5b75505Sopenharmony_ci	return q;
97e5b75505Sopenharmony_ci}
98e5b75505Sopenharmony_ci
99e5b75505Sopenharmony_ci
100e5b75505Sopenharmony_cistatic void p2p_decrease_sd_bc_queries(struct p2p_data *p2p, int query_number)
101e5b75505Sopenharmony_ci{
102e5b75505Sopenharmony_ci	struct p2p_device *dev;
103e5b75505Sopenharmony_ci
104e5b75505Sopenharmony_ci	p2p->num_p2p_sd_queries--;
105e5b75505Sopenharmony_ci	dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
106e5b75505Sopenharmony_ci		if (query_number <= dev->sd_pending_bcast_queries - 1) {
107e5b75505Sopenharmony_ci			/*
108e5b75505Sopenharmony_ci			 * Query not yet sent to the device and it is to be
109e5b75505Sopenharmony_ci			 * removed, so update the pending count.
110e5b75505Sopenharmony_ci			*/
111e5b75505Sopenharmony_ci			dev->sd_pending_bcast_queries--;
112e5b75505Sopenharmony_ci		}
113e5b75505Sopenharmony_ci	}
114e5b75505Sopenharmony_ci}
115e5b75505Sopenharmony_ci
116e5b75505Sopenharmony_ci
117e5b75505Sopenharmony_cistatic int p2p_unlink_sd_query(struct p2p_data *p2p,
118e5b75505Sopenharmony_ci			       struct p2p_sd_query *query)
119e5b75505Sopenharmony_ci{
120e5b75505Sopenharmony_ci	struct p2p_sd_query *q, *prev;
121e5b75505Sopenharmony_ci	int query_number = 0;
122e5b75505Sopenharmony_ci
123e5b75505Sopenharmony_ci	q = p2p->sd_queries;
124e5b75505Sopenharmony_ci	prev = NULL;
125e5b75505Sopenharmony_ci	while (q) {
126e5b75505Sopenharmony_ci		if (q == query) {
127e5b75505Sopenharmony_ci			/* If the query is a broadcast query, decrease one from
128e5b75505Sopenharmony_ci			 * all the devices */
129e5b75505Sopenharmony_ci			if (query->for_all_peers)
130e5b75505Sopenharmony_ci				p2p_decrease_sd_bc_queries(p2p, query_number);
131e5b75505Sopenharmony_ci			if (prev)
132e5b75505Sopenharmony_ci				prev->next = q->next;
133e5b75505Sopenharmony_ci			else
134e5b75505Sopenharmony_ci				p2p->sd_queries = q->next;
135e5b75505Sopenharmony_ci			if (p2p->sd_query == query)
136e5b75505Sopenharmony_ci				p2p->sd_query = NULL;
137e5b75505Sopenharmony_ci			return 1;
138e5b75505Sopenharmony_ci		}
139e5b75505Sopenharmony_ci		if (q->for_all_peers)
140e5b75505Sopenharmony_ci			query_number++;
141e5b75505Sopenharmony_ci		prev = q;
142e5b75505Sopenharmony_ci		q = q->next;
143e5b75505Sopenharmony_ci	}
144e5b75505Sopenharmony_ci	return 0;
145e5b75505Sopenharmony_ci}
146e5b75505Sopenharmony_ci
147e5b75505Sopenharmony_ci
148e5b75505Sopenharmony_cistatic void p2p_free_sd_query(struct p2p_sd_query *q)
149e5b75505Sopenharmony_ci{
150e5b75505Sopenharmony_ci	if (q == NULL)
151e5b75505Sopenharmony_ci		return;
152e5b75505Sopenharmony_ci	wpabuf_free(q->tlvs);
153e5b75505Sopenharmony_ci	os_free(q);
154e5b75505Sopenharmony_ci}
155e5b75505Sopenharmony_ci
156e5b75505Sopenharmony_ci
157e5b75505Sopenharmony_civoid p2p_free_sd_queries(struct p2p_data *p2p)
158e5b75505Sopenharmony_ci{
159e5b75505Sopenharmony_ci	struct p2p_sd_query *q, *prev;
160e5b75505Sopenharmony_ci	q = p2p->sd_queries;
161e5b75505Sopenharmony_ci	p2p->sd_queries = NULL;
162e5b75505Sopenharmony_ci	while (q) {
163e5b75505Sopenharmony_ci		prev = q;
164e5b75505Sopenharmony_ci		q = q->next;
165e5b75505Sopenharmony_ci		p2p_free_sd_query(prev);
166e5b75505Sopenharmony_ci	}
167e5b75505Sopenharmony_ci	p2p->num_p2p_sd_queries = 0;
168e5b75505Sopenharmony_ci}
169e5b75505Sopenharmony_ci
170e5b75505Sopenharmony_ci
171e5b75505Sopenharmony_cistatic struct wpabuf * p2p_build_sd_query(u16 update_indic,
172e5b75505Sopenharmony_ci					  struct wpabuf *tlvs)
173e5b75505Sopenharmony_ci{
174e5b75505Sopenharmony_ci	struct wpabuf *buf;
175e5b75505Sopenharmony_ci	u8 *len_pos;
176e5b75505Sopenharmony_ci
177e5b75505Sopenharmony_ci	buf = gas_anqp_build_initial_req(0, 100 + wpabuf_len(tlvs));
178e5b75505Sopenharmony_ci	if (buf == NULL)
179e5b75505Sopenharmony_ci		return NULL;
180e5b75505Sopenharmony_ci
181e5b75505Sopenharmony_ci	/* ANQP Query Request Frame */
182e5b75505Sopenharmony_ci	len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
183e5b75505Sopenharmony_ci	wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
184e5b75505Sopenharmony_ci	wpabuf_put_le16(buf, update_indic); /* Service Update Indicator */
185e5b75505Sopenharmony_ci	wpabuf_put_buf(buf, tlvs);
186e5b75505Sopenharmony_ci	gas_anqp_set_element_len(buf, len_pos);
187e5b75505Sopenharmony_ci
188e5b75505Sopenharmony_ci	gas_anqp_set_len(buf);
189e5b75505Sopenharmony_ci
190e5b75505Sopenharmony_ci	return buf;
191e5b75505Sopenharmony_ci}
192e5b75505Sopenharmony_ci
193e5b75505Sopenharmony_ci
194e5b75505Sopenharmony_cistatic void p2p_send_gas_comeback_req(struct p2p_data *p2p, const u8 *dst,
195e5b75505Sopenharmony_ci				      u8 dialog_token, int freq)
196e5b75505Sopenharmony_ci{
197e5b75505Sopenharmony_ci	struct wpabuf *req;
198e5b75505Sopenharmony_ci
199e5b75505Sopenharmony_ci	req = gas_build_comeback_req(dialog_token);
200e5b75505Sopenharmony_ci	if (req == NULL)
201e5b75505Sopenharmony_ci		return;
202e5b75505Sopenharmony_ci
203e5b75505Sopenharmony_ci	p2p->pending_action_state = P2P_NO_PENDING_ACTION;
204e5b75505Sopenharmony_ci	if (p2p_send_action(p2p, freq, dst, p2p->cfg->dev_addr, dst,
205e5b75505Sopenharmony_ci			    wpabuf_head(req), wpabuf_len(req), 200) < 0)
206e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Failed to send Action frame");
207e5b75505Sopenharmony_ci
208e5b75505Sopenharmony_ci	wpabuf_free(req);
209e5b75505Sopenharmony_ci}
210e5b75505Sopenharmony_ci
211e5b75505Sopenharmony_ci
212e5b75505Sopenharmony_cistatic struct wpabuf * p2p_build_sd_response(u8 dialog_token, u16 status_code,
213e5b75505Sopenharmony_ci					     u16 comeback_delay,
214e5b75505Sopenharmony_ci					     u16 update_indic,
215e5b75505Sopenharmony_ci					     const struct wpabuf *tlvs)
216e5b75505Sopenharmony_ci{
217e5b75505Sopenharmony_ci	struct wpabuf *buf;
218e5b75505Sopenharmony_ci	u8 *len_pos;
219e5b75505Sopenharmony_ci
220e5b75505Sopenharmony_ci	buf = gas_anqp_build_initial_resp(dialog_token, status_code,
221e5b75505Sopenharmony_ci					  comeback_delay,
222e5b75505Sopenharmony_ci					  100 + (tlvs ? wpabuf_len(tlvs) : 0));
223e5b75505Sopenharmony_ci	if (buf == NULL)
224e5b75505Sopenharmony_ci		return NULL;
225e5b75505Sopenharmony_ci
226e5b75505Sopenharmony_ci	if (tlvs) {
227e5b75505Sopenharmony_ci		/* ANQP Query Response Frame */
228e5b75505Sopenharmony_ci		len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
229e5b75505Sopenharmony_ci		wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
230e5b75505Sopenharmony_ci		 /* Service Update Indicator */
231e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, update_indic);
232e5b75505Sopenharmony_ci		wpabuf_put_buf(buf, tlvs);
233e5b75505Sopenharmony_ci		gas_anqp_set_element_len(buf, len_pos);
234e5b75505Sopenharmony_ci	}
235e5b75505Sopenharmony_ci
236e5b75505Sopenharmony_ci	gas_anqp_set_len(buf);
237e5b75505Sopenharmony_ci
238e5b75505Sopenharmony_ci	return buf;
239e5b75505Sopenharmony_ci}
240e5b75505Sopenharmony_ci
241e5b75505Sopenharmony_ci
242e5b75505Sopenharmony_cistatic struct wpabuf * p2p_build_gas_comeback_resp(u8 dialog_token,
243e5b75505Sopenharmony_ci						   u16 status_code,
244e5b75505Sopenharmony_ci						   u16 update_indic,
245e5b75505Sopenharmony_ci						   const u8 *data, size_t len,
246e5b75505Sopenharmony_ci						   u8 frag_id, u8 more,
247e5b75505Sopenharmony_ci						   u16 total_len)
248e5b75505Sopenharmony_ci{
249e5b75505Sopenharmony_ci	struct wpabuf *buf;
250e5b75505Sopenharmony_ci
251e5b75505Sopenharmony_ci	buf = gas_anqp_build_comeback_resp(dialog_token, status_code, frag_id,
252e5b75505Sopenharmony_ci					   more, 0, 100 + len);
253e5b75505Sopenharmony_ci	if (buf == NULL)
254e5b75505Sopenharmony_ci		return NULL;
255e5b75505Sopenharmony_ci
256e5b75505Sopenharmony_ci	if (frag_id == 0) {
257e5b75505Sopenharmony_ci		/* ANQP Query Response Frame */
258e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, ANQP_VENDOR_SPECIFIC); /* Info ID */
259e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, 3 + 1 + 2 + total_len);
260e5b75505Sopenharmony_ci		wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
261e5b75505Sopenharmony_ci		/* Service Update Indicator */
262e5b75505Sopenharmony_ci		wpabuf_put_le16(buf, update_indic);
263e5b75505Sopenharmony_ci	}
264e5b75505Sopenharmony_ci
265e5b75505Sopenharmony_ci	wpabuf_put_data(buf, data, len);
266e5b75505Sopenharmony_ci	gas_anqp_set_len(buf);
267e5b75505Sopenharmony_ci
268e5b75505Sopenharmony_ci	return buf;
269e5b75505Sopenharmony_ci}
270e5b75505Sopenharmony_ci
271e5b75505Sopenharmony_ci
272e5b75505Sopenharmony_ciint p2p_start_sd(struct p2p_data *p2p, struct p2p_device *dev)
273e5b75505Sopenharmony_ci{
274e5b75505Sopenharmony_ci	struct wpabuf *req;
275e5b75505Sopenharmony_ci	int ret = 0;
276e5b75505Sopenharmony_ci	struct p2p_sd_query *query;
277e5b75505Sopenharmony_ci	int freq;
278e5b75505Sopenharmony_ci	unsigned int wait_time;
279e5b75505Sopenharmony_ci
280e5b75505Sopenharmony_ci	freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
281e5b75505Sopenharmony_ci	if (freq <= 0) {
282e5b75505Sopenharmony_ci		p2p_dbg(p2p, "No Listen/Operating frequency known for the peer "
283e5b75505Sopenharmony_ci			MACSTR " to send SD Request",
284e5b75505Sopenharmony_ci			MAC2STR(dev->info.p2p_device_addr));
285e5b75505Sopenharmony_ci		return -1;
286e5b75505Sopenharmony_ci	}
287e5b75505Sopenharmony_ci
288e5b75505Sopenharmony_ci	query = p2p_pending_sd_req(p2p, dev);
289e5b75505Sopenharmony_ci	if (query == NULL)
290e5b75505Sopenharmony_ci		return -1;
291e5b75505Sopenharmony_ci	if (p2p->state == P2P_SEARCH &&
292e5b75505Sopenharmony_ci	    os_memcmp(p2p->sd_query_no_ack, dev->info.p2p_device_addr,
293e5b75505Sopenharmony_ci		      ETH_ALEN) == 0) {
294e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Do not start Service Discovery with " MACSTR
295e5b75505Sopenharmony_ci			" due to it being the first no-ACK peer in this search iteration",
296e5b75505Sopenharmony_ci			MAC2STR(dev->info.p2p_device_addr));
297e5b75505Sopenharmony_ci		return -2;
298e5b75505Sopenharmony_ci	}
299e5b75505Sopenharmony_ci
300e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Start Service Discovery with " MACSTR,
301e5b75505Sopenharmony_ci		MAC2STR(dev->info.p2p_device_addr));
302e5b75505Sopenharmony_ci
303e5b75505Sopenharmony_ci	req = p2p_build_sd_query(p2p->srv_update_indic, query->tlvs);
304e5b75505Sopenharmony_ci	if (req == NULL)
305e5b75505Sopenharmony_ci		return -1;
306e5b75505Sopenharmony_ci
307e5b75505Sopenharmony_ci	dev->sd_reqs++;
308e5b75505Sopenharmony_ci	p2p->sd_peer = dev;
309e5b75505Sopenharmony_ci	p2p->sd_query = query;
310e5b75505Sopenharmony_ci	p2p->pending_action_state = P2P_PENDING_SD;
311e5b75505Sopenharmony_ci
312e5b75505Sopenharmony_ci	wait_time = 5000;
313e5b75505Sopenharmony_ci	if (p2p->cfg->max_listen && wait_time > p2p->cfg->max_listen)
314e5b75505Sopenharmony_ci		wait_time = p2p->cfg->max_listen;
315e5b75505Sopenharmony_ci	if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
316e5b75505Sopenharmony_ci			    p2p->cfg->dev_addr, dev->info.p2p_device_addr,
317e5b75505Sopenharmony_ci			    wpabuf_head(req), wpabuf_len(req), wait_time) < 0) {
318e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Failed to send Action frame");
319e5b75505Sopenharmony_ci		ret = -1;
320e5b75505Sopenharmony_ci	}
321e5b75505Sopenharmony_ci
322e5b75505Sopenharmony_ci	wpabuf_free(req);
323e5b75505Sopenharmony_ci
324e5b75505Sopenharmony_ci	return ret;
325e5b75505Sopenharmony_ci}
326e5b75505Sopenharmony_ci
327e5b75505Sopenharmony_ci
328e5b75505Sopenharmony_civoid p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
329e5b75505Sopenharmony_ci			    const u8 *data, size_t len, int rx_freq)
330e5b75505Sopenharmony_ci{
331e5b75505Sopenharmony_ci	const u8 *pos = data;
332e5b75505Sopenharmony_ci	const u8 *end = data + len;
333e5b75505Sopenharmony_ci	const u8 *next;
334e5b75505Sopenharmony_ci	u8 dialog_token;
335e5b75505Sopenharmony_ci	u16 slen;
336e5b75505Sopenharmony_ci	int freq;
337e5b75505Sopenharmony_ci	u16 update_indic;
338e5b75505Sopenharmony_ci
339e5b75505Sopenharmony_ci
340e5b75505Sopenharmony_ci	if (p2p->cfg->sd_request == NULL)
341e5b75505Sopenharmony_ci		return;
342e5b75505Sopenharmony_ci
343e5b75505Sopenharmony_ci	if (rx_freq > 0)
344e5b75505Sopenharmony_ci		freq = rx_freq;
345e5b75505Sopenharmony_ci	else
346e5b75505Sopenharmony_ci		freq = p2p_channel_to_freq(p2p->cfg->reg_class,
347e5b75505Sopenharmony_ci					   p2p->cfg->channel);
348e5b75505Sopenharmony_ci	if (freq < 0)
349e5b75505Sopenharmony_ci		return;
350e5b75505Sopenharmony_ci
351e5b75505Sopenharmony_ci	if (len < 1 + 2)
352e5b75505Sopenharmony_ci		return;
353e5b75505Sopenharmony_ci
354e5b75505Sopenharmony_ci	dialog_token = *pos++;
355e5b75505Sopenharmony_ci	p2p_dbg(p2p, "GAS Initial Request from " MACSTR
356e5b75505Sopenharmony_ci		" (dialog token %u, freq %d)",
357e5b75505Sopenharmony_ci		MAC2STR(sa), dialog_token, rx_freq);
358e5b75505Sopenharmony_ci
359e5b75505Sopenharmony_ci	if (*pos != WLAN_EID_ADV_PROTO) {
360e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Unexpected IE in GAS Initial Request: %u", *pos);
361e5b75505Sopenharmony_ci		return;
362e5b75505Sopenharmony_ci	}
363e5b75505Sopenharmony_ci	pos++;
364e5b75505Sopenharmony_ci
365e5b75505Sopenharmony_ci	slen = *pos++;
366e5b75505Sopenharmony_ci	if (slen > end - pos || slen < 2) {
367e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Invalid IE in GAS Initial Request");
368e5b75505Sopenharmony_ci		return;
369e5b75505Sopenharmony_ci	}
370e5b75505Sopenharmony_ci	next = pos + slen;
371e5b75505Sopenharmony_ci	pos++; /* skip QueryRespLenLimit and PAME-BI */
372e5b75505Sopenharmony_ci
373e5b75505Sopenharmony_ci	if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
374e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Unsupported GAS advertisement protocol id %u",
375e5b75505Sopenharmony_ci			*pos);
376e5b75505Sopenharmony_ci		return;
377e5b75505Sopenharmony_ci	}
378e5b75505Sopenharmony_ci
379e5b75505Sopenharmony_ci	pos = next;
380e5b75505Sopenharmony_ci	/* Query Request */
381e5b75505Sopenharmony_ci	if (end - pos < 2)
382e5b75505Sopenharmony_ci		return;
383e5b75505Sopenharmony_ci	slen = WPA_GET_LE16(pos);
384e5b75505Sopenharmony_ci	pos += 2;
385e5b75505Sopenharmony_ci	if (slen > end - pos)
386e5b75505Sopenharmony_ci		return;
387e5b75505Sopenharmony_ci	end = pos + slen;
388e5b75505Sopenharmony_ci
389e5b75505Sopenharmony_ci	/* ANQP Query Request */
390e5b75505Sopenharmony_ci	if (end - pos < 4)
391e5b75505Sopenharmony_ci		return;
392e5b75505Sopenharmony_ci	if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
393e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
394e5b75505Sopenharmony_ci		return;
395e5b75505Sopenharmony_ci	}
396e5b75505Sopenharmony_ci	pos += 2;
397e5b75505Sopenharmony_ci
398e5b75505Sopenharmony_ci	slen = WPA_GET_LE16(pos);
399e5b75505Sopenharmony_ci	pos += 2;
400e5b75505Sopenharmony_ci	if (slen > end - pos || slen < 3 + 1) {
401e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Invalid ANQP Query Request length");
402e5b75505Sopenharmony_ci		return;
403e5b75505Sopenharmony_ci	}
404e5b75505Sopenharmony_ci
405e5b75505Sopenharmony_ci	if (WPA_GET_BE32(pos) != P2P_IE_VENDOR_TYPE) {
406e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Unsupported ANQP vendor OUI-type %08x",
407e5b75505Sopenharmony_ci			WPA_GET_BE32(pos));
408e5b75505Sopenharmony_ci		return;
409e5b75505Sopenharmony_ci	}
410e5b75505Sopenharmony_ci	pos += 4;
411e5b75505Sopenharmony_ci
412e5b75505Sopenharmony_ci	if (end - pos < 2)
413e5b75505Sopenharmony_ci		return;
414e5b75505Sopenharmony_ci	update_indic = WPA_GET_LE16(pos);
415e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Service Update Indicator: %u", update_indic);
416e5b75505Sopenharmony_ci	pos += 2;
417e5b75505Sopenharmony_ci
418e5b75505Sopenharmony_ci	p2p->cfg->sd_request(p2p->cfg->cb_ctx, freq, sa, dialog_token,
419e5b75505Sopenharmony_ci			     update_indic, pos, end - pos);
420e5b75505Sopenharmony_ci	/* the response will be indicated with a call to p2p_sd_response() */
421e5b75505Sopenharmony_ci}
422e5b75505Sopenharmony_ci
423e5b75505Sopenharmony_ci
424e5b75505Sopenharmony_civoid p2p_sd_response(struct p2p_data *p2p, int freq, const u8 *dst,
425e5b75505Sopenharmony_ci		     u8 dialog_token, const struct wpabuf *resp_tlvs)
426e5b75505Sopenharmony_ci{
427e5b75505Sopenharmony_ci	struct wpabuf *resp;
428e5b75505Sopenharmony_ci	size_t max_len;
429e5b75505Sopenharmony_ci	unsigned int wait_time = 200;
430e5b75505Sopenharmony_ci
431e5b75505Sopenharmony_ci	/*
432e5b75505Sopenharmony_ci	 * In the 60 GHz, we have a smaller maximum frame length for management
433e5b75505Sopenharmony_ci	 * frames.
434e5b75505Sopenharmony_ci	 */
435e5b75505Sopenharmony_ci	max_len = (freq > 56160) ? 928 : 1400;
436e5b75505Sopenharmony_ci
437e5b75505Sopenharmony_ci	/* TODO: fix the length limit to match with the maximum frame length */
438e5b75505Sopenharmony_ci	if (wpabuf_len(resp_tlvs) > max_len) {
439e5b75505Sopenharmony_ci		p2p_dbg(p2p, "SD response long enough to require fragmentation");
440e5b75505Sopenharmony_ci		if (p2p->sd_resp) {
441e5b75505Sopenharmony_ci			/*
442e5b75505Sopenharmony_ci			 * TODO: Could consider storing the fragmented response
443e5b75505Sopenharmony_ci			 * separately for each peer to avoid having to drop old
444e5b75505Sopenharmony_ci			 * one if there is more than one pending SD query.
445e5b75505Sopenharmony_ci			 * Though, that would eat more memory, so there are
446e5b75505Sopenharmony_ci			 * also benefits to just using a single buffer.
447e5b75505Sopenharmony_ci			 */
448e5b75505Sopenharmony_ci			p2p_dbg(p2p, "Drop previous SD response");
449e5b75505Sopenharmony_ci			wpabuf_free(p2p->sd_resp);
450e5b75505Sopenharmony_ci		}
451e5b75505Sopenharmony_ci		p2p->sd_resp = wpabuf_dup(resp_tlvs);
452e5b75505Sopenharmony_ci		if (p2p->sd_resp == NULL) {
453e5b75505Sopenharmony_ci			p2p_err(p2p, "Failed to allocate SD response fragmentation area");
454e5b75505Sopenharmony_ci			return;
455e5b75505Sopenharmony_ci		}
456e5b75505Sopenharmony_ci		os_memcpy(p2p->sd_resp_addr, dst, ETH_ALEN);
457e5b75505Sopenharmony_ci		p2p->sd_resp_dialog_token = dialog_token;
458e5b75505Sopenharmony_ci		p2p->sd_resp_pos = 0;
459e5b75505Sopenharmony_ci		p2p->sd_frag_id = 0;
460e5b75505Sopenharmony_ci		resp = p2p_build_sd_response(dialog_token, WLAN_STATUS_SUCCESS,
461e5b75505Sopenharmony_ci					     1, p2p->srv_update_indic, NULL);
462e5b75505Sopenharmony_ci	} else {
463e5b75505Sopenharmony_ci		p2p_dbg(p2p, "SD response fits in initial response");
464e5b75505Sopenharmony_ci		wait_time = 0; /* no more SD frames in the sequence */
465e5b75505Sopenharmony_ci		resp = p2p_build_sd_response(dialog_token,
466e5b75505Sopenharmony_ci					     WLAN_STATUS_SUCCESS, 0,
467e5b75505Sopenharmony_ci					     p2p->srv_update_indic, resp_tlvs);
468e5b75505Sopenharmony_ci	}
469e5b75505Sopenharmony_ci	if (resp == NULL)
470e5b75505Sopenharmony_ci		return;
471e5b75505Sopenharmony_ci
472e5b75505Sopenharmony_ci	p2p->pending_action_state = P2P_NO_PENDING_ACTION;
473e5b75505Sopenharmony_ci	if (p2p_send_action(p2p, freq, dst, p2p->cfg->dev_addr,
474e5b75505Sopenharmony_ci			    p2p->cfg->dev_addr,
475e5b75505Sopenharmony_ci			    wpabuf_head(resp), wpabuf_len(resp), wait_time) < 0)
476e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Failed to send Action frame");
477e5b75505Sopenharmony_ci
478e5b75505Sopenharmony_ci	wpabuf_free(resp);
479e5b75505Sopenharmony_ci}
480e5b75505Sopenharmony_ci
481e5b75505Sopenharmony_ci
482e5b75505Sopenharmony_civoid p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
483e5b75505Sopenharmony_ci			     const u8 *data, size_t len, int rx_freq)
484e5b75505Sopenharmony_ci{
485e5b75505Sopenharmony_ci	const u8 *pos = data;
486e5b75505Sopenharmony_ci	const u8 *end = data + len;
487e5b75505Sopenharmony_ci	const u8 *next;
488e5b75505Sopenharmony_ci	u8 dialog_token;
489e5b75505Sopenharmony_ci	u16 status_code;
490e5b75505Sopenharmony_ci	u16 comeback_delay;
491e5b75505Sopenharmony_ci	u16 slen;
492e5b75505Sopenharmony_ci	u16 update_indic;
493e5b75505Sopenharmony_ci
494e5b75505Sopenharmony_ci	if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL ||
495e5b75505Sopenharmony_ci	    os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) {
496e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Ignore unexpected GAS Initial Response from "
497e5b75505Sopenharmony_ci			MACSTR, MAC2STR(sa));
498e5b75505Sopenharmony_ci		return;
499e5b75505Sopenharmony_ci	}
500e5b75505Sopenharmony_ci	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
501e5b75505Sopenharmony_ci	p2p_clear_timeout(p2p);
502e5b75505Sopenharmony_ci
503e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Received GAS Initial Response from " MACSTR " (len=%d)",
504e5b75505Sopenharmony_ci		MAC2STR(sa), (int) len);
505e5b75505Sopenharmony_ci
506e5b75505Sopenharmony_ci	if (len < 5 + 2) {
507e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Too short GAS Initial Response frame");
508e5b75505Sopenharmony_ci		return;
509e5b75505Sopenharmony_ci	}
510e5b75505Sopenharmony_ci
511e5b75505Sopenharmony_ci	dialog_token = *pos++;
512e5b75505Sopenharmony_ci	/* TODO: check dialog_token match */
513e5b75505Sopenharmony_ci	status_code = WPA_GET_LE16(pos);
514e5b75505Sopenharmony_ci	pos += 2;
515e5b75505Sopenharmony_ci	comeback_delay = WPA_GET_LE16(pos);
516e5b75505Sopenharmony_ci	pos += 2;
517e5b75505Sopenharmony_ci	p2p_dbg(p2p, "dialog_token=%u status_code=%u comeback_delay=%u",
518e5b75505Sopenharmony_ci		dialog_token, status_code, comeback_delay);
519e5b75505Sopenharmony_ci	if (status_code) {
520e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Service Discovery failed: status code %u",
521e5b75505Sopenharmony_ci			status_code);
522e5b75505Sopenharmony_ci		return;
523e5b75505Sopenharmony_ci	}
524e5b75505Sopenharmony_ci
525e5b75505Sopenharmony_ci	if (*pos != WLAN_EID_ADV_PROTO) {
526e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Unexpected IE in GAS Initial Response: %u", *pos);
527e5b75505Sopenharmony_ci		return;
528e5b75505Sopenharmony_ci	}
529e5b75505Sopenharmony_ci	pos++;
530e5b75505Sopenharmony_ci
531e5b75505Sopenharmony_ci	slen = *pos++;
532e5b75505Sopenharmony_ci	if (slen > end - pos || slen < 2) {
533e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Invalid IE in GAS Initial Response");
534e5b75505Sopenharmony_ci		return;
535e5b75505Sopenharmony_ci	}
536e5b75505Sopenharmony_ci	next = pos + slen;
537e5b75505Sopenharmony_ci	pos++; /* skip QueryRespLenLimit and PAME-BI */
538e5b75505Sopenharmony_ci
539e5b75505Sopenharmony_ci	if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
540e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Unsupported GAS advertisement protocol id %u",
541e5b75505Sopenharmony_ci			*pos);
542e5b75505Sopenharmony_ci		return;
543e5b75505Sopenharmony_ci	}
544e5b75505Sopenharmony_ci
545e5b75505Sopenharmony_ci	pos = next;
546e5b75505Sopenharmony_ci	/* Query Response */
547e5b75505Sopenharmony_ci	if (end - pos < 2) {
548e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Too short Query Response");
549e5b75505Sopenharmony_ci		return;
550e5b75505Sopenharmony_ci	}
551e5b75505Sopenharmony_ci	slen = WPA_GET_LE16(pos);
552e5b75505Sopenharmony_ci	pos += 2;
553e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Query Response Length: %d", slen);
554e5b75505Sopenharmony_ci	if (slen > end - pos) {
555e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Not enough Query Response data");
556e5b75505Sopenharmony_ci		return;
557e5b75505Sopenharmony_ci	}
558e5b75505Sopenharmony_ci	end = pos + slen;
559e5b75505Sopenharmony_ci
560e5b75505Sopenharmony_ci	if (comeback_delay) {
561e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Fragmented response - request fragments");
562e5b75505Sopenharmony_ci		if (p2p->sd_rx_resp) {
563e5b75505Sopenharmony_ci			p2p_dbg(p2p, "Drop old SD reassembly buffer");
564e5b75505Sopenharmony_ci			wpabuf_free(p2p->sd_rx_resp);
565e5b75505Sopenharmony_ci			p2p->sd_rx_resp = NULL;
566e5b75505Sopenharmony_ci		}
567e5b75505Sopenharmony_ci		p2p_send_gas_comeback_req(p2p, sa, dialog_token, rx_freq);
568e5b75505Sopenharmony_ci		return;
569e5b75505Sopenharmony_ci	}
570e5b75505Sopenharmony_ci
571e5b75505Sopenharmony_ci	/* ANQP Query Response */
572e5b75505Sopenharmony_ci	if (end - pos < 4)
573e5b75505Sopenharmony_ci		return;
574e5b75505Sopenharmony_ci	if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
575e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
576e5b75505Sopenharmony_ci		return;
577e5b75505Sopenharmony_ci	}
578e5b75505Sopenharmony_ci	pos += 2;
579e5b75505Sopenharmony_ci
580e5b75505Sopenharmony_ci	slen = WPA_GET_LE16(pos);
581e5b75505Sopenharmony_ci	pos += 2;
582e5b75505Sopenharmony_ci	if (slen > end - pos || slen < 3 + 1) {
583e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Invalid ANQP Query Response length");
584e5b75505Sopenharmony_ci		return;
585e5b75505Sopenharmony_ci	}
586e5b75505Sopenharmony_ci
587e5b75505Sopenharmony_ci	if (WPA_GET_BE32(pos) != P2P_IE_VENDOR_TYPE) {
588e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Unsupported ANQP vendor OUI-type %08x",
589e5b75505Sopenharmony_ci			WPA_GET_BE32(pos));
590e5b75505Sopenharmony_ci		return;
591e5b75505Sopenharmony_ci	}
592e5b75505Sopenharmony_ci	pos += 4;
593e5b75505Sopenharmony_ci
594e5b75505Sopenharmony_ci	if (end - pos < 2)
595e5b75505Sopenharmony_ci		return;
596e5b75505Sopenharmony_ci	update_indic = WPA_GET_LE16(pos);
597e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Service Update Indicator: %u", update_indic);
598e5b75505Sopenharmony_ci	pos += 2;
599e5b75505Sopenharmony_ci
600e5b75505Sopenharmony_ci	p2p->sd_peer = NULL;
601e5b75505Sopenharmony_ci
602e5b75505Sopenharmony_ci	if (p2p->sd_query) {
603e5b75505Sopenharmony_ci		if (!p2p->sd_query->for_all_peers) {
604e5b75505Sopenharmony_ci			struct p2p_sd_query *q;
605e5b75505Sopenharmony_ci			p2p_dbg(p2p, "Remove completed SD query %p",
606e5b75505Sopenharmony_ci				p2p->sd_query);
607e5b75505Sopenharmony_ci			q = p2p->sd_query;
608e5b75505Sopenharmony_ci			p2p_unlink_sd_query(p2p, p2p->sd_query);
609e5b75505Sopenharmony_ci			p2p_free_sd_query(q);
610e5b75505Sopenharmony_ci		}
611e5b75505Sopenharmony_ci		p2p->sd_query = NULL;
612e5b75505Sopenharmony_ci	}
613e5b75505Sopenharmony_ci
614e5b75505Sopenharmony_ci	if (p2p->cfg->sd_response)
615e5b75505Sopenharmony_ci		p2p->cfg->sd_response(p2p->cfg->cb_ctx, sa, update_indic,
616e5b75505Sopenharmony_ci				      pos, end - pos);
617e5b75505Sopenharmony_ci	p2p_continue_find(p2p);
618e5b75505Sopenharmony_ci}
619e5b75505Sopenharmony_ci
620e5b75505Sopenharmony_ci
621e5b75505Sopenharmony_civoid p2p_rx_gas_comeback_req(struct p2p_data *p2p, const u8 *sa,
622e5b75505Sopenharmony_ci			     const u8 *data, size_t len, int rx_freq)
623e5b75505Sopenharmony_ci{
624e5b75505Sopenharmony_ci	struct wpabuf *resp;
625e5b75505Sopenharmony_ci	u8 dialog_token;
626e5b75505Sopenharmony_ci	size_t frag_len, max_len;
627e5b75505Sopenharmony_ci	int more = 0;
628e5b75505Sopenharmony_ci	unsigned int wait_time = 200;
629e5b75505Sopenharmony_ci
630e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "P2P: RX GAS Comeback Request", data, len);
631e5b75505Sopenharmony_ci	if (len < 1)
632e5b75505Sopenharmony_ci		return;
633e5b75505Sopenharmony_ci	dialog_token = *data;
634e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Dialog Token: %u", dialog_token);
635e5b75505Sopenharmony_ci	if (dialog_token != p2p->sd_resp_dialog_token) {
636e5b75505Sopenharmony_ci		p2p_dbg(p2p, "No pending SD response fragment for dialog token %u",
637e5b75505Sopenharmony_ci			dialog_token);
638e5b75505Sopenharmony_ci		return;
639e5b75505Sopenharmony_ci	}
640e5b75505Sopenharmony_ci
641e5b75505Sopenharmony_ci	if (p2p->sd_resp == NULL) {
642e5b75505Sopenharmony_ci		p2p_dbg(p2p, "No pending SD response fragment available");
643e5b75505Sopenharmony_ci		return;
644e5b75505Sopenharmony_ci	}
645e5b75505Sopenharmony_ci	if (os_memcmp(sa, p2p->sd_resp_addr, ETH_ALEN) != 0) {
646e5b75505Sopenharmony_ci		p2p_dbg(p2p, "No pending SD response fragment for " MACSTR,
647e5b75505Sopenharmony_ci			MAC2STR(sa));
648e5b75505Sopenharmony_ci		return;
649e5b75505Sopenharmony_ci	}
650e5b75505Sopenharmony_ci
651e5b75505Sopenharmony_ci	/*
652e5b75505Sopenharmony_ci	 * In the 60 GHz, we have a smaller maximum frame length for management
653e5b75505Sopenharmony_ci	 * frames.
654e5b75505Sopenharmony_ci	 */
655e5b75505Sopenharmony_ci	max_len = (rx_freq > 56160) ? 928 : 1400;
656e5b75505Sopenharmony_ci	frag_len = wpabuf_len(p2p->sd_resp) - p2p->sd_resp_pos;
657e5b75505Sopenharmony_ci	if (frag_len > max_len) {
658e5b75505Sopenharmony_ci		frag_len = max_len;
659e5b75505Sopenharmony_ci		more = 1;
660e5b75505Sopenharmony_ci	}
661e5b75505Sopenharmony_ci	resp = p2p_build_gas_comeback_resp(dialog_token, WLAN_STATUS_SUCCESS,
662e5b75505Sopenharmony_ci					   p2p->srv_update_indic,
663e5b75505Sopenharmony_ci					   wpabuf_head_u8(p2p->sd_resp) +
664e5b75505Sopenharmony_ci					   p2p->sd_resp_pos, frag_len,
665e5b75505Sopenharmony_ci					   p2p->sd_frag_id, more,
666e5b75505Sopenharmony_ci					   wpabuf_len(p2p->sd_resp));
667e5b75505Sopenharmony_ci	if (resp == NULL)
668e5b75505Sopenharmony_ci		return;
669e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Send GAS Comeback Response (frag_id %d more=%d frag_len=%d)",
670e5b75505Sopenharmony_ci		p2p->sd_frag_id, more, (int) frag_len);
671e5b75505Sopenharmony_ci	p2p->sd_frag_id++;
672e5b75505Sopenharmony_ci	p2p->sd_resp_pos += frag_len;
673e5b75505Sopenharmony_ci
674e5b75505Sopenharmony_ci	if (more) {
675e5b75505Sopenharmony_ci		p2p_dbg(p2p, "%d more bytes remain to be sent",
676e5b75505Sopenharmony_ci			(int) (wpabuf_len(p2p->sd_resp) - p2p->sd_resp_pos));
677e5b75505Sopenharmony_ci	} else {
678e5b75505Sopenharmony_ci		p2p_dbg(p2p, "All fragments of SD response sent");
679e5b75505Sopenharmony_ci		wpabuf_free(p2p->sd_resp);
680e5b75505Sopenharmony_ci		p2p->sd_resp = NULL;
681e5b75505Sopenharmony_ci		wait_time = 0; /* no more SD frames in the sequence */
682e5b75505Sopenharmony_ci	}
683e5b75505Sopenharmony_ci
684e5b75505Sopenharmony_ci	p2p->pending_action_state = P2P_NO_PENDING_ACTION;
685e5b75505Sopenharmony_ci	if (p2p_send_action(p2p, rx_freq, sa, p2p->cfg->dev_addr,
686e5b75505Sopenharmony_ci			    p2p->cfg->dev_addr,
687e5b75505Sopenharmony_ci			    wpabuf_head(resp), wpabuf_len(resp), wait_time) < 0)
688e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Failed to send Action frame");
689e5b75505Sopenharmony_ci
690e5b75505Sopenharmony_ci	wpabuf_free(resp);
691e5b75505Sopenharmony_ci}
692e5b75505Sopenharmony_ci
693e5b75505Sopenharmony_ci
694e5b75505Sopenharmony_civoid p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
695e5b75505Sopenharmony_ci			      const u8 *data, size_t len, int rx_freq)
696e5b75505Sopenharmony_ci{
697e5b75505Sopenharmony_ci	const u8 *pos = data;
698e5b75505Sopenharmony_ci	const u8 *end = data + len;
699e5b75505Sopenharmony_ci	const u8 *next;
700e5b75505Sopenharmony_ci	u8 dialog_token;
701e5b75505Sopenharmony_ci	u16 status_code;
702e5b75505Sopenharmony_ci	u8 frag_id;
703e5b75505Sopenharmony_ci	u8 more_frags;
704e5b75505Sopenharmony_ci	u16 comeback_delay;
705e5b75505Sopenharmony_ci	u16 slen;
706e5b75505Sopenharmony_ci
707e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "P2P: RX GAS Comeback Response", data, len);
708e5b75505Sopenharmony_ci
709e5b75505Sopenharmony_ci	if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL ||
710e5b75505Sopenharmony_ci	    os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) {
711e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Ignore unexpected GAS Comeback Response from "
712e5b75505Sopenharmony_ci			MACSTR, MAC2STR(sa));
713e5b75505Sopenharmony_ci		return;
714e5b75505Sopenharmony_ci	}
715e5b75505Sopenharmony_ci	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
716e5b75505Sopenharmony_ci	p2p_clear_timeout(p2p);
717e5b75505Sopenharmony_ci
718e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Received GAS Comeback Response from " MACSTR " (len=%d)",
719e5b75505Sopenharmony_ci		MAC2STR(sa), (int) len);
720e5b75505Sopenharmony_ci
721e5b75505Sopenharmony_ci	if (len < 6 + 2) {
722e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Too short GAS Comeback Response frame");
723e5b75505Sopenharmony_ci		return;
724e5b75505Sopenharmony_ci	}
725e5b75505Sopenharmony_ci
726e5b75505Sopenharmony_ci	dialog_token = *pos++;
727e5b75505Sopenharmony_ci	/* TODO: check dialog_token match */
728e5b75505Sopenharmony_ci	status_code = WPA_GET_LE16(pos);
729e5b75505Sopenharmony_ci	pos += 2;
730e5b75505Sopenharmony_ci	frag_id = *pos & 0x7f;
731e5b75505Sopenharmony_ci	more_frags = (*pos & 0x80) >> 7;
732e5b75505Sopenharmony_ci	pos++;
733e5b75505Sopenharmony_ci	comeback_delay = WPA_GET_LE16(pos);
734e5b75505Sopenharmony_ci	pos += 2;
735e5b75505Sopenharmony_ci	p2p_dbg(p2p, "dialog_token=%u status_code=%u frag_id=%d more_frags=%d "
736e5b75505Sopenharmony_ci		"comeback_delay=%u",
737e5b75505Sopenharmony_ci		dialog_token, status_code, frag_id, more_frags,
738e5b75505Sopenharmony_ci		comeback_delay);
739e5b75505Sopenharmony_ci	/* TODO: check frag_id match */
740e5b75505Sopenharmony_ci	if (status_code) {
741e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Service Discovery failed: status code %u",
742e5b75505Sopenharmony_ci			status_code);
743e5b75505Sopenharmony_ci		return;
744e5b75505Sopenharmony_ci	}
745e5b75505Sopenharmony_ci
746e5b75505Sopenharmony_ci	if (*pos != WLAN_EID_ADV_PROTO) {
747e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Unexpected IE in GAS Comeback Response: %u",
748e5b75505Sopenharmony_ci			*pos);
749e5b75505Sopenharmony_ci		return;
750e5b75505Sopenharmony_ci	}
751e5b75505Sopenharmony_ci	pos++;
752e5b75505Sopenharmony_ci
753e5b75505Sopenharmony_ci	slen = *pos++;
754e5b75505Sopenharmony_ci	if (slen > end - pos || slen < 2) {
755e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Invalid IE in GAS Comeback Response");
756e5b75505Sopenharmony_ci		return;
757e5b75505Sopenharmony_ci	}
758e5b75505Sopenharmony_ci	next = pos + slen;
759e5b75505Sopenharmony_ci	pos++; /* skip QueryRespLenLimit and PAME-BI */
760e5b75505Sopenharmony_ci
761e5b75505Sopenharmony_ci	if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
762e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Unsupported GAS advertisement protocol id %u",
763e5b75505Sopenharmony_ci			*pos);
764e5b75505Sopenharmony_ci		return;
765e5b75505Sopenharmony_ci	}
766e5b75505Sopenharmony_ci
767e5b75505Sopenharmony_ci	pos = next;
768e5b75505Sopenharmony_ci	/* Query Response */
769e5b75505Sopenharmony_ci	if (end - pos < 2) {
770e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Too short Query Response");
771e5b75505Sopenharmony_ci		return;
772e5b75505Sopenharmony_ci	}
773e5b75505Sopenharmony_ci	slen = WPA_GET_LE16(pos);
774e5b75505Sopenharmony_ci	pos += 2;
775e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Query Response Length: %d", slen);
776e5b75505Sopenharmony_ci	if (slen > end - pos) {
777e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Not enough Query Response data");
778e5b75505Sopenharmony_ci		return;
779e5b75505Sopenharmony_ci	}
780e5b75505Sopenharmony_ci	if (slen == 0) {
781e5b75505Sopenharmony_ci		p2p_dbg(p2p, "No Query Response data");
782e5b75505Sopenharmony_ci		return;
783e5b75505Sopenharmony_ci	}
784e5b75505Sopenharmony_ci	end = pos + slen;
785e5b75505Sopenharmony_ci
786e5b75505Sopenharmony_ci	if (p2p->sd_rx_resp) {
787e5b75505Sopenharmony_ci		 /*
788e5b75505Sopenharmony_ci		  * ANQP header is only included in the first fragment; rest of
789e5b75505Sopenharmony_ci		  * the fragments start with continue TLVs.
790e5b75505Sopenharmony_ci		  */
791e5b75505Sopenharmony_ci		goto skip_nqp_header;
792e5b75505Sopenharmony_ci	}
793e5b75505Sopenharmony_ci
794e5b75505Sopenharmony_ci	/* ANQP Query Response */
795e5b75505Sopenharmony_ci	if (end - pos < 4)
796e5b75505Sopenharmony_ci		return;
797e5b75505Sopenharmony_ci	if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
798e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
799e5b75505Sopenharmony_ci		return;
800e5b75505Sopenharmony_ci	}
801e5b75505Sopenharmony_ci	pos += 2;
802e5b75505Sopenharmony_ci
803e5b75505Sopenharmony_ci	slen = WPA_GET_LE16(pos);
804e5b75505Sopenharmony_ci	pos += 2;
805e5b75505Sopenharmony_ci	p2p_dbg(p2p, "ANQP Query Response length: %u", slen);
806e5b75505Sopenharmony_ci	if (slen < 3 + 1) {
807e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Invalid ANQP Query Response length");
808e5b75505Sopenharmony_ci		return;
809e5b75505Sopenharmony_ci	}
810e5b75505Sopenharmony_ci	if (end - pos < 4)
811e5b75505Sopenharmony_ci		return;
812e5b75505Sopenharmony_ci
813e5b75505Sopenharmony_ci	if (WPA_GET_BE32(pos) != P2P_IE_VENDOR_TYPE) {
814e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Unsupported ANQP vendor OUI-type %08x",
815e5b75505Sopenharmony_ci			WPA_GET_BE32(pos));
816e5b75505Sopenharmony_ci		return;
817e5b75505Sopenharmony_ci	}
818e5b75505Sopenharmony_ci	pos += 4;
819e5b75505Sopenharmony_ci
820e5b75505Sopenharmony_ci	if (end - pos < 2)
821e5b75505Sopenharmony_ci		return;
822e5b75505Sopenharmony_ci	p2p->sd_rx_update_indic = WPA_GET_LE16(pos);
823e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Service Update Indicator: %u", p2p->sd_rx_update_indic);
824e5b75505Sopenharmony_ci	pos += 2;
825e5b75505Sopenharmony_ci
826e5b75505Sopenharmony_ciskip_nqp_header:
827e5b75505Sopenharmony_ci	if (wpabuf_resize(&p2p->sd_rx_resp, end - pos) < 0)
828e5b75505Sopenharmony_ci		return;
829e5b75505Sopenharmony_ci	wpabuf_put_data(p2p->sd_rx_resp, pos, end - pos);
830e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Current SD reassembly buffer length: %u",
831e5b75505Sopenharmony_ci		(unsigned int) wpabuf_len(p2p->sd_rx_resp));
832e5b75505Sopenharmony_ci
833e5b75505Sopenharmony_ci	if (more_frags) {
834e5b75505Sopenharmony_ci		p2p_dbg(p2p, "More fragments remains");
835e5b75505Sopenharmony_ci		/* TODO: what would be a good size limit? */
836e5b75505Sopenharmony_ci		if (wpabuf_len(p2p->sd_rx_resp) > 64000) {
837e5b75505Sopenharmony_ci			wpabuf_free(p2p->sd_rx_resp);
838e5b75505Sopenharmony_ci			p2p->sd_rx_resp = NULL;
839e5b75505Sopenharmony_ci			p2p_dbg(p2p, "Too long SD response - drop it");
840e5b75505Sopenharmony_ci			return;
841e5b75505Sopenharmony_ci		}
842e5b75505Sopenharmony_ci		p2p_send_gas_comeback_req(p2p, sa, dialog_token, rx_freq);
843e5b75505Sopenharmony_ci		return;
844e5b75505Sopenharmony_ci	}
845e5b75505Sopenharmony_ci
846e5b75505Sopenharmony_ci	p2p->sd_peer = NULL;
847e5b75505Sopenharmony_ci
848e5b75505Sopenharmony_ci	if (p2p->sd_query) {
849e5b75505Sopenharmony_ci		if (!p2p->sd_query->for_all_peers) {
850e5b75505Sopenharmony_ci			struct p2p_sd_query *q;
851e5b75505Sopenharmony_ci			p2p_dbg(p2p, "Remove completed SD query %p",
852e5b75505Sopenharmony_ci				p2p->sd_query);
853e5b75505Sopenharmony_ci			q = p2p->sd_query;
854e5b75505Sopenharmony_ci			p2p_unlink_sd_query(p2p, p2p->sd_query);
855e5b75505Sopenharmony_ci			p2p_free_sd_query(q);
856e5b75505Sopenharmony_ci		}
857e5b75505Sopenharmony_ci		p2p->sd_query = NULL;
858e5b75505Sopenharmony_ci	}
859e5b75505Sopenharmony_ci
860e5b75505Sopenharmony_ci	if (p2p->cfg->sd_response)
861e5b75505Sopenharmony_ci		p2p->cfg->sd_response(p2p->cfg->cb_ctx, sa,
862e5b75505Sopenharmony_ci				      p2p->sd_rx_update_indic,
863e5b75505Sopenharmony_ci				      wpabuf_head(p2p->sd_rx_resp),
864e5b75505Sopenharmony_ci				      wpabuf_len(p2p->sd_rx_resp));
865e5b75505Sopenharmony_ci	wpabuf_free(p2p->sd_rx_resp);
866e5b75505Sopenharmony_ci	p2p->sd_rx_resp = NULL;
867e5b75505Sopenharmony_ci
868e5b75505Sopenharmony_ci	p2p_continue_find(p2p);
869e5b75505Sopenharmony_ci}
870e5b75505Sopenharmony_ci
871e5b75505Sopenharmony_ci
872e5b75505Sopenharmony_civoid * p2p_sd_request(struct p2p_data *p2p, const u8 *dst,
873e5b75505Sopenharmony_ci		      const struct wpabuf *tlvs)
874e5b75505Sopenharmony_ci{
875e5b75505Sopenharmony_ci	struct p2p_sd_query *q;
876e5b75505Sopenharmony_ci
877e5b75505Sopenharmony_ci	q = os_zalloc(sizeof(*q));
878e5b75505Sopenharmony_ci	if (q == NULL)
879e5b75505Sopenharmony_ci		return NULL;
880e5b75505Sopenharmony_ci
881e5b75505Sopenharmony_ci	if (dst)
882e5b75505Sopenharmony_ci		os_memcpy(q->peer, dst, ETH_ALEN);
883e5b75505Sopenharmony_ci	else
884e5b75505Sopenharmony_ci		q->for_all_peers = 1;
885e5b75505Sopenharmony_ci
886e5b75505Sopenharmony_ci	q->tlvs = wpabuf_dup(tlvs);
887e5b75505Sopenharmony_ci	if (q->tlvs == NULL) {
888e5b75505Sopenharmony_ci		p2p_free_sd_query(q);
889e5b75505Sopenharmony_ci		return NULL;
890e5b75505Sopenharmony_ci	}
891e5b75505Sopenharmony_ci
892e5b75505Sopenharmony_ci	q->next = p2p->sd_queries;
893e5b75505Sopenharmony_ci	p2p->sd_queries = q;
894e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Added SD Query %p", q);
895e5b75505Sopenharmony_ci
896e5b75505Sopenharmony_ci	if (dst == NULL) {
897e5b75505Sopenharmony_ci		struct p2p_device *dev;
898e5b75505Sopenharmony_ci
899e5b75505Sopenharmony_ci		p2p->num_p2p_sd_queries++;
900e5b75505Sopenharmony_ci
901e5b75505Sopenharmony_ci		/* Update all the devices for the newly added broadcast query */
902e5b75505Sopenharmony_ci		dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
903e5b75505Sopenharmony_ci			if (dev->sd_pending_bcast_queries <= 0)
904e5b75505Sopenharmony_ci				dev->sd_pending_bcast_queries = 1;
905e5b75505Sopenharmony_ci			else
906e5b75505Sopenharmony_ci				dev->sd_pending_bcast_queries++;
907e5b75505Sopenharmony_ci		}
908e5b75505Sopenharmony_ci	}
909e5b75505Sopenharmony_ci
910e5b75505Sopenharmony_ci	return q;
911e5b75505Sopenharmony_ci}
912e5b75505Sopenharmony_ci
913e5b75505Sopenharmony_ci
914e5b75505Sopenharmony_ci#ifdef CONFIG_WIFI_DISPLAY
915e5b75505Sopenharmony_civoid * p2p_sd_request_wfd(struct p2p_data *p2p, const u8 *dst,
916e5b75505Sopenharmony_ci			  const struct wpabuf *tlvs)
917e5b75505Sopenharmony_ci{
918e5b75505Sopenharmony_ci	struct p2p_sd_query *q;
919e5b75505Sopenharmony_ci	q = p2p_sd_request(p2p, dst, tlvs);
920e5b75505Sopenharmony_ci	if (q)
921e5b75505Sopenharmony_ci		q->wsd = 1;
922e5b75505Sopenharmony_ci	return q;
923e5b75505Sopenharmony_ci}
924e5b75505Sopenharmony_ci#endif /* CONFIG_WIFI_DISPLAY */
925e5b75505Sopenharmony_ci
926e5b75505Sopenharmony_ci
927e5b75505Sopenharmony_civoid p2p_sd_service_update(struct p2p_data *p2p)
928e5b75505Sopenharmony_ci{
929e5b75505Sopenharmony_ci	p2p->srv_update_indic++;
930e5b75505Sopenharmony_ci}
931e5b75505Sopenharmony_ci
932e5b75505Sopenharmony_ci
933e5b75505Sopenharmony_ciint p2p_sd_cancel_request(struct p2p_data *p2p, void *req)
934e5b75505Sopenharmony_ci{
935e5b75505Sopenharmony_ci	if (p2p_unlink_sd_query(p2p, req)) {
936e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Cancel pending SD query %p", req);
937e5b75505Sopenharmony_ci		p2p_free_sd_query(req);
938e5b75505Sopenharmony_ci		return 0;
939e5b75505Sopenharmony_ci	}
940e5b75505Sopenharmony_ci	return -1;
941e5b75505Sopenharmony_ci}
942