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