1 /******************************************************************************
3 * Copyright (C) 2003-2014 Broadcom Corporation
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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 ******************************************************************************/
19 /*****************************************************************************
23 ** Description: This file contains vendor specific feature for BLE
25 ******************************************************************************/
27 #include "bt_target.h"
29 #if (BLE_INCLUDED == TRUE)
33 #include "vendor_ble.h"
34 #include "vendor_hcidefs.h"
37 /*** This needs to be moved to a VSC control block eventually per coding conventions ***/
38 #if VENDOR_DYNAMIC_MEMORY == FALSE
39 tBTM_BLE_VENDOR_CB btm_ble_vendor_cb;
42 static const BD_ADDR na_bda= {0};
44 /*******************************************************************************
45 ** Resolve Address Using IRK List functions
46 *******************************************************************************/
49 /*******************************************************************************
51 ** Function btm_ble_vendor_enq_irk_pending
53 ** Description add target address into IRK pending operation queue
55 ** Parameters target_bda: target device address
56 ** add_entry: TRUE for add entry, FALSE for remove entry
60 *******************************************************************************/
61 void btm_ble_vendor_enq_irk_pending(BD_ADDR target_bda, BD_ADDR psuedo_bda, UINT8 to_add)
63 #if BLE_PRIVACY_SPT == TRUE
64 tBTM_BLE_IRK_Q *p_q = &btm_ble_vendor_cb.irk_pend_q;
66 memcpy(p_q->irk_q[p_q->q_next], target_bda, BD_ADDR_LEN);
67 memcpy(p_q->irk_q_random_pseudo[p_q->q_next], psuedo_bda, BD_ADDR_LEN);
68 p_q->irk_q_action[p_q->q_next] = to_add;
71 p_q->q_next %= btm_cb.cmn_ble_vsc_cb.max_irk_list_sz;;
75 /*******************************************************************************
77 ** Function btm_ble_vendor_find_irk_pending_entry
79 ** Description check to see if the action is in pending list
81 ** Parameters TRUE: action pending;
86 *******************************************************************************/
87 BOOLEAN btm_ble_vendor_find_irk_pending_entry(BD_ADDR psuedo_addr, UINT8 action)
89 #if BLE_PRIVACY_SPT == TRUE
90 tBTM_BLE_IRK_Q *p_q = &btm_ble_vendor_cb.irk_pend_q;
93 for (i = p_q->q_pending; i != p_q->q_next; )
95 if (memcmp(p_q->irk_q_random_pseudo[i], psuedo_addr, BD_ADDR_LEN) == 0 &&
96 action == p_q->irk_q_action[i])
100 i %= btm_cb.cmn_ble_vsc_cb.max_irk_list_sz;
105 /*******************************************************************************
107 ** Function btm_ble_vendor_deq_irk_pending
109 ** Description add target address into IRK pending operation queue
111 ** Parameters target_bda: target device address
112 ** add_entry: TRUE for add entry, FALSE for remove entry
116 *******************************************************************************/
117 BOOLEAN btm_ble_vendor_deq_irk_pending(BD_ADDR target_bda, BD_ADDR psuedo_addr)
119 #if BLE_PRIVACY_SPT == TRUE
120 tBTM_BLE_IRK_Q *p_q = &btm_ble_vendor_cb.irk_pend_q;
122 if (p_q->q_next != p_q->q_pending)
124 memcpy(target_bda, p_q->irk_q[p_q->q_pending], BD_ADDR_LEN);
125 memcpy(psuedo_addr, p_q->irk_q_random_pseudo[p_q->q_pending], BD_ADDR_LEN);
128 p_q->q_pending %= btm_cb.cmn_ble_vsc_cb.max_irk_list_sz;
136 /*******************************************************************************
138 ** Function btm_ble_vendor_find_irk_entry
140 ** Description find IRK entry in local host IRK list by static address
142 ** Returns IRK list entry pointer
144 *******************************************************************************/
145 tBTM_BLE_IRK_ENTRY * btm_ble_vendor_find_irk_entry(BD_ADDR target_bda)
147 #if BLE_PRIVACY_SPT == TRUE
148 tBTM_BLE_IRK_ENTRY *p_irk_entry = &btm_ble_vendor_cb.irk_list[0];
151 for (i = 0; i < btm_cb.cmn_ble_vsc_cb.max_irk_list_sz; i ++, p_irk_entry++)
153 if (p_irk_entry->in_use && memcmp(p_irk_entry->bd_addr, target_bda, BD_ADDR_LEN) == 0)
161 /*******************************************************************************
163 ** Function btm_ble_vendor_find_irk_entry_by_psuedo_addr
165 ** Description find IRK entry in local host IRK list by psuedo address
167 ** Returns IRK list entry pointer
169 *******************************************************************************/
170 tBTM_BLE_IRK_ENTRY * btm_ble_vendor_find_irk_entry_by_psuedo_addr (BD_ADDR psuedo_bda)
172 #if BLE_PRIVACY_SPT == TRUE
173 tBTM_BLE_IRK_ENTRY *p_irk_entry = &btm_ble_vendor_cb.irk_list[0];
176 for (i = 0; i < btm_cb.cmn_ble_vsc_cb.max_irk_list_sz; i ++, p_irk_entry++)
178 if (p_irk_entry->in_use && memcmp(p_irk_entry->psuedo_bda, psuedo_bda, BD_ADDR_LEN) == 0)
186 /*******************************************************************************
188 ** Function btm_ble_vendor_alloc_irk_entry
190 ** Description allocate IRK entry in local host IRK list
192 ** Returns IRK list index
194 *******************************************************************************/
195 UINT8 btm_ble_vendor_alloc_irk_entry(BD_ADDR target_bda, BD_ADDR pseudo_bda)
197 #if BLE_PRIVACY_SPT == TRUE
198 tBTM_BLE_IRK_ENTRY *p_irk_entry = &btm_ble_vendor_cb.irk_list[0];
201 for (i = 0; i < btm_cb.cmn_ble_vsc_cb.max_irk_list_sz; i ++, p_irk_entry++)
203 if (!p_irk_entry->in_use)
205 memcpy(p_irk_entry->bd_addr, target_bda, BD_ADDR_LEN);
206 memcpy(p_irk_entry->psuedo_bda, pseudo_bda, BD_ADDR_LEN);
208 p_irk_entry->index = i;
209 p_irk_entry->in_use = TRUE;
215 return BTM_CS_IRK_LIST_INVALID;
218 /*******************************************************************************
220 ** Function btm_ble_vendor_update_irk_list
222 ** Description update IRK entry in local host IRK list
226 *******************************************************************************/
227 void btm_ble_vendor_update_irk_list(BD_ADDR target_bda, BD_ADDR pseudo_bda, BOOLEAN add)
229 #if BLE_PRIVACY_SPT == TRUE
230 tBTM_BLE_IRK_ENTRY *p_irk_entry = btm_ble_vendor_find_irk_entry(target_bda);
235 if (p_irk_entry == NULL)
237 if ((i = btm_ble_vendor_alloc_irk_entry(target_bda, pseudo_bda)) == BTM_CS_IRK_LIST_INVALID)
239 BTM_TRACE_ERROR("max IRK capacity reached");
244 BTM_TRACE_WARNING(" IRK already in queue");
249 if (p_irk_entry != NULL)
251 memset(p_irk_entry, 0, sizeof(tBTM_BLE_IRK_ENTRY));
255 BTM_TRACE_ERROR("No IRK exist in list, can not remove");
261 /*******************************************************************************
263 ** Function btm_ble_vendor_irk_vsc_op_cmpl
265 ** Description IRK operation VSC complete handler
271 *******************************************************************************/
272 void btm_ble_vendor_irk_vsc_op_cmpl (tBTM_VSC_CMPL *p_params)
275 UINT8 *p = p_params->p_param_buf, op_subcode;
276 UINT16 evt_len = p_params->param_len;
278 tBTM_BLE_VENDOR_CB *p_cb = &btm_ble_vendor_cb;
279 BD_ADDR target_bda, pseudo_bda, rra;
282 STREAM_TO_UINT8(status, p);
287 BTM_TRACE_DEBUG("btm_ble_vendor_irk_vsc_op_cmpl op_subcode = %d", op_subcode);
290 BTM_TRACE_ERROR("cannot interpret IRK VSC cmpl callback");
294 if (BTM_BLE_META_IRK_ENABLE == op_subcode)
296 BTM_TRACE_DEBUG("IRK enable: %d, %d", status, op_subcode);
300 if (op_subcode == BTM_BLE_META_CLEAR_IRK_LIST)
302 if (status == HCI_SUCCESS)
304 STREAM_TO_UINT8(p_cb->irk_avail_size, p);
305 p_cb->irk_list_size = 0;
307 BTM_TRACE_DEBUG("p_cb->irk_list_size = %d", p_cb->irk_avail_size);
309 for (i = 0; i < btm_cb.cmn_ble_vsc_cb.max_irk_list_sz; i ++)
310 memset(&p_cb->irk_list[i], 0, sizeof(tBTM_BLE_IRK_ENTRY));
313 else if (op_subcode == BTM_BLE_META_ADD_IRK_ENTRY)
315 if (!btm_ble_vendor_deq_irk_pending(target_bda, pseudo_bda))
317 BTM_TRACE_ERROR("no pending IRK operation");
321 if (status == HCI_SUCCESS)
323 STREAM_TO_UINT8(p_cb->irk_avail_size, p);
324 btm_ble_vendor_update_irk_list(target_bda, pseudo_bda, TRUE);
326 else if (status == 0x07) /* BT_ERROR_CODE_MEMORY_CAPACITY_EXCEEDED */
328 p_cb->irk_avail_size = 0;
329 BTM_TRACE_ERROR("IRK Full ");
333 /* give the credit back if invalid parameter failed the operation */
334 p_cb->irk_list_size ++;
337 else if (op_subcode == BTM_BLE_META_REMOVE_IRK_ENTRY)
339 if (!btm_ble_vendor_deq_irk_pending(target_bda, pseudo_bda))
341 BTM_TRACE_ERROR("no pending IRK operation");
344 if (status == HCI_SUCCESS)
346 STREAM_TO_UINT8(p_cb->irk_avail_size, p);
347 btm_ble_vendor_update_irk_list(target_bda, pseudo_bda, FALSE);
351 /* give the credit back if invalid parameter failed the operation */
352 if (p_cb->irk_avail_size > 0)
353 p_cb->irk_list_size --;
357 else if (op_subcode == BTM_BLE_META_READ_IRK_ENTRY)
359 if (status == HCI_SUCCESS)
361 //STREAM_TO_UINT8(index, p);
362 p += (1 + 16 + 1); /* skip index, IRK value, address type */
363 STREAM_TO_BDADDR(target_bda, p);
364 STREAM_TO_BDADDR(rra, p);
365 btm_ble_refresh_rra(target_bda, rra);
370 /*******************************************************************************
372 ** Function btm_ble_remove_irk_entry
374 ** Description This function to remove an IRK entry from the list
376 ** Parameters ble_addr_type: address type
377 ** ble_addr: LE adddress
381 *******************************************************************************/
382 tBTM_STATUS btm_ble_remove_irk_entry(tBTM_SEC_DEV_REC *p_dev_rec)
384 #if BLE_PRIVACY_SPT == TRUE
387 tBTM_BLE_VENDOR_CB *p_cb = &btm_ble_vendor_cb;
390 memset(param, 0, 20);
392 UINT8_TO_STREAM(p, BTM_BLE_META_REMOVE_IRK_ENTRY);
393 UINT8_TO_STREAM(p, p_dev_rec->ble.static_addr_type);
394 BDADDR_TO_STREAM(p, p_dev_rec->ble.static_addr);
396 if ((st = BTM_VendorSpecificCommand (HCI_VENDOR_BLE_RPA_VSC,
397 BTM_BLE_META_REMOVE_IRK_LEN,
399 btm_ble_vendor_irk_vsc_op_cmpl))
402 btm_ble_vendor_enq_irk_pending(p_dev_rec->ble.static_addr, p_dev_rec->bd_addr, FALSE);
403 p_cb->irk_list_size --;
408 return BTM_MODE_UNSUPPORTED;
410 /*******************************************************************************
412 ** Function btm_ble_vendor_clear_irk_list
414 ** Description This function clears the IRK entry list
420 *******************************************************************************/
421 tBTM_STATUS btm_ble_vendor_clear_irk_list(void)
423 #if BLE_PRIVACY_SPT == TRUE
428 memset(param, 0, 20);
430 UINT8_TO_STREAM(p, BTM_BLE_META_CLEAR_IRK_LIST);
432 st = BTM_VendorSpecificCommand (HCI_VENDOR_BLE_RPA_VSC,
433 BTM_BLE_META_CLEAR_IRK_LEN,
435 btm_ble_vendor_irk_vsc_op_cmpl);
439 return BTM_MODE_UNSUPPORTED;
441 /*******************************************************************************
443 ** Function btm_ble_read_irk_entry
445 ** Description This function read an IRK entry by index
447 ** Parameters entry index.
451 *******************************************************************************/
452 tBTM_STATUS btm_ble_read_irk_entry(BD_ADDR target_bda)
454 #if BLE_PRIVACY_SPT == TRUE
456 tBTM_STATUS st = BTM_UNKNOWN_ADDR;
457 tBTM_BLE_IRK_ENTRY *p_entry = btm_ble_vendor_find_irk_entry(target_bda);
463 memset(param, 0, 20);
465 UINT8_TO_STREAM(p, BTM_BLE_META_READ_IRK_ENTRY);
466 UINT8_TO_STREAM(p, p_entry->index);
468 st = BTM_VendorSpecificCommand (HCI_VENDOR_BLE_RPA_VSC,
469 BTM_BLE_META_READ_IRK_LEN,
471 btm_ble_vendor_irk_vsc_op_cmpl);
475 return BTM_MODE_UNSUPPORTED;
479 /*******************************************************************************
481 ** Function btm_ble_vendor_enable_irk_list_known_dev
483 ** Description This function add all known device with random address into
486 ** Parameters enable: enable IRK list with known device, or disable it
490 *******************************************************************************/
491 void btm_ble_vendor_irk_list_known_dev(BOOLEAN enable)
493 #if BLE_PRIVACY_SPT == TRUE
496 tBTM_SEC_DEV_REC *p_dev_rec = &btm_cb.sec_dev_rec[0];
498 /* add all known device with random address into IRK list */
499 for (i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i ++, p_dev_rec ++)
501 if (p_dev_rec->sec_flags & BTM_SEC_IN_USE)
503 if (btm_ble_vendor_irk_list_load_dev(p_dev_rec))
508 if ((count > 0 && enable) || !enable)
509 btm_ble_vendor_enable_irk_feature(enable);
513 /*******************************************************************************
515 ** Function btm_ble_vendor_irk_list_load_dev
517 ** Description This function add a device which is using RPA into white list
523 *******************************************************************************/
524 BOOLEAN btm_ble_vendor_irk_list_load_dev(tBTM_SEC_DEV_REC *p_dev_rec)
526 #if BLE_PRIVACY_SPT == TRUE
528 tBTM_BLE_VENDOR_CB *p_cb = &btm_ble_vendor_cb;
530 tBTM_BLE_IRK_ENTRY *p_irk_entry = NULL;
531 BTM_TRACE_DEBUG ("btm_ble_vendor_irk_list_load_dev:max_irk_size=%d", p_cb->irk_avail_size);
532 memset(param, 0, 40);
534 if (p_dev_rec != NULL && /* RPA is being used and PID is known */
535 (p_dev_rec->ble.key_type & BTM_LE_KEY_PID) != 0)
538 if ((p_irk_entry = btm_ble_vendor_find_irk_entry_by_psuedo_addr(p_dev_rec->bd_addr)) == NULL &&
539 btm_ble_vendor_find_irk_pending_entry(p_dev_rec->bd_addr, TRUE) == FALSE)
542 if (p_cb->irk_avail_size > 0)
546 UINT8_TO_STREAM(p, BTM_BLE_META_ADD_IRK_ENTRY);
547 ARRAY_TO_STREAM(p, p_dev_rec->ble.keys.irk, BT_OCTET16_LEN);
548 UINT8_TO_STREAM(p, p_dev_rec->ble.static_addr_type);
549 BDADDR_TO_STREAM(p,p_dev_rec->ble.static_addr);
551 if (BTM_VendorSpecificCommand (HCI_VENDOR_BLE_RPA_VSC,
552 BTM_BLE_META_ADD_IRK_LEN,
554 btm_ble_vendor_irk_vsc_op_cmpl)
557 btm_ble_vendor_enq_irk_pending(p_dev_rec->ble.static_addr, p_dev_rec->bd_addr, TRUE);
558 p_cb->irk_list_size ++;
565 BTM_TRACE_ERROR("Device already in IRK list");
571 BTM_TRACE_DEBUG("Device not a RPA enabled device");
577 /*******************************************************************************
579 ** Function btm_ble_vendor_irk_list_remove_dev
581 ** Description This function remove the device from IRK list
587 *******************************************************************************/
588 void btm_ble_vendor_irk_list_remove_dev(tBTM_SEC_DEV_REC *p_dev_rec)
590 #if BLE_PRIVACY_SPT == TRUE
591 tBTM_BLE_VENDOR_CB *p_cs_cb = &btm_ble_vendor_cb;
592 tBTM_BLE_IRK_ENTRY *p_irk_entry;
594 if ((p_irk_entry = btm_ble_vendor_find_irk_entry_by_psuedo_addr(p_dev_rec->bd_addr)) != NULL &&
595 btm_ble_vendor_find_irk_pending_entry(p_dev_rec->bd_addr, FALSE) == FALSE)
597 btm_ble_remove_irk_entry(p_dev_rec);
601 BTM_TRACE_ERROR("Device not in IRK list");
604 if (p_cs_cb->irk_list_size == 0)
605 btm_ble_vendor_enable_irk_feature(FALSE);
608 /*******************************************************************************
610 ** Function btm_ble_vendor_disable_irk_list
612 ** Description disable LE resolve address feature
618 *******************************************************************************/
619 void btm_ble_vendor_disable_irk_list(void)
621 #if BLE_PRIVACY_SPT == TRUE
622 btm_ble_vendor_enable_irk_feature(FALSE);
626 /*******************************************************************************
628 ** Function btm_ble_vendor_enable_irk_feature
630 ** Description This function is called to enable or disable the RRA
631 ** offloading feature.
633 ** Parameters enable: enable or disable the RRA offloading feature
635 ** Returns BTM_SUCCESS if successful
637 *******************************************************************************/
638 tBTM_STATUS btm_ble_vendor_enable_irk_feature(BOOLEAN enable)
640 #if BLE_PRIVACY_SPT == TRUE
642 tBTM_STATUS st = BTM_WRONG_MODE;
643 tBTM_BLE_PF_COUNT *p_bda_filter;
646 memset(param, 0, 20);
648 /* select feature based on control block settings */
649 UINT8_TO_STREAM(p, BTM_BLE_META_IRK_ENABLE);
650 UINT8_TO_STREAM(p, enable ? 0x01 : 0x00);
652 st = BTM_VendorSpecificCommand (HCI_VENDOR_BLE_RPA_VSC, BTM_BLE_IRK_ENABLE_LEN,
653 param, btm_ble_vendor_irk_vsc_op_cmpl);
657 return BTM_MODE_UNSUPPORTED;
662 /*******************************************************************************
664 ** Function btm_ble_vendor_init
666 ** Description Initialize customer specific feature information in host stack
668 ** Parameters Max IRK list size
669 ** Max filter supported
673 *******************************************************************************/
674 void btm_ble_vendor_init(UINT8 max_irk_list_sz)
676 memset(&btm_ble_vendor_cb, 0, sizeof(tBTM_BLE_VENDOR_CB));
678 #if BLE_PRIVACY_SPT == TRUE
679 if (max_irk_list_sz > 0)
681 btm_ble_vendor_cb.irk_list = (tBTM_BLE_IRK_ENTRY*)GKI_getbuf (sizeof (tBTM_BLE_IRK_ENTRY)
683 btm_ble_vendor_cb.irk_pend_q.irk_q = (BD_ADDR*) GKI_getbuf (sizeof (BD_ADDR) *
685 btm_ble_vendor_cb.irk_pend_q.irk_q_random_pseudo = (BD_ADDR*)GKI_getbuf (sizeof (BD_ADDR) *
687 btm_ble_vendor_cb.irk_pend_q.irk_q_action = (UINT8*) GKI_getbuf (max_irk_list_sz);
690 btm_ble_vendor_cb.irk_avail_size = max_irk_list_sz;
692 if (!HCI_LE_HOST_SUPPORTED(btm_cb.devcb.local_lmp_features[HCI_EXT_FEATURES_PAGE_1]))
697 /*******************************************************************************
699 ** Function btm_ble_vendor_cleanup
701 ** Description Cleanup VSC specific dynamic memory
707 *******************************************************************************/
708 void btm_ble_vendor_cleanup(void)
710 #if BLE_PRIVACY_SPT == TRUE
711 if (btm_ble_vendor_cb.irk_list)
712 GKI_freebuf(btm_ble_vendor_cb.irk_list);
714 if (btm_ble_vendor_cb.irk_pend_q.irk_q)
715 GKI_freebuf(btm_ble_vendor_cb.irk_pend_q.irk_q);
717 if (btm_ble_vendor_cb.irk_pend_q.irk_q_random_pseudo)
718 GKI_freebuf(btm_ble_vendor_cb.irk_pend_q.irk_q_random_pseudo);
720 if (btm_ble_vendor_cb.irk_pend_q.irk_q_action)
721 GKI_freebuf(btm_ble_vendor_cb.irk_pend_q.irk_q_action);
723 memset(&btm_ble_vendor_cb, 0, sizeof(tBTM_BLE_VENDOR_CB));