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