1 /******************************************************************************
2 *
3 * Copyright (C) 2010-2012 Broadcom Corporation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 /******************************************************************************
20 *
21 * This file contains the LLCP Service Discovery
22 *
23 ******************************************************************************/
24
25 #include <string.h>
26 #include "gki.h"
27 #include "nfc_target.h"
28 #include "bt_types.h"
29 #include "llcp_api.h"
30 #include "llcp_int.h"
31 #include "llcp_defs.h"
32
33 /*******************************************************************************
34 **
35 ** Function llcp_sdp_proc_data
36 **
37 ** Description Do nothing
38 **
39 **
40 ** Returns void
41 **
42 *******************************************************************************/
llcp_sdp_proc_data(tLLCP_SAP_CBACK_DATA * p_data)43 void llcp_sdp_proc_data (tLLCP_SAP_CBACK_DATA *p_data)
44 {
45 /*
46 ** Do nothing
47 ** llcp_sdp_proc_SNL () is called by link layer
48 */
49 }
50
51 /*******************************************************************************
52 **
53 ** Function llcp_sdp_check_send_snl
54 **
55 ** Description Enqueue Service Name Lookup PDU into sig_xmit_q for transmitting
56 **
57 **
58 ** Returns void
59 **
60 *******************************************************************************/
llcp_sdp_check_send_snl(void)61 void llcp_sdp_check_send_snl (void)
62 {
63 UINT8 *p;
64
65 if (llcp_cb.sdp_cb.p_snl)
66 {
67 LLCP_TRACE_DEBUG0 ("SDP: llcp_sdp_check_send_snl ()");
68
69 llcp_cb.sdp_cb.p_snl->len += LLCP_PDU_HEADER_SIZE;
70 llcp_cb.sdp_cb.p_snl->offset -= LLCP_PDU_HEADER_SIZE;
71
72 p = (UINT8 *) (llcp_cb.sdp_cb.p_snl + 1) + llcp_cb.sdp_cb.p_snl->offset;
73 UINT16_TO_BE_STREAM (p, LLCP_GET_PDU_HEADER (LLCP_SAP_SDP, LLCP_PDU_SNL_TYPE, LLCP_SAP_SDP ));
74
75 GKI_enqueue (&llcp_cb.lcb.sig_xmit_q, llcp_cb.sdp_cb.p_snl);
76 llcp_cb.sdp_cb.p_snl = NULL;
77 }
78 else
79 {
80 /* Notify DTA after sending out SNL with SDRES not to send SNLs in AGF PDU */
81 if ((llcp_cb.p_dta_cback) && (llcp_cb.dta_snl_resp))
82 {
83 llcp_cb.dta_snl_resp = FALSE;
84 (*llcp_cb.p_dta_cback) ();
85 }
86 }
87 }
88
89 /*******************************************************************************
90 **
91 ** Function llcp_sdp_add_sdreq
92 **
93 ** Description Add Service Discovery Request into SNL PDU
94 **
95 **
96 ** Returns void
97 **
98 *******************************************************************************/
llcp_sdp_add_sdreq(UINT8 tid,char * p_name)99 static void llcp_sdp_add_sdreq (UINT8 tid, char *p_name)
100 {
101 UINT8 *p;
102 UINT16 name_len = (UINT16) strlen (p_name);
103
104 p = (UINT8 *) (llcp_cb.sdp_cb.p_snl + 1) + llcp_cb.sdp_cb.p_snl->offset + llcp_cb.sdp_cb.p_snl->len;
105
106 UINT8_TO_BE_STREAM (p, LLCP_SDREQ_TYPE);
107 UINT8_TO_BE_STREAM (p, (1 + name_len));
108 UINT8_TO_BE_STREAM (p, tid);
109 ARRAY_TO_BE_STREAM (p, p_name, name_len);
110
111 llcp_cb.sdp_cb.p_snl->len += LLCP_SDREQ_MIN_LEN + name_len;
112 }
113
114 /*******************************************************************************
115 **
116 ** Function llcp_sdp_send_sdreq
117 **
118 ** Description Send Service Discovery Request
119 **
120 **
121 ** Returns LLCP_STATUS
122 **
123 *******************************************************************************/
llcp_sdp_send_sdreq(UINT8 tid,char * p_name)124 tLLCP_STATUS llcp_sdp_send_sdreq (UINT8 tid, char *p_name)
125 {
126 tLLCP_STATUS status;
127 UINT16 name_len;
128 UINT16 available_bytes;
129
130 LLCP_TRACE_DEBUG2 ("llcp_sdp_send_sdreq (): tid=0x%x, ServiceName=%s", tid, p_name);
131
132 /* if there is no pending SNL */
133 if (!llcp_cb.sdp_cb.p_snl)
134 {
135 llcp_cb.sdp_cb.p_snl = (BT_HDR*) GKI_getpoolbuf (LLCP_POOL_ID);
136
137 if (llcp_cb.sdp_cb.p_snl)
138 {
139 llcp_cb.sdp_cb.p_snl->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE + LLCP_PDU_HEADER_SIZE;
140 llcp_cb.sdp_cb.p_snl->len = 0;
141 }
142 }
143
144 if (llcp_cb.sdp_cb.p_snl)
145 {
146 available_bytes = GKI_get_buf_size (llcp_cb.sdp_cb.p_snl)
147 - BT_HDR_SIZE - llcp_cb.sdp_cb.p_snl->offset
148 - llcp_cb.sdp_cb.p_snl->len;
149
150 name_len = (UINT16) strlen (p_name);
151
152 /* if SDREQ parameter can be added in SNL */
153 if ( (available_bytes >= LLCP_SDREQ_MIN_LEN + name_len)
154 &&(llcp_cb.sdp_cb.p_snl->len + LLCP_SDREQ_MIN_LEN + name_len <= llcp_cb.lcb.effective_miu) )
155 {
156 llcp_sdp_add_sdreq (tid, p_name);
157 status = LLCP_STATUS_SUCCESS;
158 }
159 else
160 {
161 /* send pending SNL PDU to LM */
162 llcp_sdp_check_send_snl ();
163
164 llcp_cb.sdp_cb.p_snl = (BT_HDR*) GKI_getpoolbuf (LLCP_POOL_ID);
165
166 if (llcp_cb.sdp_cb.p_snl)
167 {
168 llcp_cb.sdp_cb.p_snl->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE + LLCP_PDU_HEADER_SIZE;
169 llcp_cb.sdp_cb.p_snl->len = 0;
170
171 llcp_sdp_add_sdreq (tid, p_name);
172
173 status = LLCP_STATUS_SUCCESS;
174 }
175 else
176 {
177 status = LLCP_STATUS_FAIL;
178 }
179 }
180 }
181 else
182 {
183 status = LLCP_STATUS_FAIL;
184 }
185
186 /* if LM is waiting for PDUs from upper layer */
187 if ( (status == LLCP_STATUS_SUCCESS)
188 &&(llcp_cb.lcb.symm_state == LLCP_LINK_SYMM_LOCAL_XMIT_NEXT) )
189 {
190 llcp_link_check_send_data ();
191 }
192
193 return status;
194 }
195
196 /*******************************************************************************
197 **
198 ** Function llcp_sdp_add_sdres
199 **
200 ** Description Add Service Discovery Response into SNL PDU
201 **
202 **
203 ** Returns void
204 **
205 *******************************************************************************/
llcp_sdp_add_sdres(UINT8 tid,UINT8 sap)206 static void llcp_sdp_add_sdres (UINT8 tid, UINT8 sap)
207 {
208 UINT8 *p;
209
210 p = (UINT8 *) (llcp_cb.sdp_cb.p_snl + 1) + llcp_cb.sdp_cb.p_snl->offset + llcp_cb.sdp_cb.p_snl->len;
211
212 UINT8_TO_BE_STREAM (p, LLCP_SDRES_TYPE);
213 UINT8_TO_BE_STREAM (p, LLCP_SDRES_LEN);
214 UINT8_TO_BE_STREAM (p, tid);
215 UINT8_TO_BE_STREAM (p, sap);
216
217 llcp_cb.sdp_cb.p_snl->len += 2 + LLCP_SDRES_LEN; /* type and length */
218 }
219
220 /*******************************************************************************
221 **
222 ** Function llcp_sdp_send_sdres
223 **
224 ** Description Send Service Discovery Response
225 **
226 **
227 ** Returns LLCP_STATUS
228 **
229 *******************************************************************************/
llcp_sdp_send_sdres(UINT8 tid,UINT8 sap)230 static tLLCP_STATUS llcp_sdp_send_sdres (UINT8 tid, UINT8 sap)
231 {
232 tLLCP_STATUS status;
233 UINT16 available_bytes;
234
235 LLCP_TRACE_DEBUG2 ("llcp_sdp_send_sdres (): tid=0x%x, SAP=0x%x", tid, sap);
236
237 /* if there is no pending SNL */
238 if (!llcp_cb.sdp_cb.p_snl)
239 {
240 llcp_cb.sdp_cb.p_snl = (BT_HDR*) GKI_getpoolbuf (LLCP_POOL_ID);
241
242 if (llcp_cb.sdp_cb.p_snl)
243 {
244 llcp_cb.sdp_cb.p_snl->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE + LLCP_PDU_HEADER_SIZE;
245 llcp_cb.sdp_cb.p_snl->len = 0;
246 }
247 }
248
249 if (llcp_cb.sdp_cb.p_snl)
250 {
251 available_bytes = GKI_get_buf_size (llcp_cb.sdp_cb.p_snl)
252 - BT_HDR_SIZE - llcp_cb.sdp_cb.p_snl->offset
253 - llcp_cb.sdp_cb.p_snl->len;
254
255 /* if SDRES parameter can be added in SNL */
256 if ( (available_bytes >= 2 + LLCP_SDRES_LEN)
257 &&(llcp_cb.sdp_cb.p_snl->len + 2 + LLCP_SDRES_LEN <= llcp_cb.lcb.effective_miu) )
258 {
259 llcp_sdp_add_sdres (tid, sap);
260 status = LLCP_STATUS_SUCCESS;
261 }
262 else
263 {
264 /* send pending SNL PDU to LM */
265 llcp_sdp_check_send_snl ();
266
267 llcp_cb.sdp_cb.p_snl = (BT_HDR*) GKI_getpoolbuf (LLCP_POOL_ID);
268
269 if (llcp_cb.sdp_cb.p_snl)
270 {
271 llcp_cb.sdp_cb.p_snl->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE + LLCP_PDU_HEADER_SIZE;
272 llcp_cb.sdp_cb.p_snl->len = 0;
273
274 llcp_sdp_add_sdres (tid, sap);
275
276 status = LLCP_STATUS_SUCCESS;
277 }
278 else
279 {
280 status = LLCP_STATUS_FAIL;
281 }
282 }
283 }
284 else
285 {
286 status = LLCP_STATUS_FAIL;
287 }
288
289 /* if LM is waiting for PDUs from upper layer */
290 if ( (status == LLCP_STATUS_SUCCESS)
291 &&(llcp_cb.lcb.symm_state == LLCP_LINK_SYMM_LOCAL_XMIT_NEXT) )
292 {
293 llcp_link_check_send_data ();
294 }
295
296 return status;
297 }
298
299 /*******************************************************************************
300 **
301 ** Function llcp_sdp_get_sap_by_name
302 **
303 ** Description Search SAP by service name
304 **
305 **
306 ** Returns SAP if success
307 **
308 *******************************************************************************/
llcp_sdp_get_sap_by_name(char * p_name,UINT8 length)309 UINT8 llcp_sdp_get_sap_by_name (char *p_name, UINT8 length)
310 {
311 UINT8 sap;
312 tLLCP_APP_CB *p_app_cb;
313
314 for (sap = LLCP_SAP_SDP; sap <= LLCP_UPPER_BOUND_SDP_SAP; sap++)
315 {
316 p_app_cb = llcp_util_get_app_cb (sap);
317
318 if ( (p_app_cb)
319 &&(p_app_cb->p_app_cback)
320 &&(strlen((char*)p_app_cb->p_service_name) == length)
321 &&(!strncmp((char*)p_app_cb->p_service_name, p_name, length)) )
322 {
323 /* if device is under LLCP DTA testing */
324 if ( (llcp_cb.p_dta_cback)
325 &&(!strncmp((char*)p_app_cb->p_service_name, "urn:nfc:sn:cl-echo-in", length)) )
326 {
327 llcp_cb.dta_snl_resp = TRUE;
328 }
329 return (sap);
330 }
331 }
332 return 0;
333 }
334
335 /*******************************************************************************
336 **
337 ** Function llcp_sdp_return_sap
338 **
339 ** Description Report TID and SAP to requester
340 **
341 **
342 ** Returns void
343 **
344 *******************************************************************************/
llcp_sdp_return_sap(UINT8 tid,UINT8 sap)345 static void llcp_sdp_return_sap (UINT8 tid, UINT8 sap)
346 {
347 UINT8 i;
348
349 LLCP_TRACE_DEBUG2 ("llcp_sdp_return_sap (): tid=0x%x, SAP=0x%x", tid, sap);
350
351 for (i = 0; i < LLCP_MAX_SDP_TRANSAC; i++)
352 {
353 if ( (llcp_cb.sdp_cb.transac[i].p_cback)
354 &&(llcp_cb.sdp_cb.transac[i].tid == tid) )
355 {
356 (*llcp_cb.sdp_cb.transac[i].p_cback) (tid, sap);
357
358 llcp_cb.sdp_cb.transac[i].p_cback = NULL;
359 }
360 }
361 }
362
363 /*******************************************************************************
364 **
365 ** Function llcp_sdp_proc_deactivation
366 **
367 ** Description Report SDP failure for any pending request because of deactivation
368 **
369 **
370 ** Returns void
371 **
372 *******************************************************************************/
llcp_sdp_proc_deactivation(void)373 void llcp_sdp_proc_deactivation (void)
374 {
375 UINT8 i;
376
377 LLCP_TRACE_DEBUG0 ("llcp_sdp_proc_deactivation ()");
378
379 for (i = 0; i < LLCP_MAX_SDP_TRANSAC; i++)
380 {
381 if (llcp_cb.sdp_cb.transac[i].p_cback)
382 {
383 (*llcp_cb.sdp_cb.transac[i].p_cback) (llcp_cb.sdp_cb.transac[i].tid, 0x00);
384
385 llcp_cb.sdp_cb.transac[i].p_cback = NULL;
386 }
387 }
388
389 /* free any pending SNL PDU */
390 if (llcp_cb.sdp_cb.p_snl)
391 {
392 GKI_freebuf (llcp_cb.sdp_cb.p_snl);
393 llcp_cb.sdp_cb.p_snl = NULL;
394 }
395
396 llcp_cb.sdp_cb.next_tid = 0;
397 llcp_cb.dta_snl_resp = FALSE;
398 }
399
400 /*******************************************************************************
401 **
402 ** Function llcp_sdp_proc_snl
403 **
404 ** Description Process SDREQ and SDRES in SNL
405 **
406 **
407 ** Returns LLCP_STATUS
408 **
409 *******************************************************************************/
llcp_sdp_proc_snl(UINT16 sdu_length,UINT8 * p)410 tLLCP_STATUS llcp_sdp_proc_snl (UINT16 sdu_length, UINT8 *p)
411 {
412 UINT8 type, length, tid, sap, *p_value;
413
414 LLCP_TRACE_DEBUG0 ("llcp_sdp_proc_snl ()");
415
416 if ((llcp_cb.lcb.agreed_major_version < LLCP_MIN_SNL_MAJOR_VERSION)||
417 ((llcp_cb.lcb.agreed_major_version == LLCP_MIN_SNL_MAJOR_VERSION)&&(llcp_cb.lcb.agreed_minor_version < LLCP_MIN_SNL_MINOR_VERSION)))
418 {
419 LLCP_TRACE_DEBUG0 ("llcp_sdp_proc_snl(): version number less than 1.1, SNL not supported.");
420 return LLCP_STATUS_FAIL;
421 }
422 while (sdu_length >= 2) /* at least type and length */
423 {
424 BE_STREAM_TO_UINT8 (type, p);
425 BE_STREAM_TO_UINT8 (length, p);
426
427 switch (type)
428 {
429 case LLCP_SDREQ_TYPE:
430 if ( (length > 1) /* TID and sevice name */
431 &&(sdu_length >= 2 + length) ) /* type, length, TID and service name */
432 {
433 p_value = p;
434 BE_STREAM_TO_UINT8 (tid, p_value);
435 sap = llcp_sdp_get_sap_by_name ((char*) p_value, (UINT8) (length - 1));
436 llcp_sdp_send_sdres (tid, sap);
437 }
438 else
439 {
440 LLCP_TRACE_ERROR1 ("llcp_sdp_proc_snl (): bad length (%d) in LLCP_SDREQ_TYPE", length);
441 }
442 break;
443
444 case LLCP_SDRES_TYPE:
445 if ( (length == LLCP_SDRES_LEN) /* TID and SAP */
446 &&(sdu_length >= 2 + length) ) /* type, length, TID and SAP */
447 {
448 p_value = p;
449 BE_STREAM_TO_UINT8 (tid, p_value);
450 BE_STREAM_TO_UINT8 (sap, p_value);
451 llcp_sdp_return_sap (tid, sap);
452 }
453 else
454 {
455 LLCP_TRACE_ERROR1 ("llcp_sdp_proc_snl (): bad length (%d) in LLCP_SDRES_TYPE", length);
456 }
457 break;
458
459 default:
460 LLCP_TRACE_WARNING1 ("llcp_sdp_proc_snl (): Unknown type (0x%x) is ignored", type);
461 break;
462 }
463
464 if (sdu_length >= 2 + length) /* type, length, value */
465 {
466 sdu_length -= 2 + length;
467 p += length;
468 }
469 else
470 {
471 break;
472 }
473 }
474
475 if (sdu_length)
476 {
477 LLCP_TRACE_ERROR0 ("llcp_sdp_proc_snl (): Bad format of SNL");
478 return LLCP_STATUS_FAIL;
479 }
480 else
481 {
482 return LLCP_STATUS_SUCCESS;
483 }
484 }
485