blob: 9df834c4cae01d6fe7e747f727ea128b18f2c75f [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * Wi-Fi Direct - P2P service discovery
3 * Copyright (c) 2009, Atheros Communications
4 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007 */
8
9#include "includes.h"
10
11#include "common.h"
12#include "common/ieee802_11_defs.h"
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080013#include "common/gas.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070014#include "p2p_i.h"
15#include "p2p.h"
16
17
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070018#ifdef CONFIG_WIFI_DISPLAY
19static int wfd_wsd_supported(struct wpabuf *wfd)
20{
21 const u8 *pos, *end;
22 u8 subelem;
23 u16 len;
24
25 if (wfd == NULL)
26 return 0;
27
28 pos = wpabuf_head(wfd);
29 end = pos + wpabuf_len(wfd);
30
31 while (pos + 3 <= end) {
32 subelem = *pos++;
33 len = WPA_GET_BE16(pos);
34 pos += 2;
35 if (pos + len > end)
36 break;
37
38 if (subelem == WFD_SUBELEM_DEVICE_INFO && len >= 6) {
39 u16 info = WPA_GET_BE16(pos);
40 return !!(info & 0x0040);
41 }
42
43 pos += len;
44 }
45
46 return 0;
47}
48#endif /* CONFIG_WIFI_DISPLAY */
49
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070050struct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p,
51 struct p2p_device *dev)
52{
53 struct p2p_sd_query *q;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070054 int wsd = 0;
Dmitry Shmidt13ca8d82014-02-20 10:18:40 -080055 int count = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070056
57 if (!(dev->info.dev_capab & P2P_DEV_CAPAB_SERVICE_DISCOVERY))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080058 return NULL; /* peer does not support SD */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070059#ifdef CONFIG_WIFI_DISPLAY
60 if (wfd_wsd_supported(dev->info.wfd_subelems))
61 wsd = 1;
62#endif /* CONFIG_WIFI_DISPLAY */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070063
64 for (q = p2p->sd_queries; q; q = q->next) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070065 /* Use WSD only if the peer indicates support or it */
66 if (q->wsd && !wsd)
67 continue;
Dmitry Shmidt13ca8d82014-02-20 10:18:40 -080068 /* if the query is a broadcast query */
69 if (q->for_all_peers) {
70 /*
71 * check if there are any broadcast queries pending for
72 * this device
73 */
74 if (dev->sd_pending_bcast_queries <= 0)
75 return NULL;
76 /* query number that needs to be send to the device */
77 if (count == dev->sd_pending_bcast_queries - 1)
78 return q;
79 count++;
80 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070081 if (!q->for_all_peers &&
82 os_memcmp(q->peer, dev->info.p2p_device_addr, ETH_ALEN) ==
83 0)
84 return q;
85 }
86
87 return NULL;
88}
89
90
Dmitry Shmidt13ca8d82014-02-20 10:18:40 -080091static void p2p_decrease_sd_bc_queries(struct p2p_data *p2p, int query_number)
92{
93 struct p2p_device *dev;
94
95 p2p->num_p2p_sd_queries--;
96 dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
97 if (query_number <= dev->sd_pending_bcast_queries - 1) {
98 /*
99 * Query not yet sent to the device and it is to be
100 * removed, so update the pending count.
101 */
102 dev->sd_pending_bcast_queries--;
103 }
104 }
105}
106
107
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700108static int p2p_unlink_sd_query(struct p2p_data *p2p,
109 struct p2p_sd_query *query)
110{
111 struct p2p_sd_query *q, *prev;
Dmitry Shmidt13ca8d82014-02-20 10:18:40 -0800112 int query_number = 0;
113
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700114 q = p2p->sd_queries;
115 prev = NULL;
116 while (q) {
117 if (q == query) {
Dmitry Shmidt13ca8d82014-02-20 10:18:40 -0800118 /* If the query is a broadcast query, decrease one from
119 * all the devices */
120 if (query->for_all_peers)
121 p2p_decrease_sd_bc_queries(p2p, query_number);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700122 if (prev)
123 prev->next = q->next;
124 else
125 p2p->sd_queries = q->next;
126 if (p2p->sd_query == query)
127 p2p->sd_query = NULL;
128 return 1;
129 }
Dmitry Shmidt13ca8d82014-02-20 10:18:40 -0800130 if (q->for_all_peers)
131 query_number++;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700132 prev = q;
133 q = q->next;
134 }
135 return 0;
136}
137
138
139static void p2p_free_sd_query(struct p2p_sd_query *q)
140{
141 if (q == NULL)
142 return;
143 wpabuf_free(q->tlvs);
144 os_free(q);
145}
146
147
148void p2p_free_sd_queries(struct p2p_data *p2p)
149{
150 struct p2p_sd_query *q, *prev;
151 q = p2p->sd_queries;
152 p2p->sd_queries = NULL;
153 while (q) {
154 prev = q;
155 q = q->next;
156 p2p_free_sd_query(prev);
157 }
Dmitry Shmidt13ca8d82014-02-20 10:18:40 -0800158 p2p->num_p2p_sd_queries = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700159}
160
161
162static struct wpabuf * p2p_build_sd_query(u16 update_indic,
163 struct wpabuf *tlvs)
164{
165 struct wpabuf *buf;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800166 u8 *len_pos;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700167
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800168 buf = gas_anqp_build_initial_req(0, 100 + wpabuf_len(tlvs));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700169 if (buf == NULL)
170 return NULL;
171
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800172 /* ANQP Query Request Frame */
173 len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
Dmitry Shmidta38abf92014-03-06 13:38:44 -0800174 wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700175 wpabuf_put_le16(buf, update_indic); /* Service Update Indicator */
176 wpabuf_put_buf(buf, tlvs);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800177 gas_anqp_set_element_len(buf, len_pos);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700178
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800179 gas_anqp_set_len(buf);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700180
181 return buf;
182}
183
184
185static void p2p_send_gas_comeback_req(struct p2p_data *p2p, const u8 *dst,
186 u8 dialog_token, int freq)
187{
188 struct wpabuf *req;
189
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800190 req = gas_build_comeback_req(dialog_token);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700191 if (req == NULL)
192 return;
193
194 p2p->pending_action_state = P2P_NO_PENDING_ACTION;
195 if (p2p_send_action(p2p, freq, dst, p2p->cfg->dev_addr, dst,
196 wpabuf_head(req), wpabuf_len(req), 200) < 0)
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700197 p2p_dbg(p2p, "Failed to send Action frame");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700198
199 wpabuf_free(req);
200}
201
202
203static struct wpabuf * p2p_build_sd_response(u8 dialog_token, u16 status_code,
204 u16 comeback_delay,
205 u16 update_indic,
206 const struct wpabuf *tlvs)
207{
208 struct wpabuf *buf;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800209 u8 *len_pos;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700210
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800211 buf = gas_anqp_build_initial_resp(dialog_token, status_code,
212 comeback_delay,
213 100 + (tlvs ? wpabuf_len(tlvs) : 0));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700214 if (buf == NULL)
215 return NULL;
216
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700217 if (tlvs) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800218 /* ANQP Query Response Frame */
219 len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
Dmitry Shmidta38abf92014-03-06 13:38:44 -0800220 wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700221 /* Service Update Indicator */
222 wpabuf_put_le16(buf, update_indic);
223 wpabuf_put_buf(buf, tlvs);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800224 gas_anqp_set_element_len(buf, len_pos);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700225 }
226
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800227 gas_anqp_set_len(buf);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700228
229 return buf;
230}
231
232
233static struct wpabuf * p2p_build_gas_comeback_resp(u8 dialog_token,
234 u16 status_code,
235 u16 update_indic,
236 const u8 *data, size_t len,
237 u8 frag_id, u8 more,
238 u16 total_len)
239{
240 struct wpabuf *buf;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700241
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800242 buf = gas_anqp_build_comeback_resp(dialog_token, status_code, frag_id,
243 more, 0, 100 + len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700244 if (buf == NULL)
245 return NULL;
246
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700247 if (frag_id == 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800248 /* ANQP Query Response Frame */
249 wpabuf_put_le16(buf, ANQP_VENDOR_SPECIFIC); /* Info ID */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700250 wpabuf_put_le16(buf, 3 + 1 + 2 + total_len);
Dmitry Shmidta38abf92014-03-06 13:38:44 -0800251 wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700252 /* Service Update Indicator */
253 wpabuf_put_le16(buf, update_indic);
254 }
255
256 wpabuf_put_data(buf, data, len);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800257 gas_anqp_set_len(buf);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700258
259 return buf;
260}
261
262
263int p2p_start_sd(struct p2p_data *p2p, struct p2p_device *dev)
264{
265 struct wpabuf *req;
266 int ret = 0;
267 struct p2p_sd_query *query;
268 int freq;
269
270 freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
271 if (freq <= 0) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700272 p2p_dbg(p2p, "No Listen/Operating frequency known for the peer "
273 MACSTR " to send SD Request",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700274 MAC2STR(dev->info.p2p_device_addr));
275 return -1;
276 }
277
278 query = p2p_pending_sd_req(p2p, dev);
279 if (query == NULL)
280 return -1;
281
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700282 p2p_dbg(p2p, "Start Service Discovery with " MACSTR,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700283 MAC2STR(dev->info.p2p_device_addr));
284
285 req = p2p_build_sd_query(p2p->srv_update_indic, query->tlvs);
286 if (req == NULL)
287 return -1;
288
289 p2p->sd_peer = dev;
290 p2p->sd_query = query;
291 p2p->pending_action_state = P2P_PENDING_SD;
292
293 if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
294 p2p->cfg->dev_addr, dev->info.p2p_device_addr,
295 wpabuf_head(req), wpabuf_len(req), 5000) < 0) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700296 p2p_dbg(p2p, "Failed to send Action frame");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700297 ret = -1;
298 }
299
Dmitry Shmidt13ca8d82014-02-20 10:18:40 -0800300 /* Update the pending broadcast SD query count for this device */
301 dev->sd_pending_bcast_queries--;
302
303 /*
304 * If there are no pending broadcast queries for this device, mark it as
305 * done (-1).
306 */
307 if (dev->sd_pending_bcast_queries == 0)
308 dev->sd_pending_bcast_queries = -1;
309
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700310 wpabuf_free(req);
311
312 return ret;
313}
314
315
316void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa,
317 const u8 *data, size_t len, int rx_freq)
318{
319 const u8 *pos = data;
320 const u8 *end = data + len;
321 const u8 *next;
322 u8 dialog_token;
323 u16 slen;
324 int freq;
325 u16 update_indic;
326
327
328 if (p2p->cfg->sd_request == NULL)
329 return;
330
331 if (rx_freq > 0)
332 freq = rx_freq;
333 else
Dmitry Shmidt4b060592013-04-29 16:42:49 -0700334 freq = p2p_channel_to_freq(p2p->cfg->reg_class,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700335 p2p->cfg->channel);
336 if (freq < 0)
337 return;
338
339 if (len < 1 + 2)
340 return;
341
342 dialog_token = *pos++;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700343 p2p_dbg(p2p, "GAS Initial Request from " MACSTR
344 " (dialog token %u, freq %d)",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700345 MAC2STR(sa), dialog_token, rx_freq);
346
347 if (*pos != WLAN_EID_ADV_PROTO) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700348 p2p_dbg(p2p, "Unexpected IE in GAS Initial Request: %u", *pos);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700349 return;
350 }
351 pos++;
352
353 slen = *pos++;
354 next = pos + slen;
355 if (next > end || slen < 2) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700356 p2p_dbg(p2p, "Invalid IE in GAS Initial Request");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700357 return;
358 }
359 pos++; /* skip QueryRespLenLimit and PAME-BI */
360
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800361 if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700362 p2p_dbg(p2p, "Unsupported GAS advertisement protocol id %u",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700363 *pos);
364 return;
365 }
366
367 pos = next;
368 /* Query Request */
369 if (pos + 2 > end)
370 return;
371 slen = WPA_GET_LE16(pos);
372 pos += 2;
373 if (pos + slen > end)
374 return;
375 end = pos + slen;
376
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800377 /* ANQP Query Request */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700378 if (pos + 4 > end)
379 return;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800380 if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700381 p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700382 return;
383 }
384 pos += 2;
385
386 slen = WPA_GET_LE16(pos);
387 pos += 2;
388 if (pos + slen > end || slen < 3 + 1) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700389 p2p_dbg(p2p, "Invalid ANQP Query Request length");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700390 return;
391 }
392
Dmitry Shmidta38abf92014-03-06 13:38:44 -0800393 if (WPA_GET_BE32(pos) != P2P_IE_VENDOR_TYPE) {
394 p2p_dbg(p2p, "Unsupported ANQP vendor OUI-type %08x",
395 WPA_GET_BE32(pos));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700396 return;
397 }
Dmitry Shmidta38abf92014-03-06 13:38:44 -0800398 pos += 4;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700399
400 if (pos + 2 > end)
401 return;
402 update_indic = WPA_GET_LE16(pos);
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700403 p2p_dbg(p2p, "Service Update Indicator: %u", update_indic);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700404 pos += 2;
405
406 p2p->cfg->sd_request(p2p->cfg->cb_ctx, freq, sa, dialog_token,
407 update_indic, pos, end - pos);
408 /* the response will be indicated with a call to p2p_sd_response() */
409}
410
411
412void p2p_sd_response(struct p2p_data *p2p, int freq, const u8 *dst,
413 u8 dialog_token, const struct wpabuf *resp_tlvs)
414{
415 struct wpabuf *resp;
416
417 /* TODO: fix the length limit to match with the maximum frame length */
418 if (wpabuf_len(resp_tlvs) > 1400) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700419 p2p_dbg(p2p, "SD response long enough to require fragmentation");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700420 if (p2p->sd_resp) {
421 /*
422 * TODO: Could consider storing the fragmented response
423 * separately for each peer to avoid having to drop old
424 * one if there is more than one pending SD query.
425 * Though, that would eat more memory, so there are
426 * also benefits to just using a single buffer.
427 */
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700428 p2p_dbg(p2p, "Drop previous SD response");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700429 wpabuf_free(p2p->sd_resp);
430 }
Dmitry Shmidt04949592012-07-19 12:16:46 -0700431 p2p->sd_resp = wpabuf_dup(resp_tlvs);
432 if (p2p->sd_resp == NULL) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700433 p2p_err(p2p, "Failed to allocate SD response fragmentation area");
Dmitry Shmidt04949592012-07-19 12:16:46 -0700434 return;
435 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700436 os_memcpy(p2p->sd_resp_addr, dst, ETH_ALEN);
437 p2p->sd_resp_dialog_token = dialog_token;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700438 p2p->sd_resp_pos = 0;
439 p2p->sd_frag_id = 0;
440 resp = p2p_build_sd_response(dialog_token, WLAN_STATUS_SUCCESS,
441 1, p2p->srv_update_indic, NULL);
442 } else {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700443 p2p_dbg(p2p, "SD response fits in initial response");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700444 resp = p2p_build_sd_response(dialog_token,
445 WLAN_STATUS_SUCCESS, 0,
446 p2p->srv_update_indic, resp_tlvs);
447 }
448 if (resp == NULL)
449 return;
450
451 p2p->pending_action_state = P2P_NO_PENDING_ACTION;
452 if (p2p_send_action(p2p, freq, dst, p2p->cfg->dev_addr,
453 p2p->cfg->dev_addr,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700454 wpabuf_head(resp), wpabuf_len(resp), 200) < 0)
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700455 p2p_dbg(p2p, "Failed to send Action frame");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700456
457 wpabuf_free(resp);
458}
459
460
461void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa,
462 const u8 *data, size_t len, int rx_freq)
463{
464 const u8 *pos = data;
465 const u8 *end = data + len;
466 const u8 *next;
467 u8 dialog_token;
468 u16 status_code;
469 u16 comeback_delay;
470 u16 slen;
471 u16 update_indic;
472
473 if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL ||
474 os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700475 p2p_dbg(p2p, "Ignore unexpected GAS Initial Response from "
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700476 MACSTR, MAC2STR(sa));
477 return;
478 }
479 p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
480 p2p_clear_timeout(p2p);
481
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700482 p2p_dbg(p2p, "Received GAS Initial Response from " MACSTR " (len=%d)",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700483 MAC2STR(sa), (int) len);
484
485 if (len < 5 + 2) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700486 p2p_dbg(p2p, "Too short GAS Initial Response frame");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700487 return;
488 }
489
490 dialog_token = *pos++;
491 /* TODO: check dialog_token match */
492 status_code = WPA_GET_LE16(pos);
493 pos += 2;
494 comeback_delay = WPA_GET_LE16(pos);
495 pos += 2;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700496 p2p_dbg(p2p, "dialog_token=%u status_code=%u comeback_delay=%u",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700497 dialog_token, status_code, comeback_delay);
498 if (status_code) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700499 p2p_dbg(p2p, "Service Discovery failed: status code %u",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700500 status_code);
501 return;
502 }
503
504 if (*pos != WLAN_EID_ADV_PROTO) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700505 p2p_dbg(p2p, "Unexpected IE in GAS Initial Response: %u", *pos);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700506 return;
507 }
508 pos++;
509
510 slen = *pos++;
511 next = pos + slen;
512 if (next > end || slen < 2) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700513 p2p_dbg(p2p, "Invalid IE in GAS Initial Response");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700514 return;
515 }
516 pos++; /* skip QueryRespLenLimit and PAME-BI */
517
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800518 if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700519 p2p_dbg(p2p, "Unsupported GAS advertisement protocol id %u",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700520 *pos);
521 return;
522 }
523
524 pos = next;
525 /* Query Response */
526 if (pos + 2 > end) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700527 p2p_dbg(p2p, "Too short Query Response");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700528 return;
529 }
530 slen = WPA_GET_LE16(pos);
531 pos += 2;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700532 p2p_dbg(p2p, "Query Response Length: %d", slen);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700533 if (pos + slen > end) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700534 p2p_dbg(p2p, "Not enough Query Response data");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700535 return;
536 }
537 end = pos + slen;
538
539 if (comeback_delay) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700540 p2p_dbg(p2p, "Fragmented response - request fragments");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700541 if (p2p->sd_rx_resp) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700542 p2p_dbg(p2p, "Drop old SD reassembly buffer");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700543 wpabuf_free(p2p->sd_rx_resp);
544 p2p->sd_rx_resp = NULL;
545 }
546 p2p_send_gas_comeback_req(p2p, sa, dialog_token, rx_freq);
547 return;
548 }
549
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800550 /* ANQP Query Response */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700551 if (pos + 4 > end)
552 return;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800553 if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700554 p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700555 return;
556 }
557 pos += 2;
558
559 slen = WPA_GET_LE16(pos);
560 pos += 2;
561 if (pos + slen > end || slen < 3 + 1) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700562 p2p_dbg(p2p, "Invalid ANQP Query Response length");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700563 return;
564 }
565
Dmitry Shmidta38abf92014-03-06 13:38:44 -0800566 if (WPA_GET_BE32(pos) != P2P_IE_VENDOR_TYPE) {
567 p2p_dbg(p2p, "Unsupported ANQP vendor OUI-type %08x",
568 WPA_GET_BE32(pos));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700569 return;
570 }
Dmitry Shmidta38abf92014-03-06 13:38:44 -0800571 pos += 4;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700572
573 if (pos + 2 > end)
574 return;
575 update_indic = WPA_GET_LE16(pos);
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700576 p2p_dbg(p2p, "Service Update Indicator: %u", update_indic);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700577 pos += 2;
578
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700579 p2p->sd_peer = NULL;
580
581 if (p2p->sd_query) {
582 if (!p2p->sd_query->for_all_peers) {
583 struct p2p_sd_query *q;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700584 p2p_dbg(p2p, "Remove completed SD query %p",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700585 p2p->sd_query);
586 q = p2p->sd_query;
587 p2p_unlink_sd_query(p2p, p2p->sd_query);
588 p2p_free_sd_query(q);
589 }
590 p2p->sd_query = NULL;
591 }
592
593 if (p2p->cfg->sd_response)
594 p2p->cfg->sd_response(p2p->cfg->cb_ctx, sa, update_indic,
595 pos, end - pos);
596 p2p_continue_find(p2p);
597}
598
599
600void p2p_rx_gas_comeback_req(struct p2p_data *p2p, const u8 *sa,
601 const u8 *data, size_t len, int rx_freq)
602{
603 struct wpabuf *resp;
604 u8 dialog_token;
605 size_t frag_len;
606 int more = 0;
607
608 wpa_hexdump(MSG_DEBUG, "P2P: RX GAS Comeback Request", data, len);
609 if (len < 1)
610 return;
611 dialog_token = *data;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700612 p2p_dbg(p2p, "Dialog Token: %u", dialog_token);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700613 if (dialog_token != p2p->sd_resp_dialog_token) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700614 p2p_dbg(p2p, "No pending SD response fragment for dialog token %u",
615 dialog_token);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700616 return;
617 }
618
619 if (p2p->sd_resp == NULL) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700620 p2p_dbg(p2p, "No pending SD response fragment available");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700621 return;
622 }
623 if (os_memcmp(sa, p2p->sd_resp_addr, ETH_ALEN) != 0) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700624 p2p_dbg(p2p, "No pending SD response fragment for " MACSTR,
625 MAC2STR(sa));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700626 return;
627 }
628
629 frag_len = wpabuf_len(p2p->sd_resp) - p2p->sd_resp_pos;
630 if (frag_len > 1400) {
631 frag_len = 1400;
632 more = 1;
633 }
634 resp = p2p_build_gas_comeback_resp(dialog_token, WLAN_STATUS_SUCCESS,
635 p2p->srv_update_indic,
636 wpabuf_head_u8(p2p->sd_resp) +
637 p2p->sd_resp_pos, frag_len,
638 p2p->sd_frag_id, more,
639 wpabuf_len(p2p->sd_resp));
640 if (resp == NULL)
641 return;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700642 p2p_dbg(p2p, "Send GAS Comeback Response (frag_id %d more=%d frag_len=%d)",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700643 p2p->sd_frag_id, more, (int) frag_len);
644 p2p->sd_frag_id++;
645 p2p->sd_resp_pos += frag_len;
646
647 if (more) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700648 p2p_dbg(p2p, "%d more bytes remain to be sent",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700649 (int) (wpabuf_len(p2p->sd_resp) - p2p->sd_resp_pos));
650 } else {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700651 p2p_dbg(p2p, "All fragments of SD response sent");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700652 wpabuf_free(p2p->sd_resp);
653 p2p->sd_resp = NULL;
654 }
655
656 p2p->pending_action_state = P2P_NO_PENDING_ACTION;
657 if (p2p_send_action(p2p, rx_freq, sa, p2p->cfg->dev_addr,
658 p2p->cfg->dev_addr,
659 wpabuf_head(resp), wpabuf_len(resp), 200) < 0)
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700660 p2p_dbg(p2p, "Failed to send Action frame");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700661
662 wpabuf_free(resp);
663}
664
665
666void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
667 const u8 *data, size_t len, int rx_freq)
668{
669 const u8 *pos = data;
670 const u8 *end = data + len;
671 const u8 *next;
672 u8 dialog_token;
673 u16 status_code;
674 u8 frag_id;
675 u8 more_frags;
676 u16 comeback_delay;
677 u16 slen;
678
679 wpa_hexdump(MSG_DEBUG, "P2P: RX GAS Comeback Response", data, len);
680
Dmitry Shmidt04949592012-07-19 12:16:46 -0700681 if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL ||
Dmitry Shmidt04949592012-07-19 12:16:46 -0700682 os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700683 p2p_dbg(p2p, "Ignore unexpected GAS Comeback Response from "
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700684 MACSTR, MAC2STR(sa));
685 return;
686 }
687 p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
688 p2p_clear_timeout(p2p);
689
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700690 p2p_dbg(p2p, "Received GAS Comeback Response from " MACSTR " (len=%d)",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700691 MAC2STR(sa), (int) len);
692
693 if (len < 6 + 2) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700694 p2p_dbg(p2p, "Too short GAS Comeback Response frame");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700695 return;
696 }
697
698 dialog_token = *pos++;
699 /* TODO: check dialog_token match */
700 status_code = WPA_GET_LE16(pos);
701 pos += 2;
702 frag_id = *pos & 0x7f;
703 more_frags = (*pos & 0x80) >> 7;
704 pos++;
705 comeback_delay = WPA_GET_LE16(pos);
706 pos += 2;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700707 p2p_dbg(p2p, "dialog_token=%u status_code=%u frag_id=%d more_frags=%d "
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700708 "comeback_delay=%u",
709 dialog_token, status_code, frag_id, more_frags,
710 comeback_delay);
711 /* TODO: check frag_id match */
712 if (status_code) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700713 p2p_dbg(p2p, "Service Discovery failed: status code %u",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700714 status_code);
715 return;
716 }
717
718 if (*pos != WLAN_EID_ADV_PROTO) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700719 p2p_dbg(p2p, "Unexpected IE in GAS Comeback Response: %u",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700720 *pos);
721 return;
722 }
723 pos++;
724
725 slen = *pos++;
726 next = pos + slen;
727 if (next > end || slen < 2) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700728 p2p_dbg(p2p, "Invalid IE in GAS Comeback Response");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700729 return;
730 }
731 pos++; /* skip QueryRespLenLimit and PAME-BI */
732
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800733 if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700734 p2p_dbg(p2p, "Unsupported GAS advertisement protocol id %u",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700735 *pos);
736 return;
737 }
738
739 pos = next;
740 /* Query Response */
741 if (pos + 2 > end) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700742 p2p_dbg(p2p, "Too short Query Response");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700743 return;
744 }
745 slen = WPA_GET_LE16(pos);
746 pos += 2;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700747 p2p_dbg(p2p, "Query Response Length: %d", slen);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700748 if (pos + slen > end) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700749 p2p_dbg(p2p, "Not enough Query Response data");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700750 return;
751 }
752 if (slen == 0) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700753 p2p_dbg(p2p, "No Query Response data");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700754 return;
755 }
756 end = pos + slen;
757
758 if (p2p->sd_rx_resp) {
759 /*
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800760 * ANQP header is only included in the first fragment; rest of
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700761 * the fragments start with continue TLVs.
762 */
763 goto skip_nqp_header;
764 }
765
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800766 /* ANQP Query Response */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700767 if (pos + 4 > end)
768 return;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800769 if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700770 p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700771 return;
772 }
773 pos += 2;
774
775 slen = WPA_GET_LE16(pos);
776 pos += 2;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700777 p2p_dbg(p2p, "ANQP Query Response length: %u", slen);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700778 if (slen < 3 + 1) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700779 p2p_dbg(p2p, "Invalid ANQP Query Response length");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700780 return;
781 }
782 if (pos + 4 > end)
783 return;
784
Dmitry Shmidta38abf92014-03-06 13:38:44 -0800785 if (WPA_GET_BE32(pos) != P2P_IE_VENDOR_TYPE) {
786 p2p_dbg(p2p, "Unsupported ANQP vendor OUI-type %08x",
787 WPA_GET_BE32(pos));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700788 return;
789 }
Dmitry Shmidta38abf92014-03-06 13:38:44 -0800790 pos += 4;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700791
792 if (pos + 2 > end)
793 return;
794 p2p->sd_rx_update_indic = WPA_GET_LE16(pos);
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700795 p2p_dbg(p2p, "Service Update Indicator: %u", p2p->sd_rx_update_indic);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700796 pos += 2;
797
798skip_nqp_header:
799 if (wpabuf_resize(&p2p->sd_rx_resp, end - pos) < 0)
800 return;
801 wpabuf_put_data(p2p->sd_rx_resp, pos, end - pos);
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700802 p2p_dbg(p2p, "Current SD reassembly buffer length: %u",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700803 (unsigned int) wpabuf_len(p2p->sd_rx_resp));
804
805 if (more_frags) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700806 p2p_dbg(p2p, "More fragments remains");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700807 /* TODO: what would be a good size limit? */
808 if (wpabuf_len(p2p->sd_rx_resp) > 64000) {
809 wpabuf_free(p2p->sd_rx_resp);
810 p2p->sd_rx_resp = NULL;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700811 p2p_dbg(p2p, "Too long SD response - drop it");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700812 return;
813 }
814 p2p_send_gas_comeback_req(p2p, sa, dialog_token, rx_freq);
815 return;
816 }
817
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700818 p2p->sd_peer = NULL;
819
820 if (p2p->sd_query) {
821 if (!p2p->sd_query->for_all_peers) {
822 struct p2p_sd_query *q;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700823 p2p_dbg(p2p, "Remove completed SD query %p",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700824 p2p->sd_query);
825 q = p2p->sd_query;
826 p2p_unlink_sd_query(p2p, p2p->sd_query);
827 p2p_free_sd_query(q);
828 }
829 p2p->sd_query = NULL;
830 }
831
832 if (p2p->cfg->sd_response)
833 p2p->cfg->sd_response(p2p->cfg->cb_ctx, sa,
834 p2p->sd_rx_update_indic,
835 wpabuf_head(p2p->sd_rx_resp),
836 wpabuf_len(p2p->sd_rx_resp));
837 wpabuf_free(p2p->sd_rx_resp);
838 p2p->sd_rx_resp = NULL;
839
840 p2p_continue_find(p2p);
841}
842
843
844void * p2p_sd_request(struct p2p_data *p2p, const u8 *dst,
845 const struct wpabuf *tlvs)
846{
847 struct p2p_sd_query *q;
848
849 q = os_zalloc(sizeof(*q));
850 if (q == NULL)
851 return NULL;
852
853 if (dst)
854 os_memcpy(q->peer, dst, ETH_ALEN);
855 else
856 q->for_all_peers = 1;
857
858 q->tlvs = wpabuf_dup(tlvs);
859 if (q->tlvs == NULL) {
860 p2p_free_sd_query(q);
861 return NULL;
862 }
863
864 q->next = p2p->sd_queries;
865 p2p->sd_queries = q;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700866 p2p_dbg(p2p, "Added SD Query %p", q);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700867
Irfan Sheriff96161872012-04-11 18:07:13 -0700868 if (dst == NULL) {
869 struct p2p_device *dev;
Dmitry Shmidt13ca8d82014-02-20 10:18:40 -0800870
871 p2p->num_p2p_sd_queries++;
872
873 /* Update all the devices for the newly added broadcast query */
874 dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
875 if (dev->sd_pending_bcast_queries <= 0)
876 dev->sd_pending_bcast_queries = 1;
877 else
878 dev->sd_pending_bcast_queries++;
879 }
Irfan Sheriff96161872012-04-11 18:07:13 -0700880 }
881
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700882 return q;
883}
884
885
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700886#ifdef CONFIG_WIFI_DISPLAY
887void * p2p_sd_request_wfd(struct p2p_data *p2p, const u8 *dst,
888 const struct wpabuf *tlvs)
889{
890 struct p2p_sd_query *q;
891 q = p2p_sd_request(p2p, dst, tlvs);
892 if (q)
893 q->wsd = 1;
894 return q;
895}
896#endif /* CONFIG_WIFI_DISPLAY */
897
898
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700899void p2p_sd_service_update(struct p2p_data *p2p)
900{
901 p2p->srv_update_indic++;
902}
903
904
905int p2p_sd_cancel_request(struct p2p_data *p2p, void *req)
906{
907 if (p2p_unlink_sd_query(p2p, req)) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700908 p2p_dbg(p2p, "Cancel pending SD query %p", req);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700909 p2p_free_sd_query(req);
910 return 0;
911 }
912 return -1;
913}