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*******************************************************************************/
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}
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*******************************************************************************/
91static 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*******************************************************************************/
116tLLCP_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*******************************************************************************/
198static 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*******************************************************************************/
222static 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*******************************************************************************/
301UINT8 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*******************************************************************************/
331static 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*******************************************************************************/
359void 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*******************************************************************************/
395tLLCP_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