• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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