Home | History | Annotate | Download | only in llcp
      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 *******************************************************************************/
     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 *******************************************************************************/
     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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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