Home | History | Annotate | Download | only in gap
      1 /******************************************************************************
      2  *
      3  *  Copyright (C) 2009-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 #include <string.h>
     20 #include "bt_target.h"
     21 #include "gap_int.h"
     22 
     23 /*****************************************************************************/
     24 /*                 G L O B A L      GAP       D A T A                        */
     25 /*****************************************************************************/
     26 #if GAP_DYNAMIC_MEMORY == FALSE
     27 tGAP_CB  gap_cb;
     28 #endif
     29 
     30 /*****************************************************************************
     31 ** Callbacks passed to BTM -
     32 **      There are different callbacks based on the control block index so that
     33 **      more than one command can be pending at a time.
     34 **  NOTE:  There must be 1 callback for each control block defined
     35 **          GAP_MAX_BLOCKS
     36 **
     37 **          Also, the inquiry results event has its own callback; Not handled here!
     38 ******************************************************************************/
     39 static void btm_cback(UINT16 index, void *p_data)
     40 {
     41     tGAP_INFO       *p_cb;
     42     tGAP_INQ_CMPL    inq_cmpl;
     43 
     44     /* Make sure that the index is valid AND it is in use */
     45     if (index < GAP_MAX_BLOCKS && gap_cb.blk[index].in_use)
     46     {
     47         p_cb = &gap_cb.blk[index];
     48 
     49         /* If the callback is non-NULL, call it with the specified event */
     50         switch (p_cb->event)
     51         {
     52         case GAP_EVT_INQUIRY_COMPLETE:
     53             /* pass the number of results to caller */
     54             inq_cmpl.num_results = ((tBTM_INQUIRY_CMPL *)p_data)->num_resp;
     55 
     56             inq_cmpl.status = (((tBTM_INQUIRY_CMPL *)p_data)->status == BTM_SUCCESS) ? BT_PASS : GAP_ERR_PROCESSING;
     57 
     58             p_data = &inq_cmpl;
     59 
     60             GAP_TRACE_EVENT2("   GAP Inquiry Complete Event (Status 0x%04x, Result(s) %d)",
     61                             inq_cmpl.status, inq_cmpl.num_results);
     62             break;
     63 
     64         case GAP_EVT_DISCOVERY_COMPLETE:
     65             if (*((UINT16 *) p_data))
     66             {
     67                 GAP_TRACE_EVENT1("   GAP Discovery Complete Event(SDP Result: 0x%04x)", *((UINT16 *) p_data));
     68             }
     69             else
     70             {
     71                 GAP_TRACE_EVENT0("   GAP Discovery Successfully Completed");
     72             }
     73 
     74             break;
     75 
     76         case GAP_EVT_REM_NAME_COMPLETE:
     77             /* override the BTM error code with a GAP error code */
     78             ((tGAP_REMOTE_DEV_NAME *)p_data)->status =
     79                     gap_convert_btm_status ((tBTM_STATUS)((tBTM_REMOTE_DEV_NAME *)p_data)->status);
     80 
     81             GAP_TRACE_EVENT1("   GAP Remote Name Complete Event (status 0x%04x)", ((tGAP_REMOTE_DEV_NAME *)p_data)->status);
     82 
     83             break;
     84         };
     85 
     86         if (p_cb->gap_cback)
     87             p_cb->gap_cback(p_cb->event, p_data);
     88 
     89         /* Deallocate the control block */
     90         gap_free_cb(p_cb);
     91     }
     92 }
     93 
     94 
     95 /*** Callback functions for BTM_CMPL_CB ***/
     96 void gap_btm_cback0(void *p1)
     97 {
     98     btm_cback(0, p1);
     99 }
    100 
    101 #if GAP_MAX_BLOCKS > 1
    102 void gap_btm_cback1(void *p1)
    103 {
    104     btm_cback(1, p1);
    105 }
    106 #endif
    107 #if GAP_MAX_BLOCKS > 2
    108 void gap_btm_cback2(void *p1)
    109 {
    110     btm_cback(2, p1);
    111 }
    112 #endif
    113 
    114 /* There is only one instance of this because only 1 inquiry can be active at a time */
    115 void gap_inq_results_cb(tBTM_INQ_RESULTS *p_results, UINT8 *p_eir)
    116 {
    117     tGAP_INFO   *p_cb;
    118     UINT8        index;
    119 
    120     GAP_TRACE_EVENT6 ("GAP Inquiry Results Callback (bdaddr [%02x%02x%02x%02x%02x%02x])",
    121                 p_results->remote_bd_addr[0], p_results->remote_bd_addr[1],
    122                 p_results->remote_bd_addr[2], p_results->remote_bd_addr[3],
    123                 p_results->remote_bd_addr[4], p_results->remote_bd_addr[5]);
    124     GAP_TRACE_EVENT4 ("                             (COD [%02x%02x%02x], clkoff 0x%04x)",
    125                 p_results->dev_class[0], p_results->dev_class[1], p_results->dev_class[2],
    126                 p_results->clock_offset);
    127 
    128     /* Find the control block which has an Inquiry Active and call its results callback */
    129     for (index = 0, p_cb = &gap_cb.blk[0]; index < GAP_MAX_BLOCKS; index++, p_cb++)
    130     {
    131         /* Look for the control block that is using inquiry */
    132         if (p_cb->in_use && (p_cb->event == GAP_EVT_INQUIRY_COMPLETE))
    133         {
    134             /* Notify the higher layer if they care */
    135             if (p_cb->gap_inq_rslt_cback)
    136                 p_cb->gap_inq_rslt_cback (GAP_EVT_INQUIRY_RESULTS, (tGAP_INQ_RESULTS *)p_results);
    137         }
    138     }
    139 }
    140 
    141 
    142 /*******************************************************************************
    143 **
    144 ** Function         gap_find_addr_name_cb
    145 **
    146 ** Description      Processes the remote name request event when the Find Addr by Name
    147 **                  request is active.  The following procedure takes place:
    148 **                  1. Check the resulting name (If return status is ok)
    149 **                  2. If name matches requested name, we're done, call the appl's callback
    150 **                          with the BD ADDR.
    151 **                  3. Otherwise get the next BD ADDR out of the inquiry database and intiate
    152 **                          another remote name request.
    153 **                  4. If there are no more BD ADDRs, then call the appl's callback with a FAIL
    154 **                          status.
    155 **
    156 ** Returns          void
    157 **
    158 *******************************************************************************/
    159 void gap_find_addr_name_cb (tBTM_REMOTE_DEV_NAME *p)
    160 {
    161     tGAP_FINDADDR_CB        *p_cb = &gap_cb.findaddr_cb;
    162     tGAP_FINDADDR_RESULTS   *p_result = &p_cb->results;
    163 
    164     if (p_cb->in_use)
    165     {
    166         if (p->status == BTM_SUCCESS)
    167         {
    168             GAP_TRACE_EVENT2("   GAP: FindAddrByName Rem Name Cmpl Evt (Status 0x%04x, Name [%s])",
    169                                 p->status, p->remote_bd_name);
    170 
    171             /* See if the returned name matches the desired name; if not initiate another search */
    172             if (!strncmp ((char *)p_result->devname, (char *) p->remote_bd_name, strlen ((char *) p_result->devname)))
    173             {
    174                 /* We found the device!  Copy it into the return structure */
    175                 memcpy (p_result->bd_addr, p_cb->p_cur_inq->results.remote_bd_addr, BD_ADDR_LEN);
    176                 p_result->status = BT_PASS;
    177             }
    178             else    /* The name doesn't match so initiate another search */
    179             {
    180                 /* Get the device address of the next database entry */
    181                 if ((p_cb->p_cur_inq = BTM_InqDbNext(p_cb->p_cur_inq)) != NULL)
    182                 {
    183                     if ((BTM_ReadRemoteDeviceName (p_cb->p_cur_inq->results.remote_bd_addr,
    184                         (tBTM_CMPL_CB *) gap_find_addr_name_cb)) == BTM_CMD_STARTED)
    185                         return;     /* This routine will get called again with the next results */
    186                     else
    187                         p_result->status = gap_convert_btm_status ((tBTM_STATUS) p->status);
    188                 }
    189                 else
    190                     p_result->status = GAP_EOINQDB;     /* No inquiry results; we're done! */
    191             }
    192         }
    193         else
    194         {
    195             GAP_TRACE_EVENT1("   GAP: FindAddrByName Rem Name Cmpl Evt (Status 0x%04x)", p->status);
    196             p_result->status = gap_convert_btm_status ((tBTM_STATUS) p->status);
    197         }
    198 
    199         /* If this code is reached, the process has completed so call the appl's callback with results */
    200         if (p_cb->p_cback)
    201             p_cb->p_cback (GAP_EVT_FIND_ADDR_COMPLETE, (tGAP_FINDADDR_RESULTS *) p_result);
    202 
    203         /* Clear out the control block */
    204         p_cb->in_use = FALSE;
    205         p_cb->p_cback = (tGAP_CALLBACK *) NULL;
    206     }
    207 }
    208 
    209 /*******************************************************************************
    210 **
    211 ** Function         gap_find_addr_inq_cb
    212 **
    213 ** Description      Processes the inquiry complete event when the Find Addr by Name
    214 **                  request is active.  This callback performs one of the two following
    215 **                  steps:
    216 **                      1. If the remote name is retrieved automatically, the DB is searched
    217 **                          immediately, and the results are returned in the appls callback.
    218 **
    219 **                      2. If remote name is not automatic, retrieve the first BTM INQ
    220 **                         database entry and initiate a remote name request.
    221 **
    222 ** Returns          void
    223 **
    224 *******************************************************************************/
    225 void gap_find_addr_inq_cb (tBTM_INQUIRY_CMPL *p)
    226 {
    227     tGAP_FINDADDR_CB        *p_cb = &gap_cb.findaddr_cb;
    228     tGAP_FINDADDR_RESULTS   *p_result = &p_cb->results;
    229 
    230     if (p_cb->in_use)
    231     {
    232 
    233         GAP_TRACE_EVENT2("   GAP: FindAddrByName Inq Cmpl Evt (Status 0x%04x, Result(s) %d)",
    234             p->status, p->num_resp);
    235 
    236         if (p->status == BTM_SUCCESS)
    237         {
    238             /* Step 1: If automatically retrieving remote names then search the local database */
    239             if ((p_result->status = gap_find_local_addr_by_name (p_result->devname, p_result->bd_addr)) == GAP_NO_DATA_AVAIL)
    240             {
    241                 /* Step 2:  The name is not stored automatically, so a search of all devices needs to
    242                  *          be initiated.
    243                  */
    244                 if ((p_cb->p_cur_inq = BTM_InqDbFirst()) != NULL)
    245                 {
    246                     if ((BTM_ReadRemoteDeviceName (p_cb->p_cur_inq->results.remote_bd_addr,
    247                         (tBTM_CMPL_CB *) gap_find_addr_name_cb)) == BTM_CMD_STARTED)
    248                         return;     /* Wait for the response in gap_find_addr_name_cb() */
    249                     else
    250                         p_result->status = gap_convert_btm_status (p->status);
    251                 }
    252                 else
    253                     p_result->status = GAP_EOINQDB;     /* No inquiry results; we're done! */
    254             }
    255         }
    256         else
    257             p_result->status = gap_convert_btm_status (p->status);
    258 
    259         /* If this code is reached, the process has completed so call the appl's callback with results */
    260         if (p_cb->p_cback)
    261             p_cb->p_cback (GAP_EVT_FIND_ADDR_COMPLETE, (tGAP_FINDADDR_RESULTS *) p_result);
    262 
    263         /* Clear out the control block */
    264         p_cb->in_use = FALSE;
    265         p_cb->p_cback = (tGAP_CALLBACK *) NULL;
    266     }
    267 }
    268 
    269 /*******************************************************************************
    270 **
    271 ** Function         gap_find_local_addr_by_name
    272 **
    273 ** Description      Searches through the internal inquiry database for a device
    274 **                  that has the same name as the one passed in.  If found, the
    275 **                  device address is filled in.
    276 **
    277 **                  NOTE:  It only searches up to the first BTM_MAX_REM_BD_NAME_LEN
    278 **                          bytes because the inquiry database uses tBTM_BD_NAME.
    279 **
    280 ** Returns          BT_PASS if the name was found and the device address is filled in
    281 **                  GAP_EOINQDB if the name was not found in the database
    282 **                  GAP_NO_DATA_AVAIL if the name is not saved with the inquiry
    283 **
    284 *******************************************************************************/
    285 UINT16 gap_find_local_addr_by_name (const tBTM_BD_NAME devname, BD_ADDR bd_addr)
    286 {
    287 
    288 /* If the remote name is retrieved automatically during an inquiry search the local db */
    289 #if (BTM_INQ_GET_REMOTE_NAME == TRUE)
    290     tBTM_INQ_INFO   *p_result;
    291 
    292     p_result = BTM_InqDbFirst();
    293 
    294     while (p_result)
    295     {
    296         /* Check the entry for a device name match */
    297         if (!strncmp ((char *)devname, (char *)p_result->remote_name, BTM_MAX_REM_BD_NAME_LEN))
    298         {
    299             memcpy (bd_addr, p_result->results.remote_bd_addr, BD_ADDR_LEN);
    300             return (BT_PASS);
    301         }
    302         else
    303             p_result = BTM_InqDbNext(p_result);
    304     };
    305 
    306     return (GAP_EOINQDB);
    307 #else
    308     /* No data available because we are not automatically saving the data */
    309     return (GAP_NO_DATA_AVAIL);
    310 #endif
    311 }
    312 
    313 
    314 /*******************************************************************************
    315 **
    316 ** Function         gap_allocate_cb
    317 **
    318 ** Description      Look through the GAP Control Blocks for a free one.
    319 **
    320 ** Returns          Pointer to the control block or NULL if not found
    321 **
    322 *******************************************************************************/
    323 tGAP_INFO *gap_allocate_cb (void)
    324 {
    325     tGAP_INFO     *p_cb = &gap_cb.blk[0];
    326     UINT8        x;
    327 
    328     for (x = 0; x < GAP_MAX_BLOCKS; x++, p_cb++)
    329     {
    330         if (!p_cb->in_use)
    331         {
    332             memset (p_cb, 0, sizeof (tGAP_INFO));
    333 
    334             p_cb->in_use = TRUE;
    335             p_cb->index = x;
    336             p_cb->p_data = (void *)NULL;
    337             return (p_cb);
    338         }
    339     }
    340 
    341     /* If here, no free control blocks found */
    342     return (NULL);
    343 }
    344 
    345 
    346 /*******************************************************************************
    347 **
    348 ** Function         gap_free_cb
    349 **
    350 ** Description      Release GAP control block.
    351 **
    352 ** Returns          Pointer to the control block or NULL if not found
    353 **
    354 *******************************************************************************/
    355 void gap_free_cb (tGAP_INFO *p_cb)
    356 {
    357     if (p_cb)
    358     {
    359         p_cb->gap_cback = NULL;
    360         p_cb->in_use = FALSE;
    361     }
    362 }
    363 
    364 
    365 /*******************************************************************************
    366 **
    367 ** Function         gap_is_service_busy
    368 **
    369 ** Description      Look through the GAP Control Blocks that are in use
    370 **                  and check to see if the event waiting for is the command
    371 **                  requested.
    372 **
    373 ** Returns          TRUE if already in use
    374 **                  FALSE if not busy
    375 **
    376 *******************************************************************************/
    377 BOOLEAN gap_is_service_busy (UINT16 request)
    378 {
    379     tGAP_INFO   *p_cb = &gap_cb.blk[0];
    380     UINT8        x;
    381 
    382     for (x = 0; x < GAP_MAX_BLOCKS; x++, p_cb++)
    383     {
    384         if (p_cb->in_use && p_cb->event == request)
    385             return (TRUE);
    386     }
    387 
    388     /* If here, service is not busy */
    389     return (FALSE);
    390 }
    391 
    392 
    393 /*******************************************************************************
    394 **
    395 ** Function         gap_convert_btm_status
    396 **
    397 ** Description      Converts a BTM error status into a GAP error status
    398 **
    399 **
    400 ** Returns          GAP_UNKNOWN_BTM_STATUS is returned if not recognized
    401 **
    402 *******************************************************************************/
    403 UINT16 gap_convert_btm_status (tBTM_STATUS btm_status)
    404 {
    405     switch (btm_status)
    406     {
    407     case BTM_SUCCESS:
    408         return (BT_PASS);
    409 
    410     case BTM_CMD_STARTED:
    411         return (GAP_CMD_INITIATED);
    412 
    413     case BTM_BUSY:
    414         return (GAP_ERR_BUSY);
    415 
    416     case BTM_MODE_UNSUPPORTED:
    417     case BTM_ILLEGAL_VALUE:
    418         return (GAP_ERR_ILL_PARM);
    419 
    420     case BTM_WRONG_MODE:
    421         return (GAP_DEVICE_NOT_UP);
    422 
    423     case BTM_UNKNOWN_ADDR:
    424         return (GAP_BAD_BD_ADDR);
    425 
    426     case BTM_DEVICE_TIMEOUT:
    427         return (GAP_ERR_TIMEOUT);
    428 
    429     default:
    430         return (GAP_ERR_PROCESSING);
    431     }
    432 }
    433