llcp_sdp.c revision 5c65c3a0f42e174e47fecd4e569606003217ff4e
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*******************************************************************************/
44void 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*******************************************************************************/
62void 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*******************************************************************************/
100static 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*******************************************************************************/
125tLLCP_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*******************************************************************************/
207static 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*******************************************************************************/
231static 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*******************************************************************************/
310UINT8 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*******************************************************************************/
346static 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*******************************************************************************/
374void 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*******************************************************************************/
411tLLCP_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