/******************************************************************************* ** ** Function btm_ble_refresh_peer_resolvable_private_addr ** ** Description This function refresh the currently used resolvable remote private address into security ** database and set active connection address. ** *******************************************************************************/ void btm_ble_refresh_peer_resolvable_private_addr(BD_ADDR pseudo_bda, BD_ADDR rpa, UINT8 rra_type) { #if BLE_PRIVACY_SPT == TRUE UINT8 rra_dummy = FALSE; BD_ADDR dummy_bda = {0}; if (memcmp(dummy_bda, rpa, BD_ADDR_LEN) == 0) { rra_dummy = TRUE; } /* update security record here, in adv event or connection complete process */ tBTM_SEC_DEV_REC *p_sec_rec = btm_find_dev(pseudo_bda); if (p_sec_rec != NULL) { memcpy(p_sec_rec->ble.cur_rand_addr, rpa, BD_ADDR_LEN); /* unknown, if dummy address, set to static */ if (rra_type == BTM_BLE_ADDR_PSEUDO) { p_sec_rec->ble.active_addr_type = rra_dummy ? BTM_BLE_ADDR_STATIC : BTM_BLE_ADDR_RRA; } else { p_sec_rec->ble.active_addr_type = rra_type; } } else { BTM_TRACE_ERROR("No matching known device in record"); return; } BTM_TRACE_DEBUG("%s: active_addr_type: %d ", __func__, p_sec_rec->ble.active_addr_type); /* connection refresh remote address */ tACL_CONN *p_acl = btm_bda_to_acl(p_sec_rec->bd_addr, BT_TRANSPORT_LE); if (p_acl == NULL) { p_acl = btm_bda_to_acl(p_sec_rec->ble.pseudo_addr, BT_TRANSPORT_LE); } if (p_acl != NULL) { if (rra_type == BTM_BLE_ADDR_PSEUDO) { /* use static address, resolvable_private_addr is empty */ if (rra_dummy) { p_acl->active_remote_addr_type = p_sec_rec->ble.static_addr_type; memcpy(p_acl->active_remote_addr, p_sec_rec->ble.static_addr, BD_ADDR_LEN); } else { p_acl->active_remote_addr_type = BLE_ADDR_RANDOM; memcpy(p_acl->active_remote_addr, rpa, BD_ADDR_LEN); } } else { p_acl->active_remote_addr_type = rra_type; memcpy(p_acl->active_remote_addr, rpa, BD_ADDR_LEN); } BTM_TRACE_DEBUG("p_acl->active_remote_addr_type: %d ", p_acl->active_remote_addr_type); BTM_TRACE_DEBUG("%s conn_addr: %02x:%02x:%02x:%02x:%02x:%02x", __func__, p_acl->active_remote_addr[0], p_acl->active_remote_addr[1], p_acl->active_remote_addr[2], p_acl->active_remote_addr[3], p_acl->active_remote_addr[4], p_acl->active_remote_addr[5]); } #endif }
/******************************************************************************* ** ** Function l2cble_notify_le_connection ** ** Description This function notifiy the l2cap connection to the app layer ** ** Returns none ** *******************************************************************************/ void l2cble_notify_le_connection (BD_ADDR bda) { tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr (bda, BT_TRANSPORT_LE); tACL_CONN *p_acl = btm_bda_to_acl(bda, BT_TRANSPORT_LE) ; if (p_lcb != NULL && p_acl != NULL && p_lcb->link_state != LST_CONNECTED) { /* update link status */ btm_establish_continue(p_acl); /* update l2cap link status and send callback */ p_lcb->link_state = LST_CONNECTED; l2cu_process_fixed_chnl_resp (p_lcb); } }
/******************************************************************************* ** ** Function btm_ble_refresh_rra ** ** Description This function refresh the currently used RRA into security ** database and set active connection address. ** *******************************************************************************/ void btm_ble_refresh_rra(BD_ADDR static_bda, BD_ADDR rra) { #if BLE_PRIVACY_SPT == TRUE tBTM_SEC_DEV_REC *p_sec_rec = btm_find_dev_by_public_static_addr(static_bda); tACL_CONN *p_acl = btm_bda_to_acl (p_sec_rec->bd_addr, BT_TRANSPORT_LE); UINT8 rra_dummy = FALSE; BD_ADDR dummy_bda = {0}; BTM_TRACE_ERROR("btm_ble_refresh_rra"); if (memcmp(dummy_bda, rra, BD_ADDR_LEN) == 0) rra_dummy = TRUE; /* connection refresh RRA */ if (p_acl != NULL /* && memcmp(p_acl->active_remote_addr, dummy_bda, BD_ADDR_LEN) == 0 */) { /* use static address, rra is empty */ if (rra_dummy && p_sec_rec != NULL) { p_acl->active_remote_addr_type = p_sec_rec->ble.static_addr_type; memcpy(p_acl->active_remote_addr, p_sec_rec->ble.static_addr, BD_ADDR_LEN); } else { p_acl->active_remote_addr_type = BLE_ADDR_RANDOM; memcpy(p_acl->active_remote_addr, rra, BD_ADDR_LEN); } } /* update security record here, in adv event or connection complete process */ if (p_sec_rec != NULL) { memcpy(p_sec_rec->ble.cur_rand_addr, rra, BD_ADDR_LEN); p_sec_rec->ble.active_addr_type = rra_dummy ? BTM_BLE_ADDR_STATIC: BTM_BLE_ADDR_RRA; } else { BTM_TRACE_ERROR("No matching known device in record"); } #endif }
/******************************************************************************* ** ** Function btm_ble_refresh_local_resolvable_private_addr ** ** Description This function refresh the currently used resolvable private address for the ** active link to the remote device ** *******************************************************************************/ void btm_ble_refresh_local_resolvable_private_addr(BD_ADDR pseudo_addr, BD_ADDR local_rpa) { #if BLE_PRIVACY_SPT == TRUE tACL_CONN *p = btm_bda_to_acl(pseudo_addr, BT_TRANSPORT_LE); BD_ADDR dummy_bda = {0}; if (p != NULL) { if (btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE) { p->conn_addr_type = BLE_ADDR_RANDOM; if (memcmp(local_rpa, dummy_bda, BD_ADDR_LEN)) { memcpy(p->conn_addr, local_rpa, BD_ADDR_LEN); } else { memcpy(p->conn_addr, btm_cb.ble_ctr_cb.addr_mgnt_cb.private_addr, BD_ADDR_LEN); } } else { p->conn_addr_type = BLE_ADDR_PUBLIC; memcpy(p->conn_addr, &controller_get_interface()->get_address()->address, BD_ADDR_LEN); } } #endif }
/******************************************************************************* ** ** Function L2CA_UpdateBleConnParams ** ** Description Update BLE connection parameters. ** ** Parameters: BD Address of remote ** ** Return value: TRUE if update started ** *******************************************************************************/ BOOLEAN L2CA_UpdateBleConnParams (BD_ADDR rem_bda, UINT16 min_int, UINT16 max_int, UINT16 latency, UINT16 timeout) { tL2C_LCB *p_lcb; tACL_CONN *p_acl_cb = btm_bda_to_acl(rem_bda, BT_TRANSPORT_LE); /* See if we have a link control block for the remote device */ p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, BT_TRANSPORT_LE); /* If we don't have one, create one and accept the connection. */ if (!p_lcb || !p_acl_cb) { L2CAP_TRACE_WARNING ("L2CA_UpdateBleConnParams - unknown BD_ADDR %08x%04x", (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5]); return(FALSE); } if (p_lcb->transport != BT_TRANSPORT_LE) { L2CAP_TRACE_WARNING ("L2CA_UpdateBleConnParams - BD_ADDR %08x%04x not LE", (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5]); return(FALSE); } p_lcb->min_interval = min_int; p_lcb->max_interval = max_int; p_lcb->latency = latency; p_lcb->timeout = timeout; p_lcb->conn_update_mask |= L2C_BLE_NEW_CONN_PARAM; l2cble_start_conn_update(p_lcb); return(TRUE); }
/******************************************************************************* ** ** Function bta_dm_pm_cback ** ** Description Conn change callback from sys for low power management ** ** ** Returns void ** *******************************************************************************/ static void bta_dm_pm_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, BD_ADDR peer_addr) { UINT8 i,j; UINT16 policy_setting; tBTM_STATUS btm_status; tBTM_VERSION_INFO vers; UINT8 *p = NULL; #if (BTM_SSR_INCLUDED == TRUE) int index = BTA_DM_PM_SSR0; #endif tBTA_DM_PEER_DEVICE *p_dev; tACL_CONN *p_dev_rec; APPL_TRACE_DEBUG("bta_dm_pm_cback: st(%d), id(%d), app(%d)", status, id, app_id); btm_status = BTM_ReadLocalVersion (&vers); p_dev = bta_dm_find_peer_device(peer_addr); p_dev_rec = btm_bda_to_acl(peer_addr, BT_TRANSPORT_BR_EDR); /* Disable/Enable sniff policy on the SCO link if sco Up/Down. Will be removed in 2.2*/ if ((p_dev) && ((status == BTA_SYS_SCO_OPEN) || (status == BTA_SYS_SCO_CLOSE)) ) { if ((btm_status == BTM_SUCCESS) && (((vers.manufacturer == LMP_COMPID_BROADCOM) && (vers.hci_version < HCI_PROTO_VERSION_2_0)) || (p_dev_rec && (p_dev_rec->lmp_version < 2)))) { if (p_dev_rec) APPL_TRACE_DEBUG("bta_dm_pm_cback:disable sniff for rmt lmp ver:%d",p_dev_rec->lmp_version); bta_dm_pm_set_sniff_policy(p_dev, (status == BTA_SYS_SCO_OPEN)); } } /* find if there is an power mode entry for the service */ for(i=1; i<=p_bta_dm_pm_cfg[0].app_id; i++) { if((p_bta_dm_pm_cfg[i].id == id) && ((p_bta_dm_pm_cfg[i].app_id == BTA_ALL_APP_ID ) || (p_bta_dm_pm_cfg[i].app_id == app_id ))) break; } /* if no entries are there for the app_id and subystem in p_bta_dm_pm_spec*/ if(i> p_bta_dm_pm_cfg[0].app_id) return; /*p_dev = bta_dm_find_peer_device(peer_addr);*/ #if (BTM_SSR_INCLUDED == TRUE) /* set SSR parameters on SYS CONN OPEN */ if((BTA_SYS_CONN_OPEN == status) && p_dev && (p_dev->info & BTA_DM_DI_USE_SSR)) { index = p_bta_dm_pm_spec[p_bta_dm_pm_cfg[i].spec_idx].ssr; } #endif /* if no action for the event */ if(p_bta_dm_pm_spec[p_bta_dm_pm_cfg[i].spec_idx].actn_tbl[status][0].power_mode == BTA_DM_PM_NO_ACTION) { #if (BTM_SSR_INCLUDED == TRUE) if(BTA_DM_PM_SSR0 == index) /* and do not need to set SSR, return. */ #endif return; } for(j=0; j<bta_dm_conn_srvcs.count ; j++) { /* check if an entry already present */ if((bta_dm_conn_srvcs.conn_srvc[j].id == id) && (bta_dm_conn_srvcs.conn_srvc[j].app_id == app_id ) && !bdcmp(bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr, peer_addr)) break; } /* if subsystem has no more preference on the power mode remove the cb */ if(p_bta_dm_pm_spec[p_bta_dm_pm_cfg[i].spec_idx].actn_tbl[status][0].power_mode == BTA_DM_PM_NO_PREF) { if(j != bta_dm_conn_srvcs.count) { bta_dm_conn_srvcs.count--; APPL_TRACE_DEBUG("Removed power mode entry for service id = %d, count = %d", p_bta_dm_pm_cfg[i].id, bta_dm_conn_srvcs.count); for(; j<bta_dm_conn_srvcs.count ; j++) { memcpy(&bta_dm_conn_srvcs.conn_srvc[j], &bta_dm_conn_srvcs.conn_srvc[j+1], sizeof(bta_dm_conn_srvcs.conn_srvc[j])); } } else { APPL_TRACE_WARNING("bta_dm_act no entry for connected service cbs"); return; } } else if(j == bta_dm_conn_srvcs.count ) { /* check if we have more connected service that cbs */ if(bta_dm_conn_srvcs.count == BTA_DM_NUM_CONN_SRVS) { APPL_TRACE_WARNING("bta_dm_act no more connected service cbs"); return; } /* fill in a new cb */ bta_dm_conn_srvcs.conn_srvc[j].id = id; bta_dm_conn_srvcs.conn_srvc[j].app_id = app_id; bdcpy(bta_dm_conn_srvcs.conn_srvc[j].peer_bdaddr, peer_addr); APPL_TRACE_WARNING("new conn_srvc id:%d, app_id:%d", id, app_id); bta_dm_conn_srvcs.count++; bta_dm_conn_srvcs.conn_srvc[j].state = status; APPL_TRACE_WARNING("new conn_srvc id:%d, app_id:%d count:%d", id, app_id, bta_dm_conn_srvcs.count); } else { /* no service is added or removed. only updating status. */ bta_dm_conn_srvcs.conn_srvc[j].state = status; } /* stop timer */ bta_dm_pm_stop_timer(peer_addr); if(p_dev) { p_dev->pm_mode_attempted = 0; p_dev->pm_mode_failed = 0; } #if (BTM_SSR_INCLUDED == TRUE) if(p_bta_dm_ssr_spec[index].max_lat #if (defined BTA_HH_INCLUDED && BTA_HH_INCLUDED == TRUE) || index == BTA_DM_PM_SSR_HH #endif ) { /* If HID connection open is received and SCO is already active. This will handle the case where HID connects when SCO already active */ if ((status == BTA_SYS_CONN_OPEN) && (id == BTA_ID_HH) && bta_dm_pm_is_sco_active()) { APPL_TRACE_DEBUG("bta_dm_pm_cback: SCO is Active, disabling SSR on HID link") APPL_TRACE_WARNING("HID Dev address: %02x:%02x:%02x:%02x:%02x:%02x", peer_addr[0], peer_addr[1], peer_addr[2], peer_addr[3], peer_addr[4], peer_addr[5]); BTM_SetSsrParams(peer_addr, 0, 0, 0); } else { bta_dm_pm_ssr(peer_addr); } } else { if( ((NULL != (p = BTM_ReadLocalFeatures ())) && HCI_SNIFF_SUB_RATE_SUPPORTED(p)) && ((NULL != (p = BTM_ReadRemoteFeatures (peer_addr))) && HCI_SNIFF_SUB_RATE_SUPPORTED(p)) && (index == BTA_DM_PM_SSR0) ) { if (status == BTA_SYS_SCO_OPEN) { APPL_TRACE_DEBUG("bta_dm_pm_cback: SCO is open, reset SSR to zero"); BTM_SetSsrParams (peer_addr, 0,0,0 ); } else if (status == BTA_SYS_SCO_CLOSE) { APPL_TRACE_DEBUG("bta_dm_pm_cback: SCO is close, back to old SSR"); bta_dm_pm_ssr(peer_addr); } } } /* If SCO up/down event is received, then enable/disable SSR on active HID link */ if (btm_status == BTM_SUCCESS && (status == BTA_SYS_SCO_OPEN || status == BTA_SYS_SCO_CLOSE)) { BOOLEAN bScoActive = (status == BTA_SYS_SCO_OPEN); APPL_TRACE_DEBUG("bta_dm_pm_cback: bta_dm_pm_hid_check with bScoActive = %d", bScoActive); bta_dm_pm_hid_check(bScoActive); } #endif bta_dm_pm_set_mode(peer_addr, FALSE); }
/******************************************************************************* ** ** Function l2cble_start_conn_update ** ** Description start BLE connection parameter update process based on status ** ** Parameters: lcb : l2cap link control block ** ** Return value: none ** *******************************************************************************/ static void l2cble_start_conn_update (tL2C_LCB *p_lcb) { UINT16 min_conn_int, max_conn_int, slave_latency, supervision_tout; tBTM_SEC_DEV_REC *p_dev_rec = btm_find_or_alloc_dev(p_lcb->remote_bd_addr); tACL_CONN *p_acl_cb = btm_bda_to_acl(p_lcb->remote_bd_addr, BT_TRANSPORT_LE); if (p_lcb->conn_update_mask & L2C_BLE_UPDATE_PENDING) return; if (p_lcb->conn_update_mask & L2C_BLE_CONN_UPDATE_DISABLE) { /* application requests to disable parameters update. If parameters are already updated, lets set them up to what has been requested during connection establishement */ if (p_lcb->conn_update_mask & L2C_BLE_NOT_DEFAULT_PARAM && /* current connection interval is greater than default min */ p_lcb->min_interval > BTM_BLE_CONN_INT_MIN) { /* use 7.5 ms as fast connection parameter, 0 slave latency */ min_conn_int = max_conn_int = BTM_BLE_CONN_INT_MIN; slave_latency = BTM_BLE_CONN_SLAVE_LATENCY_DEF; supervision_tout = BTM_BLE_CONN_TIMEOUT_DEF; /* if both side 4.1, or we are master device, send HCI command */ if (p_lcb->link_role == HCI_ROLE_MASTER #if (defined BLE_LLT_INCLUDED) && (BLE_LLT_INCLUDED == TRUE) || (HCI_LE_CONN_PARAM_REQ_SUPPORTED(controller_get_interface()->get_features_ble()->as_array) && HCI_LE_CONN_PARAM_REQ_SUPPORTED(p_acl_cb->peer_le_features)) #endif ) { btsnd_hcic_ble_upd_ll_conn_params(p_lcb->handle, min_conn_int, max_conn_int, slave_latency, supervision_tout, 0, 0); p_lcb->conn_update_mask |= L2C_BLE_UPDATE_PENDING; } else { l2cu_send_peer_ble_par_req (p_lcb, min_conn_int, max_conn_int, slave_latency, supervision_tout); } p_lcb->conn_update_mask &= ~L2C_BLE_NOT_DEFAULT_PARAM; p_lcb->conn_update_mask |= L2C_BLE_NEW_CONN_PARAM; } } else { /* application allows to do update, if we were delaying one do it now */ if (p_lcb->conn_update_mask & L2C_BLE_NEW_CONN_PARAM) { /* if both side 4.1, or we are master device, send HCI command */ if (p_lcb->link_role == HCI_ROLE_MASTER #if (defined BLE_LLT_INCLUDED) && (BLE_LLT_INCLUDED == TRUE) || (HCI_LE_CONN_PARAM_REQ_SUPPORTED(controller_get_interface()->get_features_ble()->as_array) && HCI_LE_CONN_PARAM_REQ_SUPPORTED(p_acl_cb->peer_le_features)) #endif ) { btsnd_hcic_ble_upd_ll_conn_params(p_lcb->handle, p_lcb->min_interval, p_lcb->max_interval, p_lcb->latency, p_lcb->timeout, 0, 0); p_lcb->conn_update_mask |= L2C_BLE_UPDATE_PENDING; } else { l2cu_send_peer_ble_par_req (p_lcb, p_lcb->min_interval, p_lcb->max_interval, p_lcb->latency, p_lcb->timeout); } p_lcb->conn_update_mask &= ~L2C_BLE_NEW_CONN_PARAM; p_lcb->conn_update_mask |= L2C_BLE_NOT_DEFAULT_PARAM; } } }