xref: /freebsd/contrib/wpa/src/p2p/p2p_sd.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
1f05cddf9SRui Paulo /*
2f05cddf9SRui Paulo  * Wi-Fi Direct - P2P service discovery
3f05cddf9SRui Paulo  * Copyright (c) 2009, Atheros Communications
4f05cddf9SRui Paulo  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo  * See README for more details.
7f05cddf9SRui Paulo  */
8f05cddf9SRui Paulo 
9f05cddf9SRui Paulo #include "includes.h"
10f05cddf9SRui Paulo 
11f05cddf9SRui Paulo #include "common.h"
12f05cddf9SRui Paulo #include "common/ieee802_11_defs.h"
13f05cddf9SRui Paulo #include "common/gas.h"
14f05cddf9SRui Paulo #include "p2p_i.h"
15f05cddf9SRui Paulo #include "p2p.h"
16f05cddf9SRui Paulo 
17f05cddf9SRui Paulo 
18f05cddf9SRui Paulo #ifdef CONFIG_WIFI_DISPLAY
wfd_wsd_supported(struct wpabuf * wfd)19f05cddf9SRui Paulo static int wfd_wsd_supported(struct wpabuf *wfd)
20f05cddf9SRui Paulo {
21f05cddf9SRui Paulo 	const u8 *pos, *end;
22f05cddf9SRui Paulo 	u8 subelem;
23f05cddf9SRui Paulo 	u16 len;
24f05cddf9SRui Paulo 
25f05cddf9SRui Paulo 	if (wfd == NULL)
26f05cddf9SRui Paulo 		return 0;
27f05cddf9SRui Paulo 
28f05cddf9SRui Paulo 	pos = wpabuf_head(wfd);
29f05cddf9SRui Paulo 	end = pos + wpabuf_len(wfd);
30f05cddf9SRui Paulo 
31780fb4a2SCy Schubert 	while (end - pos >= 3) {
32f05cddf9SRui Paulo 		subelem = *pos++;
33f05cddf9SRui Paulo 		len = WPA_GET_BE16(pos);
34f05cddf9SRui Paulo 		pos += 2;
35780fb4a2SCy Schubert 		if (len > end - pos)
36f05cddf9SRui Paulo 			break;
37f05cddf9SRui Paulo 
38f05cddf9SRui Paulo 		if (subelem == WFD_SUBELEM_DEVICE_INFO && len >= 6) {
39f05cddf9SRui Paulo 			u16 info = WPA_GET_BE16(pos);
40f05cddf9SRui Paulo 			return !!(info & 0x0040);
41f05cddf9SRui Paulo 		}
42f05cddf9SRui Paulo 
43f05cddf9SRui Paulo 		pos += len;
44f05cddf9SRui Paulo 	}
45f05cddf9SRui Paulo 
46f05cddf9SRui Paulo 	return 0;
47f05cddf9SRui Paulo }
48f05cddf9SRui Paulo #endif /* CONFIG_WIFI_DISPLAY */
49f05cddf9SRui Paulo 
p2p_pending_sd_req(struct p2p_data * p2p,struct p2p_device * dev)50f05cddf9SRui Paulo struct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p,
51f05cddf9SRui Paulo 					 struct p2p_device *dev)
52f05cddf9SRui Paulo {
53f05cddf9SRui Paulo 	struct p2p_sd_query *q;
54f05cddf9SRui Paulo 	int wsd = 0;
555b9c547cSRui Paulo 	int count = 0;
56f05cddf9SRui Paulo 
57f05cddf9SRui Paulo 	if (!(dev->info.dev_capab & P2P_DEV_CAPAB_SERVICE_DISCOVERY))
58f05cddf9SRui Paulo 		return NULL; /* peer does not support SD */
59f05cddf9SRui Paulo #ifdef CONFIG_WIFI_DISPLAY
60f05cddf9SRui Paulo 	if (wfd_wsd_supported(dev->info.wfd_subelems))
61f05cddf9SRui Paulo 		wsd = 1;
62f05cddf9SRui Paulo #endif /* CONFIG_WIFI_DISPLAY */
63f05cddf9SRui Paulo 
64f05cddf9SRui Paulo 	for (q = p2p->sd_queries; q; q = q->next) {
65f05cddf9SRui Paulo 		/* Use WSD only if the peer indicates support or it */
66f05cddf9SRui Paulo 		if (q->wsd && !wsd)
67f05cddf9SRui Paulo 			continue;
685b9c547cSRui Paulo 		/* if the query is a broadcast query */
695b9c547cSRui Paulo 		if (q->for_all_peers) {
705b9c547cSRui Paulo 			/*
715b9c547cSRui Paulo 			 * check if there are any broadcast queries pending for
725b9c547cSRui Paulo 			 * this device
735b9c547cSRui Paulo 			 */
745b9c547cSRui Paulo 			if (dev->sd_pending_bcast_queries <= 0)
755b9c547cSRui Paulo 				return NULL;
765b9c547cSRui Paulo 			/* query number that needs to be send to the device */
775b9c547cSRui Paulo 			if (count == dev->sd_pending_bcast_queries - 1)
785b9c547cSRui Paulo 				goto found;
795b9c547cSRui Paulo 			count++;
805b9c547cSRui Paulo 		}
81f05cddf9SRui Paulo 		if (!q->for_all_peers &&
82*a90b9d01SCy Schubert 		    ether_addr_equal(q->peer, dev->info.p2p_device_addr))
835b9c547cSRui Paulo 			goto found;
84f05cddf9SRui Paulo 	}
85f05cddf9SRui Paulo 
86f05cddf9SRui Paulo 	return NULL;
875b9c547cSRui Paulo 
885b9c547cSRui Paulo found:
895b9c547cSRui Paulo 	if (dev->sd_reqs > 100) {
905b9c547cSRui Paulo 		p2p_dbg(p2p, "Too many SD request attempts to " MACSTR
915b9c547cSRui Paulo 			" - skip remaining queries",
925b9c547cSRui Paulo 			MAC2STR(dev->info.p2p_device_addr));
935b9c547cSRui Paulo 		return NULL;
945b9c547cSRui Paulo 	}
955b9c547cSRui Paulo 	return q;
965b9c547cSRui Paulo }
975b9c547cSRui Paulo 
985b9c547cSRui Paulo 
p2p_decrease_sd_bc_queries(struct p2p_data * p2p,int query_number)995b9c547cSRui Paulo static void p2p_decrease_sd_bc_queries(struct p2p_data *p2p, int query_number)
1005b9c547cSRui Paulo {
1015b9c547cSRui Paulo 	struct p2p_device *dev;
1025b9c547cSRui Paulo 
1035b9c547cSRui Paulo 	p2p->num_p2p_sd_queries--;
1045b9c547cSRui Paulo 	dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
1055b9c547cSRui Paulo 		if (query_number <= dev->sd_pending_bcast_queries - 1) {
1065b9c547cSRui Paulo 			/*
1075b9c547cSRui Paulo 			 * Query not yet sent to the device and it is to be
1085b9c547cSRui Paulo 			 * removed, so update the pending count.
1095b9c547cSRui Paulo 			*/
1105b9c547cSRui Paulo 			dev->sd_pending_bcast_queries--;
1115b9c547cSRui Paulo 		}
1125b9c547cSRui Paulo 	}
113f05cddf9SRui Paulo }
114f05cddf9SRui Paulo 
115f05cddf9SRui Paulo 
p2p_unlink_sd_query(struct p2p_data * p2p,struct p2p_sd_query * query)116f05cddf9SRui Paulo static int p2p_unlink_sd_query(struct p2p_data *p2p,
117f05cddf9SRui Paulo 			       struct p2p_sd_query *query)
118f05cddf9SRui Paulo {
119f05cddf9SRui Paulo 	struct p2p_sd_query *q, *prev;
1205b9c547cSRui Paulo 	int query_number = 0;
1215b9c547cSRui Paulo 
122f05cddf9SRui Paulo 	q = p2p->sd_queries;
123f05cddf9SRui Paulo 	prev = NULL;
124f05cddf9SRui Paulo 	while (q) {
125f05cddf9SRui Paulo 		if (q == query) {
1265b9c547cSRui Paulo 			/* If the query is a broadcast query, decrease one from
1275b9c547cSRui Paulo 			 * all the devices */
1285b9c547cSRui Paulo 			if (query->for_all_peers)
1295b9c547cSRui Paulo 				p2p_decrease_sd_bc_queries(p2p, query_number);
130f05cddf9SRui Paulo 			if (prev)
131f05cddf9SRui Paulo 				prev->next = q->next;
132f05cddf9SRui Paulo 			else
133f05cddf9SRui Paulo 				p2p->sd_queries = q->next;
134f05cddf9SRui Paulo 			if (p2p->sd_query == query)
135f05cddf9SRui Paulo 				p2p->sd_query = NULL;
136f05cddf9SRui Paulo 			return 1;
137f05cddf9SRui Paulo 		}
1385b9c547cSRui Paulo 		if (q->for_all_peers)
1395b9c547cSRui Paulo 			query_number++;
140f05cddf9SRui Paulo 		prev = q;
141f05cddf9SRui Paulo 		q = q->next;
142f05cddf9SRui Paulo 	}
143f05cddf9SRui Paulo 	return 0;
144f05cddf9SRui Paulo }
145f05cddf9SRui Paulo 
146f05cddf9SRui Paulo 
p2p_free_sd_query(struct p2p_sd_query * q)147f05cddf9SRui Paulo static void p2p_free_sd_query(struct p2p_sd_query *q)
148f05cddf9SRui Paulo {
149f05cddf9SRui Paulo 	if (q == NULL)
150f05cddf9SRui Paulo 		return;
151f05cddf9SRui Paulo 	wpabuf_free(q->tlvs);
152f05cddf9SRui Paulo 	os_free(q);
153f05cddf9SRui Paulo }
154f05cddf9SRui Paulo 
155f05cddf9SRui Paulo 
p2p_free_sd_queries(struct p2p_data * p2p)156f05cddf9SRui Paulo void p2p_free_sd_queries(struct p2p_data *p2p)
157f05cddf9SRui Paulo {
158f05cddf9SRui Paulo 	struct p2p_sd_query *q, *prev;
159f05cddf9SRui Paulo 	q = p2p->sd_queries;
160f05cddf9SRui Paulo 	p2p->sd_queries = NULL;
161f05cddf9SRui Paulo 	while (q) {
162f05cddf9SRui Paulo 		prev = q;
163f05cddf9SRui Paulo 		q = q->next;
164f05cddf9SRui Paulo 		p2p_free_sd_query(prev);
165f05cddf9SRui Paulo 	}
1665b9c547cSRui Paulo 	p2p->num_p2p_sd_queries = 0;
167f05cddf9SRui Paulo }
168f05cddf9SRui Paulo 
169f05cddf9SRui Paulo 
p2p_build_sd_query(u16 update_indic,struct wpabuf * tlvs)170f05cddf9SRui Paulo static struct wpabuf * p2p_build_sd_query(u16 update_indic,
171f05cddf9SRui Paulo 					  struct wpabuf *tlvs)
172f05cddf9SRui Paulo {
173f05cddf9SRui Paulo 	struct wpabuf *buf;
174f05cddf9SRui Paulo 	u8 *len_pos;
175f05cddf9SRui Paulo 
176f05cddf9SRui Paulo 	buf = gas_anqp_build_initial_req(0, 100 + wpabuf_len(tlvs));
177f05cddf9SRui Paulo 	if (buf == NULL)
178f05cddf9SRui Paulo 		return NULL;
179f05cddf9SRui Paulo 
180f05cddf9SRui Paulo 	/* ANQP Query Request Frame */
181f05cddf9SRui Paulo 	len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
1825b9c547cSRui Paulo 	wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
183f05cddf9SRui Paulo 	wpabuf_put_le16(buf, update_indic); /* Service Update Indicator */
184f05cddf9SRui Paulo 	wpabuf_put_buf(buf, tlvs);
185f05cddf9SRui Paulo 	gas_anqp_set_element_len(buf, len_pos);
186f05cddf9SRui Paulo 
187f05cddf9SRui Paulo 	gas_anqp_set_len(buf);
188f05cddf9SRui Paulo 
189f05cddf9SRui Paulo 	return buf;
190f05cddf9SRui Paulo }
191f05cddf9SRui Paulo 
192f05cddf9SRui Paulo 
p2p_send_gas_comeback_req(struct p2p_data * p2p,const u8 * dst,u8 dialog_token,int freq)193f05cddf9SRui Paulo static void p2p_send_gas_comeback_req(struct p2p_data *p2p, const u8 *dst,
194f05cddf9SRui Paulo 				      u8 dialog_token, int freq)
195f05cddf9SRui Paulo {
196f05cddf9SRui Paulo 	struct wpabuf *req;
197f05cddf9SRui Paulo 
198f05cddf9SRui Paulo 	req = gas_build_comeback_req(dialog_token);
199f05cddf9SRui Paulo 	if (req == NULL)
200f05cddf9SRui Paulo 		return;
201f05cddf9SRui Paulo 
202f05cddf9SRui Paulo 	p2p->pending_action_state = P2P_NO_PENDING_ACTION;
203f05cddf9SRui Paulo 	if (p2p_send_action(p2p, freq, dst, p2p->cfg->dev_addr, dst,
204f05cddf9SRui Paulo 			    wpabuf_head(req), wpabuf_len(req), 200) < 0)
2055b9c547cSRui Paulo 		p2p_dbg(p2p, "Failed to send Action frame");
206f05cddf9SRui Paulo 
207f05cddf9SRui Paulo 	wpabuf_free(req);
208f05cddf9SRui Paulo }
209f05cddf9SRui Paulo 
210f05cddf9SRui Paulo 
p2p_build_sd_response(u8 dialog_token,u16 status_code,u16 comeback_delay,u16 update_indic,const struct wpabuf * tlvs)211f05cddf9SRui Paulo static struct wpabuf * p2p_build_sd_response(u8 dialog_token, u16 status_code,
212f05cddf9SRui Paulo 					     u16 comeback_delay,
213f05cddf9SRui Paulo 					     u16 update_indic,
214f05cddf9SRui Paulo 					     const struct wpabuf *tlvs)
215f05cddf9SRui Paulo {
216f05cddf9SRui Paulo 	struct wpabuf *buf;
217f05cddf9SRui Paulo 	u8 *len_pos;
218f05cddf9SRui Paulo 
219f05cddf9SRui Paulo 	buf = gas_anqp_build_initial_resp(dialog_token, status_code,
220f05cddf9SRui Paulo 					  comeback_delay,
221f05cddf9SRui Paulo 					  100 + (tlvs ? wpabuf_len(tlvs) : 0));
222f05cddf9SRui Paulo 	if (buf == NULL)
223f05cddf9SRui Paulo 		return NULL;
224f05cddf9SRui Paulo 
225f05cddf9SRui Paulo 	if (tlvs) {
226f05cddf9SRui Paulo 		/* ANQP Query Response Frame */
227f05cddf9SRui Paulo 		len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
2285b9c547cSRui Paulo 		wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
229f05cddf9SRui Paulo 		 /* Service Update Indicator */
230f05cddf9SRui Paulo 		wpabuf_put_le16(buf, update_indic);
231f05cddf9SRui Paulo 		wpabuf_put_buf(buf, tlvs);
232f05cddf9SRui Paulo 		gas_anqp_set_element_len(buf, len_pos);
233f05cddf9SRui Paulo 	}
234f05cddf9SRui Paulo 
235f05cddf9SRui Paulo 	gas_anqp_set_len(buf);
236f05cddf9SRui Paulo 
237f05cddf9SRui Paulo 	return buf;
238f05cddf9SRui Paulo }
239f05cddf9SRui Paulo 
240f05cddf9SRui Paulo 
p2p_build_gas_comeback_resp(u8 dialog_token,u16 status_code,u16 update_indic,const u8 * data,size_t len,u8 frag_id,u8 more,u16 total_len)241f05cddf9SRui Paulo static struct wpabuf * p2p_build_gas_comeback_resp(u8 dialog_token,
242f05cddf9SRui Paulo 						   u16 status_code,
243f05cddf9SRui Paulo 						   u16 update_indic,
244f05cddf9SRui Paulo 						   const u8 *data, size_t len,
245f05cddf9SRui Paulo 						   u8 frag_id, u8 more,
246f05cddf9SRui Paulo 						   u16 total_len)
247f05cddf9SRui Paulo {
248f05cddf9SRui Paulo 	struct wpabuf *buf;
249f05cddf9SRui Paulo 
250f05cddf9SRui Paulo 	buf = gas_anqp_build_comeback_resp(dialog_token, status_code, frag_id,
251f05cddf9SRui Paulo 					   more, 0, 100 + len);
252f05cddf9SRui Paulo 	if (buf == NULL)
253f05cddf9SRui Paulo 		return NULL;
254f05cddf9SRui Paulo 
255f05cddf9SRui Paulo 	if (frag_id == 0) {
256f05cddf9SRui Paulo 		/* ANQP Query Response Frame */
257f05cddf9SRui Paulo 		wpabuf_put_le16(buf, ANQP_VENDOR_SPECIFIC); /* Info ID */
258f05cddf9SRui Paulo 		wpabuf_put_le16(buf, 3 + 1 + 2 + total_len);
2595b9c547cSRui Paulo 		wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
260f05cddf9SRui Paulo 		/* Service Update Indicator */
261f05cddf9SRui Paulo 		wpabuf_put_le16(buf, update_indic);
262f05cddf9SRui Paulo 	}
263f05cddf9SRui Paulo 
264f05cddf9SRui Paulo 	wpabuf_put_data(buf, data, len);
265f05cddf9SRui Paulo 	gas_anqp_set_len(buf);
266f05cddf9SRui Paulo 
267f05cddf9SRui Paulo 	return buf;
268f05cddf9SRui Paulo }
269f05cddf9SRui Paulo 
270f05cddf9SRui Paulo 
p2p_start_sd(struct p2p_data * p2p,struct p2p_device * dev)271f05cddf9SRui Paulo int p2p_start_sd(struct p2p_data *p2p, struct p2p_device *dev)
272f05cddf9SRui Paulo {
273f05cddf9SRui Paulo 	struct wpabuf *req;
274f05cddf9SRui Paulo 	int ret = 0;
275f05cddf9SRui Paulo 	struct p2p_sd_query *query;
276f05cddf9SRui Paulo 	int freq;
2775b9c547cSRui Paulo 	unsigned int wait_time;
278f05cddf9SRui Paulo 
279f05cddf9SRui Paulo 	freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
280f05cddf9SRui Paulo 	if (freq <= 0) {
2815b9c547cSRui Paulo 		p2p_dbg(p2p, "No Listen/Operating frequency known for the peer "
2825b9c547cSRui Paulo 			MACSTR " to send SD Request",
283f05cddf9SRui Paulo 			MAC2STR(dev->info.p2p_device_addr));
284f05cddf9SRui Paulo 		return -1;
285f05cddf9SRui Paulo 	}
286f05cddf9SRui Paulo 
287f05cddf9SRui Paulo 	query = p2p_pending_sd_req(p2p, dev);
288f05cddf9SRui Paulo 	if (query == NULL)
289f05cddf9SRui Paulo 		return -1;
290780fb4a2SCy Schubert 	if (p2p->state == P2P_SEARCH &&
291*a90b9d01SCy Schubert 	    ether_addr_equal(p2p->sd_query_no_ack, dev->info.p2p_device_addr)) {
292780fb4a2SCy Schubert 		p2p_dbg(p2p, "Do not start Service Discovery with " MACSTR
293780fb4a2SCy Schubert 			" due to it being the first no-ACK peer in this search iteration",
294780fb4a2SCy Schubert 			MAC2STR(dev->info.p2p_device_addr));
295780fb4a2SCy Schubert 		return -2;
296780fb4a2SCy Schubert 	}
297f05cddf9SRui Paulo 
2985b9c547cSRui Paulo 	p2p_dbg(p2p, "Start Service Discovery with " MACSTR,
299f05cddf9SRui Paulo 		MAC2STR(dev->info.p2p_device_addr));
300f05cddf9SRui Paulo 
301f05cddf9SRui Paulo 	req = p2p_build_sd_query(p2p->srv_update_indic, query->tlvs);
302f05cddf9SRui Paulo 	if (req == NULL)
303f05cddf9SRui Paulo 		return -1;
304f05cddf9SRui Paulo 
3055b9c547cSRui Paulo 	dev->sd_reqs++;
306f05cddf9SRui Paulo 	p2p->sd_peer = dev;
307f05cddf9SRui Paulo 	p2p->sd_query = query;
308f05cddf9SRui Paulo 	p2p->pending_action_state = P2P_PENDING_SD;
309f05cddf9SRui Paulo 
3105b9c547cSRui Paulo 	wait_time = 5000;
3115b9c547cSRui Paulo 	if (p2p->cfg->max_listen && wait_time > p2p->cfg->max_listen)
3125b9c547cSRui Paulo 		wait_time = p2p->cfg->max_listen;
313f05cddf9SRui Paulo 	if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
314f05cddf9SRui Paulo 			    p2p->cfg->dev_addr, dev->info.p2p_device_addr,
3155b9c547cSRui Paulo 			    wpabuf_head(req), wpabuf_len(req), wait_time) < 0) {
3165b9c547cSRui Paulo 		p2p_dbg(p2p, "Failed to send Action frame");
317f05cddf9SRui Paulo 		ret = -1;
318f05cddf9SRui Paulo 	}
319f05cddf9SRui Paulo 
320f05cddf9SRui Paulo 	wpabuf_free(req);
321f05cddf9SRui Paulo 
322f05cddf9SRui Paulo 	return ret;
323f05cddf9SRui Paulo }
324f05cddf9SRui Paulo 
325f05cddf9SRui Paulo 
p2p_rx_gas_initial_req(struct p2p_data * p2p,const u8 * sa,const u8 * data,size_t len,int rx_freq)326f05cddf9SRui Paulo void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
327f05cddf9SRui Paulo 			    const u8 *data, size_t len, int rx_freq)
328f05cddf9SRui Paulo {
329f05cddf9SRui Paulo 	const u8 *pos = data;
330f05cddf9SRui Paulo 	const u8 *end = data + len;
331f05cddf9SRui Paulo 	const u8 *next;
332f05cddf9SRui Paulo 	u8 dialog_token;
333f05cddf9SRui Paulo 	u16 slen;
334f05cddf9SRui Paulo 	int freq;
335f05cddf9SRui Paulo 	u16 update_indic;
336f05cddf9SRui Paulo 
337f05cddf9SRui Paulo 
338f05cddf9SRui Paulo 	if (p2p->cfg->sd_request == NULL)
339f05cddf9SRui Paulo 		return;
340f05cddf9SRui Paulo 
341f05cddf9SRui Paulo 	if (rx_freq > 0)
342f05cddf9SRui Paulo 		freq = rx_freq;
343f05cddf9SRui Paulo 	else
3445b9c547cSRui Paulo 		freq = p2p_channel_to_freq(p2p->cfg->reg_class,
345f05cddf9SRui Paulo 					   p2p->cfg->channel);
346f05cddf9SRui Paulo 	if (freq < 0)
347f05cddf9SRui Paulo 		return;
348f05cddf9SRui Paulo 
349f05cddf9SRui Paulo 	if (len < 1 + 2)
350f05cddf9SRui Paulo 		return;
351f05cddf9SRui Paulo 
352f05cddf9SRui Paulo 	dialog_token = *pos++;
3535b9c547cSRui Paulo 	p2p_dbg(p2p, "GAS Initial Request from " MACSTR
3545b9c547cSRui Paulo 		" (dialog token %u, freq %d)",
355f05cddf9SRui Paulo 		MAC2STR(sa), dialog_token, rx_freq);
356f05cddf9SRui Paulo 
357f05cddf9SRui Paulo 	if (*pos != WLAN_EID_ADV_PROTO) {
3585b9c547cSRui Paulo 		p2p_dbg(p2p, "Unexpected IE in GAS Initial Request: %u", *pos);
359f05cddf9SRui Paulo 		return;
360f05cddf9SRui Paulo 	}
361f05cddf9SRui Paulo 	pos++;
362f05cddf9SRui Paulo 
363f05cddf9SRui Paulo 	slen = *pos++;
364780fb4a2SCy Schubert 	if (slen > end - pos || slen < 2) {
3655b9c547cSRui Paulo 		p2p_dbg(p2p, "Invalid IE in GAS Initial Request");
366f05cddf9SRui Paulo 		return;
367f05cddf9SRui Paulo 	}
368780fb4a2SCy Schubert 	next = pos + slen;
369f05cddf9SRui Paulo 	pos++; /* skip QueryRespLenLimit and PAME-BI */
370f05cddf9SRui Paulo 
371f05cddf9SRui Paulo 	if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
3725b9c547cSRui Paulo 		p2p_dbg(p2p, "Unsupported GAS advertisement protocol id %u",
373f05cddf9SRui Paulo 			*pos);
374f05cddf9SRui Paulo 		return;
375f05cddf9SRui Paulo 	}
376f05cddf9SRui Paulo 
377f05cddf9SRui Paulo 	pos = next;
378f05cddf9SRui Paulo 	/* Query Request */
379780fb4a2SCy Schubert 	if (end - pos < 2)
380f05cddf9SRui Paulo 		return;
381f05cddf9SRui Paulo 	slen = WPA_GET_LE16(pos);
382f05cddf9SRui Paulo 	pos += 2;
383780fb4a2SCy Schubert 	if (slen > end - pos)
384f05cddf9SRui Paulo 		return;
385f05cddf9SRui Paulo 	end = pos + slen;
386f05cddf9SRui Paulo 
387f05cddf9SRui Paulo 	/* ANQP Query Request */
388780fb4a2SCy Schubert 	if (end - pos < 4)
389f05cddf9SRui Paulo 		return;
390f05cddf9SRui Paulo 	if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
3915b9c547cSRui Paulo 		p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
392f05cddf9SRui Paulo 		return;
393f05cddf9SRui Paulo 	}
394f05cddf9SRui Paulo 	pos += 2;
395f05cddf9SRui Paulo 
396f05cddf9SRui Paulo 	slen = WPA_GET_LE16(pos);
397f05cddf9SRui Paulo 	pos += 2;
398780fb4a2SCy Schubert 	if (slen > end - pos || slen < 3 + 1) {
3995b9c547cSRui Paulo 		p2p_dbg(p2p, "Invalid ANQP Query Request length");
400f05cddf9SRui Paulo 		return;
401f05cddf9SRui Paulo 	}
402f05cddf9SRui Paulo 
4035b9c547cSRui Paulo 	if (WPA_GET_BE32(pos) != P2P_IE_VENDOR_TYPE) {
4045b9c547cSRui Paulo 		p2p_dbg(p2p, "Unsupported ANQP vendor OUI-type %08x",
4055b9c547cSRui Paulo 			WPA_GET_BE32(pos));
406f05cddf9SRui Paulo 		return;
407f05cddf9SRui Paulo 	}
4085b9c547cSRui Paulo 	pos += 4;
409f05cddf9SRui Paulo 
410780fb4a2SCy Schubert 	if (end - pos < 2)
411f05cddf9SRui Paulo 		return;
412f05cddf9SRui Paulo 	update_indic = WPA_GET_LE16(pos);
4135b9c547cSRui Paulo 	p2p_dbg(p2p, "Service Update Indicator: %u", update_indic);
414f05cddf9SRui Paulo 	pos += 2;
415f05cddf9SRui Paulo 
416f05cddf9SRui Paulo 	p2p->cfg->sd_request(p2p->cfg->cb_ctx, freq, sa, dialog_token,
417f05cddf9SRui Paulo 			     update_indic, pos, end - pos);
418f05cddf9SRui Paulo 	/* the response will be indicated with a call to p2p_sd_response() */
419f05cddf9SRui Paulo }
420f05cddf9SRui Paulo 
421f05cddf9SRui Paulo 
p2p_sd_response(struct p2p_data * p2p,int freq,const u8 * dst,u8 dialog_token,const struct wpabuf * resp_tlvs)422f05cddf9SRui Paulo void p2p_sd_response(struct p2p_data *p2p, int freq, const u8 *dst,
423f05cddf9SRui Paulo 		     u8 dialog_token, const struct wpabuf *resp_tlvs)
424f05cddf9SRui Paulo {
425f05cddf9SRui Paulo 	struct wpabuf *resp;
426780fb4a2SCy Schubert 	size_t max_len;
42785732ac8SCy Schubert 	unsigned int wait_time = 200;
428780fb4a2SCy Schubert 
429780fb4a2SCy Schubert 	/*
430780fb4a2SCy Schubert 	 * In the 60 GHz, we have a smaller maximum frame length for management
431780fb4a2SCy Schubert 	 * frames.
432780fb4a2SCy Schubert 	 */
433780fb4a2SCy Schubert 	max_len = (freq > 56160) ? 928 : 1400;
434f05cddf9SRui Paulo 
435f05cddf9SRui Paulo 	/* TODO: fix the length limit to match with the maximum frame length */
436780fb4a2SCy Schubert 	if (wpabuf_len(resp_tlvs) > max_len) {
4375b9c547cSRui Paulo 		p2p_dbg(p2p, "SD response long enough to require fragmentation");
438f05cddf9SRui Paulo 		if (p2p->sd_resp) {
439f05cddf9SRui Paulo 			/*
440f05cddf9SRui Paulo 			 * TODO: Could consider storing the fragmented response
441f05cddf9SRui Paulo 			 * separately for each peer to avoid having to drop old
442f05cddf9SRui Paulo 			 * one if there is more than one pending SD query.
443f05cddf9SRui Paulo 			 * Though, that would eat more memory, so there are
444f05cddf9SRui Paulo 			 * also benefits to just using a single buffer.
445f05cddf9SRui Paulo 			 */
4465b9c547cSRui Paulo 			p2p_dbg(p2p, "Drop previous SD response");
447f05cddf9SRui Paulo 			wpabuf_free(p2p->sd_resp);
448f05cddf9SRui Paulo 		}
449f05cddf9SRui Paulo 		p2p->sd_resp = wpabuf_dup(resp_tlvs);
450f05cddf9SRui Paulo 		if (p2p->sd_resp == NULL) {
4515b9c547cSRui Paulo 			p2p_err(p2p, "Failed to allocate SD response fragmentation area");
452f05cddf9SRui Paulo 			return;
453f05cddf9SRui Paulo 		}
454f05cddf9SRui Paulo 		os_memcpy(p2p->sd_resp_addr, dst, ETH_ALEN);
455f05cddf9SRui Paulo 		p2p->sd_resp_dialog_token = dialog_token;
456f05cddf9SRui Paulo 		p2p->sd_resp_pos = 0;
457f05cddf9SRui Paulo 		p2p->sd_frag_id = 0;
458f05cddf9SRui Paulo 		resp = p2p_build_sd_response(dialog_token, WLAN_STATUS_SUCCESS,
459f05cddf9SRui Paulo 					     1, p2p->srv_update_indic, NULL);
460f05cddf9SRui Paulo 	} else {
4615b9c547cSRui Paulo 		p2p_dbg(p2p, "SD response fits in initial response");
46285732ac8SCy Schubert 		wait_time = 0; /* no more SD frames in the sequence */
463f05cddf9SRui Paulo 		resp = p2p_build_sd_response(dialog_token,
464f05cddf9SRui Paulo 					     WLAN_STATUS_SUCCESS, 0,
465f05cddf9SRui Paulo 					     p2p->srv_update_indic, resp_tlvs);
466f05cddf9SRui Paulo 	}
467f05cddf9SRui Paulo 	if (resp == NULL)
468f05cddf9SRui Paulo 		return;
469f05cddf9SRui Paulo 
470f05cddf9SRui Paulo 	p2p->pending_action_state = P2P_NO_PENDING_ACTION;
471f05cddf9SRui Paulo 	if (p2p_send_action(p2p, freq, dst, p2p->cfg->dev_addr,
472f05cddf9SRui Paulo 			    p2p->cfg->dev_addr,
47385732ac8SCy Schubert 			    wpabuf_head(resp), wpabuf_len(resp), wait_time) < 0)
4745b9c547cSRui Paulo 		p2p_dbg(p2p, "Failed to send Action frame");
475f05cddf9SRui Paulo 
476f05cddf9SRui Paulo 	wpabuf_free(resp);
477f05cddf9SRui Paulo }
478f05cddf9SRui Paulo 
479f05cddf9SRui Paulo 
p2p_rx_gas_initial_resp(struct p2p_data * p2p,const u8 * sa,const u8 * data,size_t len,int rx_freq)480f05cddf9SRui Paulo void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
481f05cddf9SRui Paulo 			     const u8 *data, size_t len, int rx_freq)
482f05cddf9SRui Paulo {
483f05cddf9SRui Paulo 	const u8 *pos = data;
484f05cddf9SRui Paulo 	const u8 *end = data + len;
485f05cddf9SRui Paulo 	const u8 *next;
486f05cddf9SRui Paulo 	u8 dialog_token;
487f05cddf9SRui Paulo 	u16 status_code;
488f05cddf9SRui Paulo 	u16 comeback_delay;
489f05cddf9SRui Paulo 	u16 slen;
490f05cddf9SRui Paulo 	u16 update_indic;
491f05cddf9SRui Paulo 
492*a90b9d01SCy Schubert 	if ((p2p->state != P2P_SD_DURING_FIND && p2p->state != P2P_SEARCH) ||
493*a90b9d01SCy Schubert 	    !p2p->sd_peer ||
494*a90b9d01SCy Schubert 	    !ether_addr_equal(sa, p2p->sd_peer->info.p2p_device_addr)) {
4955b9c547cSRui Paulo 		p2p_dbg(p2p, "Ignore unexpected GAS Initial Response from "
496f05cddf9SRui Paulo 			MACSTR, MAC2STR(sa));
497f05cddf9SRui Paulo 		return;
498f05cddf9SRui Paulo 	}
499*a90b9d01SCy Schubert 	if (p2p->state == P2P_SEARCH) {
500*a90b9d01SCy Schubert 		/* It is possible for the TX status and RX response events to be
501*a90b9d01SCy Schubert 		 * reordered, so assume the request was ACKed if a response is
502*a90b9d01SCy Schubert 		 * received. */
503*a90b9d01SCy Schubert 		p2p_dbg(p2p,
504*a90b9d01SCy Schubert 			"GAS Initial Request had not yet received TX status - process the response anyway");
505*a90b9d01SCy Schubert 		p2p_sd_query_cb(p2p, 1);
506*a90b9d01SCy Schubert 	}
507f05cddf9SRui Paulo 	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
508f05cddf9SRui Paulo 	p2p_clear_timeout(p2p);
509f05cddf9SRui Paulo 
5105b9c547cSRui Paulo 	p2p_dbg(p2p, "Received GAS Initial Response from " MACSTR " (len=%d)",
511f05cddf9SRui Paulo 		MAC2STR(sa), (int) len);
512f05cddf9SRui Paulo 
513f05cddf9SRui Paulo 	if (len < 5 + 2) {
5145b9c547cSRui Paulo 		p2p_dbg(p2p, "Too short GAS Initial Response frame");
515f05cddf9SRui Paulo 		return;
516f05cddf9SRui Paulo 	}
517f05cddf9SRui Paulo 
518f05cddf9SRui Paulo 	dialog_token = *pos++;
519f05cddf9SRui Paulo 	/* TODO: check dialog_token match */
520f05cddf9SRui Paulo 	status_code = WPA_GET_LE16(pos);
521f05cddf9SRui Paulo 	pos += 2;
522f05cddf9SRui Paulo 	comeback_delay = WPA_GET_LE16(pos);
523f05cddf9SRui Paulo 	pos += 2;
5245b9c547cSRui Paulo 	p2p_dbg(p2p, "dialog_token=%u status_code=%u comeback_delay=%u",
525f05cddf9SRui Paulo 		dialog_token, status_code, comeback_delay);
526f05cddf9SRui Paulo 	if (status_code) {
5275b9c547cSRui Paulo 		p2p_dbg(p2p, "Service Discovery failed: status code %u",
528f05cddf9SRui Paulo 			status_code);
529f05cddf9SRui Paulo 		return;
530f05cddf9SRui Paulo 	}
531f05cddf9SRui Paulo 
532f05cddf9SRui Paulo 	if (*pos != WLAN_EID_ADV_PROTO) {
5335b9c547cSRui Paulo 		p2p_dbg(p2p, "Unexpected IE in GAS Initial Response: %u", *pos);
534f05cddf9SRui Paulo 		return;
535f05cddf9SRui Paulo 	}
536f05cddf9SRui Paulo 	pos++;
537f05cddf9SRui Paulo 
538f05cddf9SRui Paulo 	slen = *pos++;
539780fb4a2SCy Schubert 	if (slen > end - pos || slen < 2) {
5405b9c547cSRui Paulo 		p2p_dbg(p2p, "Invalid IE in GAS Initial Response");
541f05cddf9SRui Paulo 		return;
542f05cddf9SRui Paulo 	}
543780fb4a2SCy Schubert 	next = pos + slen;
544f05cddf9SRui Paulo 	pos++; /* skip QueryRespLenLimit and PAME-BI */
545f05cddf9SRui Paulo 
546f05cddf9SRui Paulo 	if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
5475b9c547cSRui Paulo 		p2p_dbg(p2p, "Unsupported GAS advertisement protocol id %u",
548f05cddf9SRui Paulo 			*pos);
549f05cddf9SRui Paulo 		return;
550f05cddf9SRui Paulo 	}
551f05cddf9SRui Paulo 
552f05cddf9SRui Paulo 	pos = next;
553f05cddf9SRui Paulo 	/* Query Response */
554780fb4a2SCy Schubert 	if (end - pos < 2) {
5555b9c547cSRui Paulo 		p2p_dbg(p2p, "Too short Query Response");
556f05cddf9SRui Paulo 		return;
557f05cddf9SRui Paulo 	}
558f05cddf9SRui Paulo 	slen = WPA_GET_LE16(pos);
559f05cddf9SRui Paulo 	pos += 2;
5605b9c547cSRui Paulo 	p2p_dbg(p2p, "Query Response Length: %d", slen);
561780fb4a2SCy Schubert 	if (slen > end - pos) {
5625b9c547cSRui Paulo 		p2p_dbg(p2p, "Not enough Query Response data");
563f05cddf9SRui Paulo 		return;
564f05cddf9SRui Paulo 	}
565f05cddf9SRui Paulo 	end = pos + slen;
566f05cddf9SRui Paulo 
567f05cddf9SRui Paulo 	if (comeback_delay) {
5685b9c547cSRui Paulo 		p2p_dbg(p2p, "Fragmented response - request fragments");
569f05cddf9SRui Paulo 		if (p2p->sd_rx_resp) {
5705b9c547cSRui Paulo 			p2p_dbg(p2p, "Drop old SD reassembly buffer");
571f05cddf9SRui Paulo 			wpabuf_free(p2p->sd_rx_resp);
572f05cddf9SRui Paulo 			p2p->sd_rx_resp = NULL;
573f05cddf9SRui Paulo 		}
574f05cddf9SRui Paulo 		p2p_send_gas_comeback_req(p2p, sa, dialog_token, rx_freq);
575f05cddf9SRui Paulo 		return;
576f05cddf9SRui Paulo 	}
577f05cddf9SRui Paulo 
578f05cddf9SRui Paulo 	/* ANQP Query Response */
579780fb4a2SCy Schubert 	if (end - pos < 4)
580f05cddf9SRui Paulo 		return;
581f05cddf9SRui Paulo 	if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
5825b9c547cSRui Paulo 		p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
583f05cddf9SRui Paulo 		return;
584f05cddf9SRui Paulo 	}
585f05cddf9SRui Paulo 	pos += 2;
586f05cddf9SRui Paulo 
587f05cddf9SRui Paulo 	slen = WPA_GET_LE16(pos);
588f05cddf9SRui Paulo 	pos += 2;
589780fb4a2SCy Schubert 	if (slen > end - pos || slen < 3 + 1) {
5905b9c547cSRui Paulo 		p2p_dbg(p2p, "Invalid ANQP Query Response length");
591f05cddf9SRui Paulo 		return;
592f05cddf9SRui Paulo 	}
593f05cddf9SRui Paulo 
5945b9c547cSRui Paulo 	if (WPA_GET_BE32(pos) != P2P_IE_VENDOR_TYPE) {
5955b9c547cSRui Paulo 		p2p_dbg(p2p, "Unsupported ANQP vendor OUI-type %08x",
5965b9c547cSRui Paulo 			WPA_GET_BE32(pos));
597f05cddf9SRui Paulo 		return;
598f05cddf9SRui Paulo 	}
5995b9c547cSRui Paulo 	pos += 4;
600f05cddf9SRui Paulo 
601780fb4a2SCy Schubert 	if (end - pos < 2)
602f05cddf9SRui Paulo 		return;
603f05cddf9SRui Paulo 	update_indic = WPA_GET_LE16(pos);
6045b9c547cSRui Paulo 	p2p_dbg(p2p, "Service Update Indicator: %u", update_indic);
605f05cddf9SRui Paulo 	pos += 2;
606f05cddf9SRui Paulo 
607f05cddf9SRui Paulo 	p2p->sd_peer = NULL;
608f05cddf9SRui Paulo 
609f05cddf9SRui Paulo 	if (p2p->sd_query) {
610f05cddf9SRui Paulo 		if (!p2p->sd_query->for_all_peers) {
611f05cddf9SRui Paulo 			struct p2p_sd_query *q;
6125b9c547cSRui Paulo 			p2p_dbg(p2p, "Remove completed SD query %p",
613f05cddf9SRui Paulo 				p2p->sd_query);
614f05cddf9SRui Paulo 			q = p2p->sd_query;
615f05cddf9SRui Paulo 			p2p_unlink_sd_query(p2p, p2p->sd_query);
616f05cddf9SRui Paulo 			p2p_free_sd_query(q);
617f05cddf9SRui Paulo 		}
618f05cddf9SRui Paulo 		p2p->sd_query = NULL;
619f05cddf9SRui Paulo 	}
620f05cddf9SRui Paulo 
621f05cddf9SRui Paulo 	if (p2p->cfg->sd_response)
622f05cddf9SRui Paulo 		p2p->cfg->sd_response(p2p->cfg->cb_ctx, sa, update_indic,
623f05cddf9SRui Paulo 				      pos, end - pos);
624f05cddf9SRui Paulo 	p2p_continue_find(p2p);
625f05cddf9SRui Paulo }
626f05cddf9SRui Paulo 
627f05cddf9SRui Paulo 
p2p_rx_gas_comeback_req(struct p2p_data * p2p,const u8 * sa,const u8 * data,size_t len,int rx_freq)628f05cddf9SRui Paulo void p2p_rx_gas_comeback_req(struct p2p_data *p2p, const u8 *sa,
629f05cddf9SRui Paulo 			     const u8 *data, size_t len, int rx_freq)
630f05cddf9SRui Paulo {
631f05cddf9SRui Paulo 	struct wpabuf *resp;
632f05cddf9SRui Paulo 	u8 dialog_token;
633780fb4a2SCy Schubert 	size_t frag_len, max_len;
634f05cddf9SRui Paulo 	int more = 0;
63585732ac8SCy Schubert 	unsigned int wait_time = 200;
636f05cddf9SRui Paulo 
637f05cddf9SRui Paulo 	wpa_hexdump(MSG_DEBUG, "P2P: RX GAS Comeback Request", data, len);
638f05cddf9SRui Paulo 	if (len < 1)
639f05cddf9SRui Paulo 		return;
640f05cddf9SRui Paulo 	dialog_token = *data;
6415b9c547cSRui Paulo 	p2p_dbg(p2p, "Dialog Token: %u", dialog_token);
642f05cddf9SRui Paulo 	if (dialog_token != p2p->sd_resp_dialog_token) {
6435b9c547cSRui Paulo 		p2p_dbg(p2p, "No pending SD response fragment for dialog token %u",
6445b9c547cSRui Paulo 			dialog_token);
645f05cddf9SRui Paulo 		return;
646f05cddf9SRui Paulo 	}
647f05cddf9SRui Paulo 
648f05cddf9SRui Paulo 	if (p2p->sd_resp == NULL) {
6495b9c547cSRui Paulo 		p2p_dbg(p2p, "No pending SD response fragment available");
650f05cddf9SRui Paulo 		return;
651f05cddf9SRui Paulo 	}
652*a90b9d01SCy Schubert 	if (!ether_addr_equal(sa, p2p->sd_resp_addr)) {
6535b9c547cSRui Paulo 		p2p_dbg(p2p, "No pending SD response fragment for " MACSTR,
6545b9c547cSRui Paulo 			MAC2STR(sa));
655f05cddf9SRui Paulo 		return;
656f05cddf9SRui Paulo 	}
657f05cddf9SRui Paulo 
658780fb4a2SCy Schubert 	/*
659780fb4a2SCy Schubert 	 * In the 60 GHz, we have a smaller maximum frame length for management
660780fb4a2SCy Schubert 	 * frames.
661780fb4a2SCy Schubert 	 */
662780fb4a2SCy Schubert 	max_len = (rx_freq > 56160) ? 928 : 1400;
663f05cddf9SRui Paulo 	frag_len = wpabuf_len(p2p->sd_resp) - p2p->sd_resp_pos;
664780fb4a2SCy Schubert 	if (frag_len > max_len) {
665780fb4a2SCy Schubert 		frag_len = max_len;
666f05cddf9SRui Paulo 		more = 1;
667f05cddf9SRui Paulo 	}
668f05cddf9SRui Paulo 	resp = p2p_build_gas_comeback_resp(dialog_token, WLAN_STATUS_SUCCESS,
669f05cddf9SRui Paulo 					   p2p->srv_update_indic,
670f05cddf9SRui Paulo 					   wpabuf_head_u8(p2p->sd_resp) +
671f05cddf9SRui Paulo 					   p2p->sd_resp_pos, frag_len,
672f05cddf9SRui Paulo 					   p2p->sd_frag_id, more,
673f05cddf9SRui Paulo 					   wpabuf_len(p2p->sd_resp));
674f05cddf9SRui Paulo 	if (resp == NULL)
675f05cddf9SRui Paulo 		return;
6765b9c547cSRui Paulo 	p2p_dbg(p2p, "Send GAS Comeback Response (frag_id %d more=%d frag_len=%d)",
677f05cddf9SRui Paulo 		p2p->sd_frag_id, more, (int) frag_len);
678f05cddf9SRui Paulo 	p2p->sd_frag_id++;
679f05cddf9SRui Paulo 	p2p->sd_resp_pos += frag_len;
680f05cddf9SRui Paulo 
681f05cddf9SRui Paulo 	if (more) {
6825b9c547cSRui Paulo 		p2p_dbg(p2p, "%d more bytes remain to be sent",
683f05cddf9SRui Paulo 			(int) (wpabuf_len(p2p->sd_resp) - p2p->sd_resp_pos));
684f05cddf9SRui Paulo 	} else {
6855b9c547cSRui Paulo 		p2p_dbg(p2p, "All fragments of SD response sent");
686f05cddf9SRui Paulo 		wpabuf_free(p2p->sd_resp);
687f05cddf9SRui Paulo 		p2p->sd_resp = NULL;
68885732ac8SCy Schubert 		wait_time = 0; /* no more SD frames in the sequence */
689f05cddf9SRui Paulo 	}
690f05cddf9SRui Paulo 
691f05cddf9SRui Paulo 	p2p->pending_action_state = P2P_NO_PENDING_ACTION;
692f05cddf9SRui Paulo 	if (p2p_send_action(p2p, rx_freq, sa, p2p->cfg->dev_addr,
693f05cddf9SRui Paulo 			    p2p->cfg->dev_addr,
69485732ac8SCy Schubert 			    wpabuf_head(resp), wpabuf_len(resp), wait_time) < 0)
6955b9c547cSRui Paulo 		p2p_dbg(p2p, "Failed to send Action frame");
696f05cddf9SRui Paulo 
697f05cddf9SRui Paulo 	wpabuf_free(resp);
698f05cddf9SRui Paulo }
699f05cddf9SRui Paulo 
700f05cddf9SRui Paulo 
p2p_rx_gas_comeback_resp(struct p2p_data * p2p,const u8 * sa,const u8 * data,size_t len,int rx_freq)701f05cddf9SRui Paulo void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
702f05cddf9SRui Paulo 			      const u8 *data, size_t len, int rx_freq)
703f05cddf9SRui Paulo {
704f05cddf9SRui Paulo 	const u8 *pos = data;
705f05cddf9SRui Paulo 	const u8 *end = data + len;
706f05cddf9SRui Paulo 	const u8 *next;
707f05cddf9SRui Paulo 	u8 dialog_token;
708f05cddf9SRui Paulo 	u16 status_code;
709f05cddf9SRui Paulo 	u8 frag_id;
710f05cddf9SRui Paulo 	u8 more_frags;
711f05cddf9SRui Paulo 	u16 comeback_delay;
712f05cddf9SRui Paulo 	u16 slen;
713f05cddf9SRui Paulo 
714f05cddf9SRui Paulo 	wpa_hexdump(MSG_DEBUG, "P2P: RX GAS Comeback Response", data, len);
715f05cddf9SRui Paulo 
716f05cddf9SRui Paulo 	if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL ||
717*a90b9d01SCy Schubert 	    !ether_addr_equal(sa, p2p->sd_peer->info.p2p_device_addr)) {
7185b9c547cSRui Paulo 		p2p_dbg(p2p, "Ignore unexpected GAS Comeback Response from "
719f05cddf9SRui Paulo 			MACSTR, MAC2STR(sa));
720f05cddf9SRui Paulo 		return;
721f05cddf9SRui Paulo 	}
722f05cddf9SRui Paulo 	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
723f05cddf9SRui Paulo 	p2p_clear_timeout(p2p);
724f05cddf9SRui Paulo 
7255b9c547cSRui Paulo 	p2p_dbg(p2p, "Received GAS Comeback Response from " MACSTR " (len=%d)",
726f05cddf9SRui Paulo 		MAC2STR(sa), (int) len);
727f05cddf9SRui Paulo 
728f05cddf9SRui Paulo 	if (len < 6 + 2) {
7295b9c547cSRui Paulo 		p2p_dbg(p2p, "Too short GAS Comeback Response frame");
730f05cddf9SRui Paulo 		return;
731f05cddf9SRui Paulo 	}
732f05cddf9SRui Paulo 
733f05cddf9SRui Paulo 	dialog_token = *pos++;
734f05cddf9SRui Paulo 	/* TODO: check dialog_token match */
735f05cddf9SRui Paulo 	status_code = WPA_GET_LE16(pos);
736f05cddf9SRui Paulo 	pos += 2;
737f05cddf9SRui Paulo 	frag_id = *pos & 0x7f;
738f05cddf9SRui Paulo 	more_frags = (*pos & 0x80) >> 7;
739f05cddf9SRui Paulo 	pos++;
740f05cddf9SRui Paulo 	comeback_delay = WPA_GET_LE16(pos);
741f05cddf9SRui Paulo 	pos += 2;
7425b9c547cSRui Paulo 	p2p_dbg(p2p, "dialog_token=%u status_code=%u frag_id=%d more_frags=%d "
743f05cddf9SRui Paulo 		"comeback_delay=%u",
744f05cddf9SRui Paulo 		dialog_token, status_code, frag_id, more_frags,
745f05cddf9SRui Paulo 		comeback_delay);
746f05cddf9SRui Paulo 	/* TODO: check frag_id match */
747f05cddf9SRui Paulo 	if (status_code) {
7485b9c547cSRui Paulo 		p2p_dbg(p2p, "Service Discovery failed: status code %u",
749f05cddf9SRui Paulo 			status_code);
750f05cddf9SRui Paulo 		return;
751f05cddf9SRui Paulo 	}
752f05cddf9SRui Paulo 
753f05cddf9SRui Paulo 	if (*pos != WLAN_EID_ADV_PROTO) {
7545b9c547cSRui Paulo 		p2p_dbg(p2p, "Unexpected IE in GAS Comeback Response: %u",
755f05cddf9SRui Paulo 			*pos);
756f05cddf9SRui Paulo 		return;
757f05cddf9SRui Paulo 	}
758f05cddf9SRui Paulo 	pos++;
759f05cddf9SRui Paulo 
760f05cddf9SRui Paulo 	slen = *pos++;
761780fb4a2SCy Schubert 	if (slen > end - pos || slen < 2) {
7625b9c547cSRui Paulo 		p2p_dbg(p2p, "Invalid IE in GAS Comeback Response");
763f05cddf9SRui Paulo 		return;
764f05cddf9SRui Paulo 	}
765780fb4a2SCy Schubert 	next = pos + slen;
766f05cddf9SRui Paulo 	pos++; /* skip QueryRespLenLimit and PAME-BI */
767f05cddf9SRui Paulo 
768f05cddf9SRui Paulo 	if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
7695b9c547cSRui Paulo 		p2p_dbg(p2p, "Unsupported GAS advertisement protocol id %u",
770f05cddf9SRui Paulo 			*pos);
771f05cddf9SRui Paulo 		return;
772f05cddf9SRui Paulo 	}
773f05cddf9SRui Paulo 
774f05cddf9SRui Paulo 	pos = next;
775f05cddf9SRui Paulo 	/* Query Response */
776780fb4a2SCy Schubert 	if (end - pos < 2) {
7775b9c547cSRui Paulo 		p2p_dbg(p2p, "Too short Query Response");
778f05cddf9SRui Paulo 		return;
779f05cddf9SRui Paulo 	}
780f05cddf9SRui Paulo 	slen = WPA_GET_LE16(pos);
781f05cddf9SRui Paulo 	pos += 2;
7825b9c547cSRui Paulo 	p2p_dbg(p2p, "Query Response Length: %d", slen);
783780fb4a2SCy Schubert 	if (slen > end - pos) {
7845b9c547cSRui Paulo 		p2p_dbg(p2p, "Not enough Query Response data");
785f05cddf9SRui Paulo 		return;
786f05cddf9SRui Paulo 	}
787f05cddf9SRui Paulo 	if (slen == 0) {
7885b9c547cSRui Paulo 		p2p_dbg(p2p, "No Query Response data");
789f05cddf9SRui Paulo 		return;
790f05cddf9SRui Paulo 	}
791f05cddf9SRui Paulo 	end = pos + slen;
792f05cddf9SRui Paulo 
793f05cddf9SRui Paulo 	if (p2p->sd_rx_resp) {
794f05cddf9SRui Paulo 		 /*
795f05cddf9SRui Paulo 		  * ANQP header is only included in the first fragment; rest of
796f05cddf9SRui Paulo 		  * the fragments start with continue TLVs.
797f05cddf9SRui Paulo 		  */
798f05cddf9SRui Paulo 		goto skip_nqp_header;
799f05cddf9SRui Paulo 	}
800f05cddf9SRui Paulo 
801f05cddf9SRui Paulo 	/* ANQP Query Response */
802780fb4a2SCy Schubert 	if (end - pos < 4)
803f05cddf9SRui Paulo 		return;
804f05cddf9SRui Paulo 	if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
8055b9c547cSRui Paulo 		p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
806f05cddf9SRui Paulo 		return;
807f05cddf9SRui Paulo 	}
808f05cddf9SRui Paulo 	pos += 2;
809f05cddf9SRui Paulo 
810f05cddf9SRui Paulo 	slen = WPA_GET_LE16(pos);
811f05cddf9SRui Paulo 	pos += 2;
8125b9c547cSRui Paulo 	p2p_dbg(p2p, "ANQP Query Response length: %u", slen);
813f05cddf9SRui Paulo 	if (slen < 3 + 1) {
8145b9c547cSRui Paulo 		p2p_dbg(p2p, "Invalid ANQP Query Response length");
815f05cddf9SRui Paulo 		return;
816f05cddf9SRui Paulo 	}
817780fb4a2SCy Schubert 	if (end - pos < 4)
818f05cddf9SRui Paulo 		return;
819f05cddf9SRui Paulo 
8205b9c547cSRui Paulo 	if (WPA_GET_BE32(pos) != P2P_IE_VENDOR_TYPE) {
8215b9c547cSRui Paulo 		p2p_dbg(p2p, "Unsupported ANQP vendor OUI-type %08x",
8225b9c547cSRui Paulo 			WPA_GET_BE32(pos));
823f05cddf9SRui Paulo 		return;
824f05cddf9SRui Paulo 	}
8255b9c547cSRui Paulo 	pos += 4;
826f05cddf9SRui Paulo 
827780fb4a2SCy Schubert 	if (end - pos < 2)
828f05cddf9SRui Paulo 		return;
829f05cddf9SRui Paulo 	p2p->sd_rx_update_indic = WPA_GET_LE16(pos);
8305b9c547cSRui Paulo 	p2p_dbg(p2p, "Service Update Indicator: %u", p2p->sd_rx_update_indic);
831f05cddf9SRui Paulo 	pos += 2;
832f05cddf9SRui Paulo 
833f05cddf9SRui Paulo skip_nqp_header:
834f05cddf9SRui Paulo 	if (wpabuf_resize(&p2p->sd_rx_resp, end - pos) < 0)
835f05cddf9SRui Paulo 		return;
836f05cddf9SRui Paulo 	wpabuf_put_data(p2p->sd_rx_resp, pos, end - pos);
8375b9c547cSRui Paulo 	p2p_dbg(p2p, "Current SD reassembly buffer length: %u",
838f05cddf9SRui Paulo 		(unsigned int) wpabuf_len(p2p->sd_rx_resp));
839f05cddf9SRui Paulo 
840f05cddf9SRui Paulo 	if (more_frags) {
8415b9c547cSRui Paulo 		p2p_dbg(p2p, "More fragments remains");
842f05cddf9SRui Paulo 		/* TODO: what would be a good size limit? */
843f05cddf9SRui Paulo 		if (wpabuf_len(p2p->sd_rx_resp) > 64000) {
844f05cddf9SRui Paulo 			wpabuf_free(p2p->sd_rx_resp);
845f05cddf9SRui Paulo 			p2p->sd_rx_resp = NULL;
8465b9c547cSRui Paulo 			p2p_dbg(p2p, "Too long SD response - drop it");
847f05cddf9SRui Paulo 			return;
848f05cddf9SRui Paulo 		}
849f05cddf9SRui Paulo 		p2p_send_gas_comeback_req(p2p, sa, dialog_token, rx_freq);
850f05cddf9SRui Paulo 		return;
851f05cddf9SRui Paulo 	}
852f05cddf9SRui Paulo 
853f05cddf9SRui Paulo 	p2p->sd_peer = NULL;
854f05cddf9SRui Paulo 
855f05cddf9SRui Paulo 	if (p2p->sd_query) {
856f05cddf9SRui Paulo 		if (!p2p->sd_query->for_all_peers) {
857f05cddf9SRui Paulo 			struct p2p_sd_query *q;
8585b9c547cSRui Paulo 			p2p_dbg(p2p, "Remove completed SD query %p",
859f05cddf9SRui Paulo 				p2p->sd_query);
860f05cddf9SRui Paulo 			q = p2p->sd_query;
861f05cddf9SRui Paulo 			p2p_unlink_sd_query(p2p, p2p->sd_query);
862f05cddf9SRui Paulo 			p2p_free_sd_query(q);
863f05cddf9SRui Paulo 		}
864f05cddf9SRui Paulo 		p2p->sd_query = NULL;
865f05cddf9SRui Paulo 	}
866f05cddf9SRui Paulo 
867f05cddf9SRui Paulo 	if (p2p->cfg->sd_response)
868f05cddf9SRui Paulo 		p2p->cfg->sd_response(p2p->cfg->cb_ctx, sa,
869f05cddf9SRui Paulo 				      p2p->sd_rx_update_indic,
870f05cddf9SRui Paulo 				      wpabuf_head(p2p->sd_rx_resp),
871f05cddf9SRui Paulo 				      wpabuf_len(p2p->sd_rx_resp));
872f05cddf9SRui Paulo 	wpabuf_free(p2p->sd_rx_resp);
873f05cddf9SRui Paulo 	p2p->sd_rx_resp = NULL;
874f05cddf9SRui Paulo 
875f05cddf9SRui Paulo 	p2p_continue_find(p2p);
876f05cddf9SRui Paulo }
877f05cddf9SRui Paulo 
878f05cddf9SRui Paulo 
p2p_sd_request(struct p2p_data * p2p,const u8 * dst,const struct wpabuf * tlvs)879f05cddf9SRui Paulo void * p2p_sd_request(struct p2p_data *p2p, const u8 *dst,
880f05cddf9SRui Paulo 		      const struct wpabuf *tlvs)
881f05cddf9SRui Paulo {
882f05cddf9SRui Paulo 	struct p2p_sd_query *q;
883f05cddf9SRui Paulo 
884f05cddf9SRui Paulo 	q = os_zalloc(sizeof(*q));
885f05cddf9SRui Paulo 	if (q == NULL)
886f05cddf9SRui Paulo 		return NULL;
887f05cddf9SRui Paulo 
888f05cddf9SRui Paulo 	if (dst)
889f05cddf9SRui Paulo 		os_memcpy(q->peer, dst, ETH_ALEN);
890f05cddf9SRui Paulo 	else
891f05cddf9SRui Paulo 		q->for_all_peers = 1;
892f05cddf9SRui Paulo 
893f05cddf9SRui Paulo 	q->tlvs = wpabuf_dup(tlvs);
894f05cddf9SRui Paulo 	if (q->tlvs == NULL) {
895f05cddf9SRui Paulo 		p2p_free_sd_query(q);
896f05cddf9SRui Paulo 		return NULL;
897f05cddf9SRui Paulo 	}
898f05cddf9SRui Paulo 
899f05cddf9SRui Paulo 	q->next = p2p->sd_queries;
900f05cddf9SRui Paulo 	p2p->sd_queries = q;
9015b9c547cSRui Paulo 	p2p_dbg(p2p, "Added SD Query %p", q);
902f05cddf9SRui Paulo 
903f05cddf9SRui Paulo 	if (dst == NULL) {
904f05cddf9SRui Paulo 		struct p2p_device *dev;
9055b9c547cSRui Paulo 
9065b9c547cSRui Paulo 		p2p->num_p2p_sd_queries++;
9075b9c547cSRui Paulo 
9085b9c547cSRui Paulo 		/* Update all the devices for the newly added broadcast query */
9095b9c547cSRui Paulo 		dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
9105b9c547cSRui Paulo 			if (dev->sd_pending_bcast_queries <= 0)
9115b9c547cSRui Paulo 				dev->sd_pending_bcast_queries = 1;
9125b9c547cSRui Paulo 			else
9135b9c547cSRui Paulo 				dev->sd_pending_bcast_queries++;
9145b9c547cSRui Paulo 		}
915f05cddf9SRui Paulo 	}
916f05cddf9SRui Paulo 
917f05cddf9SRui Paulo 	return q;
918f05cddf9SRui Paulo }
919f05cddf9SRui Paulo 
920f05cddf9SRui Paulo 
921f05cddf9SRui Paulo #ifdef CONFIG_WIFI_DISPLAY
p2p_sd_request_wfd(struct p2p_data * p2p,const u8 * dst,const struct wpabuf * tlvs)922f05cddf9SRui Paulo void * p2p_sd_request_wfd(struct p2p_data *p2p, const u8 *dst,
923f05cddf9SRui Paulo 			  const struct wpabuf *tlvs)
924f05cddf9SRui Paulo {
925f05cddf9SRui Paulo 	struct p2p_sd_query *q;
926f05cddf9SRui Paulo 	q = p2p_sd_request(p2p, dst, tlvs);
927f05cddf9SRui Paulo 	if (q)
928f05cddf9SRui Paulo 		q->wsd = 1;
929f05cddf9SRui Paulo 	return q;
930f05cddf9SRui Paulo }
931f05cddf9SRui Paulo #endif /* CONFIG_WIFI_DISPLAY */
932f05cddf9SRui Paulo 
933f05cddf9SRui Paulo 
p2p_sd_service_update(struct p2p_data * p2p)934f05cddf9SRui Paulo void p2p_sd_service_update(struct p2p_data *p2p)
935f05cddf9SRui Paulo {
936f05cddf9SRui Paulo 	p2p->srv_update_indic++;
937f05cddf9SRui Paulo }
938f05cddf9SRui Paulo 
939f05cddf9SRui Paulo 
p2p_sd_cancel_request(struct p2p_data * p2p,void * req)940f05cddf9SRui Paulo int p2p_sd_cancel_request(struct p2p_data *p2p, void *req)
941f05cddf9SRui Paulo {
942f05cddf9SRui Paulo 	if (p2p_unlink_sd_query(p2p, req)) {
9435b9c547cSRui Paulo 		p2p_dbg(p2p, "Cancel pending SD query %p", req);
944f05cddf9SRui Paulo 		p2p_free_sd_query(req);
945f05cddf9SRui Paulo 		return 0;
946f05cddf9SRui Paulo 	}
947f05cddf9SRui Paulo 	return -1;
948f05cddf9SRui Paulo }
949