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 }
     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 *******************************************************************************/
     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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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