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