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