• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 ******************************************************************************/
btm_cback(UINT16 index,void * p_data)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 ***/
gap_btm_cback0(void * p1)97 void gap_btm_cback0(void *p1)
98 {
99     btm_cback(0, p1);
100 }
101 
102 #if GAP_MAX_BLOCKS > 1
gap_btm_cback1(void * p1)103 void gap_btm_cback1(void *p1)
104 {
105     btm_cback(1, p1);
106 }
107 #endif
108 #if GAP_MAX_BLOCKS > 2
gap_btm_cback2(void * p1)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 */
gap_inq_results_cb(tBTM_INQ_RESULTS * p_results,UINT8 * p_eir)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 *******************************************************************************/
gap_find_addr_name_cb(tBTM_REMOTE_DEV_NAME * p)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 *******************************************************************************/
gap_find_addr_inq_cb(tBTM_INQUIRY_CMPL * p)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 *******************************************************************************/
gap_find_local_addr_by_name(const tBTM_BD_NAME devname,BD_ADDR bd_addr)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 *******************************************************************************/
gap_allocate_cb(void)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 *******************************************************************************/
gap_free_cb(tGAP_INFO * p_cb)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 *******************************************************************************/
gap_is_service_busy(UINT16 request)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 *******************************************************************************/
gap_convert_btm_status(tBTM_STATUS btm_status)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