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