2 * Wi-Fi Direct - P2P service discovery
3 * Copyright (c) 2009, Atheros Communications
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
18 #include "common/ieee802_11_defs.h"
23 struct p2p_sd_query
* p2p_pending_sd_req(struct p2p_data
*p2p
,
24 struct p2p_device
*dev
)
26 struct p2p_sd_query
*q
;
28 if (!(dev
->dev_capab
& P2P_DEV_CAPAB_SERVICE_DISCOVERY
))
29 return 0; /* peer does not support SD */
31 for (q
= p2p
->sd_queries
; q
; q
= q
->next
) {
32 if (q
->for_all_peers
&& !(dev
->flags
& P2P_DEV_SD_INFO
))
34 if (!q
->for_all_peers
&&
35 os_memcmp(q
->peer
, dev
->p2p_device_addr
, ETH_ALEN
) == 0)
43 static int p2p_unlink_sd_query(struct p2p_data
*p2p
,
44 struct p2p_sd_query
*query
)
46 struct p2p_sd_query
*q
, *prev
;
54 p2p
->sd_queries
= q
->next
;
55 if (p2p
->sd_query
== query
)
66 static void p2p_free_sd_query(struct p2p_sd_query
*q
)
75 void p2p_free_sd_queries(struct p2p_data
*p2p
)
77 struct p2p_sd_query
*q
, *prev
;
79 p2p
->sd_queries
= NULL
;
83 p2p_free_sd_query(prev
);
88 static struct wpabuf
* p2p_build_sd_query(u16 update_indic
,
92 u8
*len_pos
, *len_pos2
;
94 buf
= wpabuf_alloc(1000 + wpabuf_len(tlvs
));
98 wpabuf_put_u8(buf
, WLAN_ACTION_PUBLIC
);
99 wpabuf_put_u8(buf
, WLAN_PA_GAS_INITIAL_REQ
);
100 wpabuf_put_u8(buf
, 0); /* Dialog Token */
102 /* Advertisement Protocol IE */
103 wpabuf_put_u8(buf
, WLAN_EID_ADV_PROTO
);
104 wpabuf_put_u8(buf
, 2); /* Length */
105 wpabuf_put_u8(buf
, 0); /* QueryRespLenLimit | PAME-BI */
106 wpabuf_put_u8(buf
, NATIVE_QUERY_PROTOCOL
); /* Advertisement Protocol */
109 len_pos
= wpabuf_put(buf
, 2); /* Length (to be filled) */
111 /* NQP Query Request Frame */
112 wpabuf_put_le16(buf
, NQP_VENDOR_SPECIFIC
); /* Info ID */
113 len_pos2
= wpabuf_put(buf
, 2); /* Length (to be filled) */
114 wpabuf_put_be24(buf
, OUI_WFA
);
115 wpabuf_put_u8(buf
, P2P_OUI_TYPE
);
116 wpabuf_put_le16(buf
, update_indic
); /* Service Update Indicator */
117 wpabuf_put_buf(buf
, tlvs
);
119 WPA_PUT_LE16(len_pos2
, (u8
*) wpabuf_put(buf
, 0) - len_pos2
- 2);
120 WPA_PUT_LE16(len_pos
, (u8
*) wpabuf_put(buf
, 0) - len_pos
- 2);
126 static struct wpabuf
* p2p_build_sd_response(u8 dialog_token
, u16 status_code
,
128 const struct wpabuf
*tlvs
)
131 u8
*len_pos
, *len_pos2
;
133 buf
= wpabuf_alloc(1000 + wpabuf_len(tlvs
));
137 wpabuf_put_u8(buf
, WLAN_ACTION_PUBLIC
);
138 wpabuf_put_u8(buf
, WLAN_PA_GAS_INITIAL_RESP
);
139 wpabuf_put_u8(buf
, dialog_token
);
140 wpabuf_put_le16(buf
, status_code
);
141 wpabuf_put_le16(buf
, 0); /* GAS Comeback Delay */
143 /* Advertisement Protocol IE */
144 wpabuf_put_u8(buf
, WLAN_EID_ADV_PROTO
);
145 wpabuf_put_u8(buf
, 2); /* Length */
146 wpabuf_put_u8(buf
, 0x7f); /* QueryRespLenLimit | PAME-BI */
147 wpabuf_put_u8(buf
, NATIVE_QUERY_PROTOCOL
); /* Advertisement Protocol */
150 len_pos
= wpabuf_put(buf
, 2); /* Length (to be filled) */
152 /* NQP Query Response Frame */
153 wpabuf_put_le16(buf
, NQP_VENDOR_SPECIFIC
); /* Info ID */
154 len_pos2
= wpabuf_put(buf
, 2); /* Length (to be filled) */
155 wpabuf_put_be24(buf
, OUI_WFA
);
156 wpabuf_put_u8(buf
, P2P_OUI_TYPE
);
157 wpabuf_put_le16(buf
, update_indic
); /* Service Update Indicator */
158 wpabuf_put_buf(buf
, tlvs
);
160 WPA_PUT_LE16(len_pos2
, (u8
*) wpabuf_put(buf
, 0) - len_pos2
- 2);
161 WPA_PUT_LE16(len_pos
, (u8
*) wpabuf_put(buf
, 0) - len_pos
- 2);
167 int p2p_start_sd(struct p2p_data
*p2p
, struct p2p_device
*dev
)
171 struct p2p_sd_query
*query
;
174 freq
= dev
->listen_freq
> 0 ? dev
->listen_freq
: dev
->oper_freq
;
176 wpa_msg(p2p
->cfg
->msg_ctx
, MSG_DEBUG
,
177 "P2P: No Listen/Operating frequency known for the "
178 "peer " MACSTR
" to send SD Request",
179 MAC2STR(dev
->p2p_device_addr
));
183 query
= p2p_pending_sd_req(p2p
, dev
);
187 wpa_msg(p2p
->cfg
->msg_ctx
, MSG_DEBUG
,
188 "P2P: Start Service Discovery with " MACSTR
,
189 MAC2STR(dev
->p2p_device_addr
));
191 req
= p2p_build_sd_query(p2p
->srv_update_indic
, query
->tlvs
);
196 p2p
->sd_query
= query
;
197 p2p
->pending_action_state
= P2P_PENDING_SD
;
199 if (p2p
->cfg
->send_action(p2p
->cfg
->cb_ctx
, freq
,
200 dev
->p2p_device_addr
, p2p
->cfg
->dev_addr
,
201 dev
->p2p_device_addr
,
202 wpabuf_head(req
), wpabuf_len(req
), 5000) < 0)
204 wpa_msg(p2p
->cfg
->msg_ctx
, MSG_DEBUG
,
205 "P2P: Failed to send Action frame");
215 void p2p_rx_gas_initial_req(struct p2p_data
*p2p
, const u8
*sa
,
216 const u8
*data
, size_t len
, int rx_freq
)
218 const u8
*pos
= data
;
219 const u8
*end
= data
+ len
;
227 if (p2p
->cfg
->sd_request
== NULL
)
233 freq
= p2p_channel_to_freq(p2p
->cfg
->country
,
242 dialog_token
= *pos
++;
243 wpa_msg(p2p
->cfg
->msg_ctx
, MSG_DEBUG
,
244 "P2P: GAS Initial Request from " MACSTR
" (dialog token %u, "
246 MAC2STR(sa
), dialog_token
, rx_freq
);
248 if (*pos
!= WLAN_EID_ADV_PROTO
) {
249 wpa_msg(p2p
->cfg
->msg_ctx
, MSG_DEBUG
,
250 "P2P: Unexpected IE in GAS Initial Request: %u", *pos
);
257 if (next
> end
|| slen
< 2) {
258 wpa_msg(p2p
->cfg
->msg_ctx
, MSG_DEBUG
,
259 "P2P: Invalid IE in GAS Initial Request");
262 pos
++; /* skip QueryRespLenLimit and PAME-BI */
264 if (*pos
!= NATIVE_QUERY_PROTOCOL
) {
265 wpa_msg(p2p
->cfg
->msg_ctx
, MSG_DEBUG
,
266 "P2P: Unsupported GAS advertisement protocol id %u",
275 slen
= WPA_GET_LE16(pos
);
277 if (pos
+ slen
> end
)
281 /* NQP Query Request */
284 if (WPA_GET_LE16(pos
) != NQP_VENDOR_SPECIFIC
) {
285 wpa_msg(p2p
->cfg
->msg_ctx
, MSG_DEBUG
,
286 "P2P: Unsupported NQP Info ID %u", WPA_GET_LE16(pos
));
291 slen
= WPA_GET_LE16(pos
);
293 if (pos
+ slen
> end
|| slen
< 3 + 1) {
294 wpa_msg(p2p
->cfg
->msg_ctx
, MSG_DEBUG
,
295 "P2P: Invalid NQP Query Request length");
299 if (WPA_GET_BE24(pos
) != OUI_WFA
) {
300 wpa_msg(p2p
->cfg
->msg_ctx
, MSG_DEBUG
,
301 "P2P: Unsupported NQP OUI %06x", WPA_GET_BE24(pos
));
306 if (*pos
!= P2P_OUI_TYPE
) {
307 wpa_msg(p2p
->cfg
->msg_ctx
, MSG_DEBUG
,
308 "P2P: Unsupported NQP vendor type %u", *pos
);
315 update_indic
= WPA_GET_LE16(pos
);
316 wpa_msg(p2p
->cfg
->msg_ctx
, MSG_DEBUG
,
317 "P2P: Service Update Indicator: %u", update_indic
);
320 p2p
->cfg
->sd_request(p2p
->cfg
->cb_ctx
, freq
, sa
, dialog_token
,
321 update_indic
, pos
, end
- pos
);
322 /* the response will be indicated with a call to p2p_sd_response() */
326 void p2p_sd_response(struct p2p_data
*p2p
, int freq
, const u8
*dst
,
327 u8 dialog_token
, const struct wpabuf
*resp_tlvs
)
330 resp
= p2p_build_sd_response(dialog_token
, WLAN_STATUS_SUCCESS
,
331 p2p
->srv_update_indic
, resp_tlvs
);
335 p2p
->pending_action_state
= P2P_NO_PENDING_ACTION
;
336 if (p2p
->cfg
->send_action(p2p
->cfg
->cb_ctx
, freq
,
337 dst
, p2p
->cfg
->dev_addr
, p2p
->cfg
->dev_addr
,
338 wpabuf_head(resp
), wpabuf_len(resp
), 200) <
340 wpa_msg(p2p
->cfg
->msg_ctx
, MSG_DEBUG
,
341 "P2P: Failed to send Action frame");
347 void p2p_rx_gas_initial_resp(struct p2p_data
*p2p
, const u8
*sa
,
348 const u8
*data
, size_t len
)
350 const u8
*pos
= data
;
351 const u8
*end
= data
+ len
;
359 if (p2p
->state
!= P2P_SD_DURING_FIND
|| p2p
->sd_peer
== NULL
||
360 os_memcmp(sa
, p2p
->sd_peer
->p2p_device_addr
, ETH_ALEN
) != 0) {
361 wpa_msg(p2p
->cfg
->msg_ctx
, MSG_DEBUG
,
362 "P2P: Ignore unexpected GAS Initial Response from "
363 MACSTR
, MAC2STR(sa
));
366 p2p
->cfg
->send_action_done(p2p
->cfg
->cb_ctx
);
367 p2p_clear_timeout(p2p
);
369 wpa_msg(p2p
->cfg
->msg_ctx
, MSG_DEBUG
,
370 "P2P: Received GAS Initial Response from " MACSTR
,
376 dialog_token
= *pos
++;
377 /* TODO: check dialog_token match */
378 status_code
= WPA_GET_LE16(pos
);
380 comeback_delay
= WPA_GET_LE16(pos
);
382 wpa_msg(p2p
->cfg
->msg_ctx
, MSG_DEBUG
,
383 "P2P: dialog_token=%u status_code=%u comeback_delay=%u",
384 dialog_token
, status_code
, comeback_delay
);
386 if (*pos
!= WLAN_EID_ADV_PROTO
) {
387 wpa_msg(p2p
->cfg
->msg_ctx
, MSG_DEBUG
,
388 "P2P: Unexpected IE in GAS Initial Response: %u",
396 if (next
> end
|| slen
< 2) {
397 wpa_msg(p2p
->cfg
->msg_ctx
, MSG_DEBUG
,
398 "P2P: Invalid IE in GAS Initial Response");
401 pos
++; /* skip QueryRespLenLimit and PAME-BI */
403 if (*pos
!= NATIVE_QUERY_PROTOCOL
) {
404 wpa_msg(p2p
->cfg
->msg_ctx
, MSG_DEBUG
,
405 "P2P: Unsupported GAS advertisement protocol id %u",
414 slen
= WPA_GET_LE16(pos
);
416 if (pos
+ slen
> end
)
420 /* NQP Query Response */
423 if (WPA_GET_LE16(pos
) != NQP_VENDOR_SPECIFIC
) {
424 wpa_msg(p2p
->cfg
->msg_ctx
, MSG_DEBUG
,
425 "P2P: Unsupported NQP Info ID %u", WPA_GET_LE16(pos
));
430 slen
= WPA_GET_LE16(pos
);
432 if (pos
+ slen
> end
|| slen
< 3 + 1) {
433 wpa_msg(p2p
->cfg
->msg_ctx
, MSG_DEBUG
,
434 "P2P: Invalid NQP Query Response length");
438 if (WPA_GET_BE24(pos
) != OUI_WFA
) {
439 wpa_msg(p2p
->cfg
->msg_ctx
, MSG_DEBUG
,
440 "P2P: Unsupported NQP OUI %06x", WPA_GET_BE24(pos
));
445 if (*pos
!= P2P_OUI_TYPE
) {
446 wpa_msg(p2p
->cfg
->msg_ctx
, MSG_DEBUG
,
447 "P2P: Unsupported NQP vendor type %u", *pos
);
454 update_indic
= WPA_GET_LE16(pos
);
455 wpa_msg(p2p
->cfg
->msg_ctx
, MSG_DEBUG
,
456 "P2P: Service Update Indicator: %u", update_indic
);
459 p2p
->sd_peer
->flags
|= P2P_DEV_SD_INFO
;
460 p2p
->sd_peer
->flags
&= ~P2P_DEV_SD_SCHEDULE
;
464 if (!p2p
->sd_query
->for_all_peers
) {
465 struct p2p_sd_query
*q
;
466 wpa_msg(p2p
->cfg
->msg_ctx
, MSG_DEBUG
,
467 "P2P: Remove completed SD query %p",
470 p2p_unlink_sd_query(p2p
, p2p
->sd_query
);
471 p2p_free_sd_query(q
);
473 p2p
->sd_query
= NULL
;
476 if (p2p
->cfg
->sd_response
)
477 p2p
->cfg
->sd_response(p2p
->cfg
->cb_ctx
, sa
, update_indic
,
479 p2p_continue_find(p2p
);
483 void * p2p_sd_request(struct p2p_data
*p2p
, const u8
*dst
,
484 const struct wpabuf
*tlvs
)
486 struct p2p_sd_query
*q
;
488 q
= os_zalloc(sizeof(*q
));
493 os_memcpy(q
->peer
, dst
, ETH_ALEN
);
495 q
->for_all_peers
= 1;
497 q
->tlvs
= wpabuf_dup(tlvs
);
498 if (q
->tlvs
== NULL
) {
499 p2p_free_sd_query(q
);
503 q
->next
= p2p
->sd_queries
;
505 wpa_msg(p2p
->cfg
->msg_ctx
, MSG_DEBUG
, "P2P: Added SD Query %p", q
);
511 void p2p_sd_service_update(struct p2p_data
*p2p
)
513 p2p
->srv_update_indic
++;
517 int p2p_sd_cancel_request(struct p2p_data
*p2p
, void *req
)
519 if (p2p_unlink_sd_query(p2p
, req
)) {
520 wpa_msg(p2p
->cfg
->msg_ctx
, MSG_DEBUG
,
521 "P2P: Cancel pending SD query %p", req
);
522 p2p_free_sd_query(req
);