| /****************************************************************************** |
| * |
| * Copyright 2021 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at: |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| ******************************************************************************/ |
| |
| |
| /****************************************************************************** |
| * |
| * This file contains the CSIP Client supporting functions |
| * |
| ******************************************************************************/ |
| |
| #include <log/log.h> |
| #include <string.h> |
| #include <stdio.h> |
| |
| #include <vector> |
| |
| #include "bta_csip_api.h" |
| #include "bta_csip_int.h" |
| #include "bta_gatt_queue.h" |
| |
| #include "osi/include/config.h" |
| #include "btif/include/btif_config.h" |
| #include "stack/crypto_toolbox/crypto_toolbox.h" |
| |
| /* CSIS Characteristic descriptors handles */ |
| #define CSIP_CCCD_UUID_VAL 0x2902 |
| Uuid CSIP_CCCD_UUID = Uuid::From16Bit(CSIP_CCCD_UUID_VAL); |
| |
| /******************************************************************************* |
| * |
| * Function bta_csip_validate_set_params |
| * |
| * Description Validates if set id and its members are valid |
| * |
| * Returns bool. true - if details are valid otherwise false. |
| * |
| ******************************************************************************/ |
| bool bta_csip_validate_set_params(tBTA_SET_LOCK_PARAMS* lock_req) { |
| std::vector<tBTA_CSIP_CSET> *csets = &bta_csip_cb.csets; |
| tBTA_CSIP_CSET cset; |
| bool is_valid_set = false; |
| |
| std::vector<tBTA_CSIP_CSET>::iterator itr; |
| for (itr = csets->begin(); itr != csets->end(); ++itr) { |
| if (lock_req->set_id == itr->set_id) { |
| cset = *itr; |
| is_valid_set = true; |
| break; |
| } |
| } |
| |
| if (!is_valid_set) { |
| LOG(ERROR) << __func__ << ": Invalid Set ID = " << +lock_req->set_id; |
| //TODO: Give Invalid parameters callback |
| return (false); |
| } |
| |
| std::vector<RawAddress> req_members = lock_req->members_addr; |
| // TODO: if requested set members size = 0, return true |
| if ((int)lock_req->members_addr.size() == 0) { |
| LOG(INFO) << __func__<< " Lock of All Set Memebers is requested"; |
| return (true); |
| } |
| |
| std::vector<RawAddress> set_members = cset.set_members; |
| int members_matched = 0; |
| for (int i = 0; i < (int)req_members.size(); i++) { |
| for (int j = 0; j < (int)set_members.size(); j++) { |
| if (req_members[i] == set_members[j]) { |
| members_matched++; |
| break; |
| } |
| } |
| } |
| LOG(INFO) << "set members matched count = " << +members_matched; //debug |
| if (members_matched != (int)req_members.size()) { |
| LOG(ERROR) << __func__ << " Incorrect Set members provided"; |
| return (false); |
| } |
| |
| return (true); |
| } |
| |
| /******************************************************************************* |
| * |
| * Function bta_csip_is_valid_lock_request |
| * |
| * Description Validates lock request parameters received |
| * |
| * Returns bool. true - if details are valid otherwise false. |
| * |
| ******************************************************************************/ |
| bool bta_csip_is_valid_lock_request(tBTA_SET_LOCK_PARAMS* lock_req) { |
| // validate if correct lock value is provided |
| if (lock_req->lock_value != UNLOCK_VALUE && lock_req->lock_value != LOCK_VALUE) { |
| LOG(ERROR) << __func__ << ": Invalid Lock Value."; |
| return (false); |
| } |
| |
| // validate set id |
| if (!bta_csip_validate_set_params(lock_req)) { |
| LOG(INFO) << __func__ << " Invalid params"; |
| return (false); |
| } |
| |
| return (true); |
| } |
| |
| /******************************************************************************* |
| * |
| * Function bta_csip_get_cset_cb |
| * |
| * Description Finds coordinated set control block by set_id |
| * |
| * Returns tBTA_CSET_CB. NULL - if set is not found. |
| * |
| ******************************************************************************/ |
| tBTA_CSET_CB* bta_csip_get_cset_cb_by_id (uint8_t set_id) { |
| int i; |
| tBTA_CSET_CB* cset_cb = &bta_csip_cb.csets_cb[0]; |
| |
| for (i = 0; i < BTA_MAX_SUPPORTED_SETS; i++, cset_cb++) { |
| if ((cset_cb->in_use) && (cset_cb->set_id == set_id)) { |
| return (cset_cb); |
| } |
| } |
| |
| /* no match found */ |
| return (NULL); |
| } |
| |
| /******************************************************************************* |
| * |
| * Function bta_csip_get_cset_cb |
| * |
| * Description Creates new coordinated set control block with next available |
| * set id. |
| * |
| * Returns tBTA_CSET_CB. NULL - if no resources are available for set. |
| * |
| ******************************************************************************/ |
| tBTA_CSET_CB* bta_csip_get_cset_cb () { |
| int i; |
| tBTA_CSET_CB* cset_cb = &bta_csip_cb.csets_cb[0]; |
| |
| for (i = 0; i < BTA_MAX_SUPPORTED_SETS; i++, cset_cb++) { |
| if (!cset_cb->in_use) { |
| cset_cb->set_id = i; |
| cset_cb->in_use = true; |
| return (cset_cb); |
| } |
| } |
| |
| LOG(ERROR) << __func__ << " No resource available for Coordinated set"; |
| return (NULL); |
| } |
| |
| /******************************************************************************** |
| * |
| * Function bta_csip_is_app_reg |
| * |
| * Description Utility function to check if app_id is valid and registered. |
| * |
| * Returns true - if reistered. |
| * false - if invalid app id or its not registered. |
| * |
| *******************************************************************************/ |
| bool bta_csip_is_app_reg(uint8_t app_id) { |
| if (app_id >= BTA_CSIP_MAX_SUPPORTED_APPS) { |
| return (false); |
| } |
| |
| if (bta_csip_cb.app_rcb[app_id].in_use) { |
| return (true); |
| } |
| |
| return (false); |
| } |
| |
| /******************************************************************************** |
| * |
| * Function bta_csip_get_rcb |
| * |
| * Description Utility function to check if app_id is valid and registered. |
| * |
| * Returns registration control block. NULL if not in use. |
| * |
| *******************************************************************************/ |
| tBTA_CSIP_RCB* bta_csip_get_rcb (uint8_t app_id) { |
| if (app_id >= BTA_CSIP_MAX_SUPPORTED_APPS) { |
| return (NULL); |
| } |
| |
| if (bta_csip_cb.app_rcb[app_id].in_use) { |
| return (&bta_csip_cb.app_rcb[app_id]); |
| } |
| |
| return (NULL); |
| } |
| |
| /******************************************************************************* |
| * |
| * Function bta_csip_get_coordinated_set |
| * |
| * Description Creates new coordinated set control block |
| * |
| * Returns tBTA_CSIP_CSET for valid set_id. |
| * Empty set with INVALID_SET_ID if not found. |
| * |
| ******************************************************************************/ |
| tBTA_CSIP_CSET bta_csip_get_coordinated_set (uint8_t set_id) { |
| for (tBTA_CSIP_CSET cset: bta_csip_cb.csets) { |
| if (cset.set_id == set_id) { |
| return cset; |
| } |
| } |
| |
| LOG(ERROR) << __func__ << "Coordinated set not found for set_id: " << +set_id; |
| tBTA_CSIP_CSET cset = {.set_id = INVALID_SET_ID, |
| .size = 0 |
| }; |
| return cset; |
| } |
| |
| /****************************************************************************** |
| * |
| * Function bta_csip_update_set_member |
| * |
| * Description Updates set member in the given set. |
| * |
| * Returns bool (true, if added successfully. Otherwise, false.) |
| * |
| ******************************************************************************/ |
| bool bta_csip_update_set_member (uint8_t set_id, RawAddress addr) { |
| for (tBTA_CSIP_CSET& cset: bta_csip_cb.csets) { |
| if (cset.set_id == set_id) { |
| if (cset.set_members.size() == cset.size) { |
| LOG(ERROR) << __func__ << " All Set members already discovered."; |
| return false; |
| } |
| cset.set_members.push_back(addr); |
| return true; |
| } |
| } |
| |
| LOG(ERROR) << __func__ << "Coordinated set not found for set_id: " << +set_id; |
| return false; |
| } |
| |
| /******************************************************************************* |
| * |
| * Function bta_csip_remove_set_member |
| * |
| * Description Removes set member from given coordinated set after unpairing. |
| * If its the last set member in set, coordinated set is deleted. |
| * |
| * Returns void |
| * |
| ******************************************************************************/ |
| void bta_csip_remove_set_member (RawAddress addr) { |
| LOG(INFO) << __func__ << " Device = " << addr.ToString(); |
| bool is_device_found = false; |
| |
| btif_config_remove(addr.ToString().c_str(), "DGroup"); |
| tBTA_CSIP_DEV_CB* p_cb = bta_csip_find_dev_cb_by_bda(addr); |
| if (!p_cb) { |
| APPL_TRACE_DEBUG("%s: Set Member not found", __func__); |
| return; |
| } |
| |
| tBTA_CSIS_SRVC_INFO* srvc = &p_cb->csis_srvc[0]; |
| for (int i = 0; i < MAX_SUPPORTED_SETS_PER_DEVICE && !is_device_found; i++, srvc++) { |
| if (!srvc->in_use) continue; |
| for (tBTA_CSIP_CSET& cset: bta_csip_cb.csets) { |
| if (cset.set_id == srvc->set_id) { |
| //std::remove(cset.set_members.begin(), cset.set_members.end(), addr); |
| cset.set_members.erase( |
| std::remove_if(cset.set_members.begin(), cset.set_members.end(), |
| [&](RawAddress const & bdaddr) { |
| return bdaddr == addr; |
| }), |
| cset.set_members.end()); |
| is_device_found = true; |
| LOG(INFO) << __func__ << " Size = " << +(int)cset.set_members.size(); |
| if (cset.set_members.empty()) { |
| tBTA_CSET_CB* cset_cb = bta_csip_get_cset_cb_by_id(cset.set_id); |
| if (cset_cb) { |
| LOG(INFO) << __func__ << " Invalidating set. Last member unpaired."; |
| cset_cb->in_use = false; |
| cset_cb->set_id = INVALID_SET_ID; |
| cset.set_members.clear(); |
| bta_csip_cb.csets.erase( |
| std::remove_if(bta_csip_cb.csets.begin(), |
| bta_csip_cb.csets.end(), [&](tBTA_CSIP_CSET& cs) { |
| return cs.set_id == srvc->set_id; |
| }), |
| bta_csip_cb.csets.end()); |
| } |
| } |
| break; |
| } |
| } |
| } |
| |
| bta_csip_cb.dev_cb.erase( |
| std::remove_if(bta_csip_cb.dev_cb.begin(), bta_csip_cb.dev_cb.end(), |
| [&](tBTA_CSIP_DEV_CB const &dev_cb) { |
| return dev_cb.addr == addr; |
| }), |
| bta_csip_cb.dev_cb.end()); |
| } |
| |
| /******************************************************************************* |
| * |
| * Function bta_csip_get_or_create_cset |
| * |
| * Description API used to create Coordinated Set Control block. |
| * |
| * Returns void |
| * |
| ******************************************************************************/ |
| tBTA_CSIP_CSET* bta_csip_get_or_create_cset (uint8_t set_id, bool existing) { |
| /*std::find_if(bta_csip_cb.csets.begin(), bta_csip_cb.csets.end(), |
| [&set_id](const tBTA_CSIP_CSET& set) { |
| return set.set_id == set_id; |
| });*/ |
| |
| for (tBTA_CSIP_CSET& cset: bta_csip_cb.csets) { |
| if (cset.set_id == set_id) { |
| return &cset; |
| } |
| } |
| |
| if (existing) return NULL; |
| |
| /* Create a new set with invalid set_id*/ |
| tBTA_CSIP_CSET cset = {.set_id = INVALID_SET_ID, |
| .size = 0 |
| }; |
| bta_csip_cb.csets.push_back(cset); |
| return &bta_csip_cb.csets.back(); |
| } |
| |
| /******************************************************************************* |
| * |
| * Function bta_csip_find_set_id_by_sirk |
| * |
| * Description Finds Coordinated set control block by sirk |
| * |
| * Returns set_id if SIRK is found |
| * otherwise, INVALID_SET_ID |
| * |
| ******************************************************************************/ |
| uint8_t bta_csip_find_set_id_by_sirk (uint8_t* sirk) { |
| int i = 0; |
| tBTA_CSET_CB* csets = &bta_csip_cb.csets_cb[0]; |
| |
| for (i = 0; i < BTA_MAX_SUPPORTED_SETS; i++, csets++) { |
| if (csets->in_use) { |
| // compare SIRK's |
| if (!memcmp(sirk, csets->sirk, SIRK_SIZE)) { |
| return csets->set_id; |
| } |
| } |
| } |
| |
| return INVALID_SET_ID; |
| } |
| |
| |
| /******************************************************************************* |
| * |
| * Function bta_csip_get_cset_cb |
| * |
| * Description Finds coordinated set control block by set_id |
| * |
| * Returns tBTA_CSET_CB. NULL - if set is not found. |
| * |
| ******************************************************************************/ |
| tBTA_CSIS_SRVC_INFO* bta_csip_get_csis_instance(tBTA_CSIP_DEV_CB* dev_cb, |
| uint8_t set_id) { |
| int i = 0; |
| |
| if (!dev_cb) return NULL; |
| |
| tBTA_CSIS_SRVC_INFO* srvc = &dev_cb->csis_srvc[0]; |
| |
| for (i = 0; i < MAX_SUPPORTED_SETS_PER_DEVICE; i++, srvc++) { |
| srvc = &dev_cb->csis_srvc[i]; |
| if ((srvc->in_use) && (srvc->set_id == set_id)) { |
| return (srvc); |
| } |
| } |
| |
| /* no match found */ |
| return (NULL); |
| } |
| |
| /******************************************************************************* |
| * |
| * Function bta_csip_get_csis_service_cb |
| * |
| * Description Creates new coordinated set control block for a given device |
| * |
| * Returns tBTA_CSET_CB. NULL if no resources available. |
| * |
| ******************************************************************************/ |
| tBTA_CSIS_SRVC_INFO* bta_csip_get_csis_service_cb(tBTA_CSIP_DEV_CB* dev_cb) { |
| int i = 0; |
| tBTA_CSIS_SRVC_INFO* srvc = &dev_cb->csis_srvc[0]; |
| |
| for (i = 0; i < MAX_SUPPORTED_SETS_PER_DEVICE; i++, srvc++) { |
| if (!srvc->in_use) { |
| srvc->in_use = true; |
| return srvc; |
| } |
| } |
| |
| /* no match found */ |
| return (NULL); |
| } |
| |
| /******************************************************************************* |
| * |
| * Function bta_csip_is_csis_supported |
| * |
| * Description checks if remote device supports coordinated set |
| * |
| * Returns true if supported, otherwise false. |
| * |
| ******************************************************************************/ |
| bool bta_csip_is_csis_supported(tBTA_CSIP_DEV_CB* dev_cb) { |
| int i = 0; |
| tBTA_CSIS_SRVC_INFO* srvc = &dev_cb->csis_srvc[0]; |
| |
| for (i = 0; i < MAX_SUPPORTED_SETS_PER_DEVICE; i++, srvc++) { |
| if (srvc->in_use) { |
| return true; |
| } |
| } |
| |
| /* no csis instance found */ |
| return (false); |
| } |
| |
| /******************************************************************************* |
| * |
| * Function bta_csip_get_csis_service_by_handle |
| * |
| * Description Gives CSIS Service Control block by service handle. |
| * |
| * Returns CSIS Service control block. Null if not found. |
| * |
| ******************************************************************************/ |
| tBTA_CSIS_SRVC_INFO* bta_csip_get_csis_service_by_handle( |
| tBTA_CSIP_DEV_CB* dev_cb, uint16_t service_handle) { |
| int i = 0; |
| tBTA_CSIS_SRVC_INFO* srvc = &dev_cb->csis_srvc[0]; |
| |
| for (i = 0; i < MAX_SUPPORTED_SETS_PER_DEVICE; i++, srvc++) { |
| if (srvc->in_use && srvc->service_handle == service_handle) { |
| return srvc; |
| } |
| } |
| |
| /* no match found */ |
| return (NULL); |
| } |
| |
| /******************************************************************************* |
| * |
| * Function bta_csip_find_csis_srvc_by_lock_handle |
| * |
| * Description Gives CSIS Service Control block by lock handle. |
| * |
| * Returns CSIS Service control block. Null if not found. |
| * |
| ******************************************************************************/ |
| tBTA_CSIS_SRVC_INFO* bta_csip_find_csis_srvc_by_lock_handle( |
| tBTA_CSIP_DEV_CB* dev_cb, uint16_t lock_handle) { |
| int i = 0; |
| tBTA_CSIS_SRVC_INFO* srvc = &dev_cb->csis_srvc[0]; |
| |
| for (i = 0; i < MAX_SUPPORTED_SETS_PER_DEVICE; i++, srvc++) { |
| if (srvc->in_use && srvc->lock_handle == lock_handle) { |
| return srvc; |
| } |
| } |
| |
| /* no match found */ |
| return (NULL); |
| |
| } |
| |
| /******************************************************************************* |
| * |
| * Function bta_csip_is_locked_by_other_apps |
| * |
| * Description Checks if set is locked by app other than mentioned one. |
| * |
| * Returns true, if locked by other app otherwise false. |
| * |
| ******************************************************************************/ |
| bool bta_csip_is_locked_by_other_apps(tBTA_CSIS_SRVC_INFO* srvc, uint8_t app_id) { |
| std::vector<uint8_t> &lock_applist = srvc->lock_applist; |
| |
| for (auto& it : lock_applist) { |
| if (it != app_id) { |
| return (true); |
| } |
| } |
| |
| return (false); |
| } |
| |
| /******************************************************************************* |
| * |
| * Function bta_csip_form_set_lock_order |
| * |
| * Description Forms order of set members as per rank. |
| * |
| * Returns Ordered Set members. |
| * |
| ******************************************************************************/ |
| std::vector<RawAddress> bta_csip_form_set_lock_order(tBTA_CSET_CB* cset_cb) { |
| std::vector<RawAddress> ordered_members; |
| std::vector<RawAddress> req_members = cset_cb->cur_lock_req.members_addr; |
| std::map<uint8_t, RawAddress> lock_order_map; |
| |
| for (int i = 0; i < (int)req_members.size(); i++) { |
| // get device control block and corresponding csis service details |
| tBTA_CSIP_DEV_CB* dev_cb = bta_csip_find_dev_cb_by_bda(req_members[i]); |
| // null checks required |
| tBTA_CSIS_SRVC_INFO* srvc = |
| bta_csip_get_csis_instance(dev_cb, cset_cb->cur_lock_req.set_id); |
| if (srvc) { |
| lock_order_map.insert({srvc->rank, req_members[i]}); |
| } |
| } |
| |
| for (auto itr: lock_order_map) { |
| ordered_members.push_back(itr.second); |
| } |
| |
| return ordered_members; |
| } |
| |
| /******************************************************************************* |
| * |
| * Function bta_csip_arrange_set_members_by_order |
| * |
| * Description Forms order of set members for LOCK/UNLOCK request. |
| * |
| * Returns Ordered set members in vector. |
| * |
| ******************************************************************************/ |
| std::vector<RawAddress> bta_csip_arrange_set_members_by_order( |
| uint8_t set_id, std::vector<RawAddress>& req_sm, bool ascending) { |
| LOG(INFO) << __func__; |
| |
| std::vector<RawAddress> ordered_req_sm; |
| std::vector<RawAddress> set_members = |
| bta_csip_get_set_member_by_order(set_id, ascending); |
| |
| // Check if all set members are requested |
| if ((uint8_t)req_sm.size() == 0) { |
| LOG(INFO) << __func__ << " original size = " << +set_members.size(); |
| return set_members; |
| } |
| |
| /* LOCK Request Order*/ |
| for (int i = 0; i < (int)set_members.size(); i++) { |
| for (int j = 0; j < (int)req_sm.size(); j++) { |
| if (set_members[i] == req_sm[j]) { |
| ordered_req_sm.push_back(set_members[i]); |
| if (ordered_req_sm.size() == req_sm.size()) { |
| return ordered_req_sm; |
| } |
| } |
| } |
| } |
| |
| return {}; |
| } |
| |
| /******************************************************************************* |
| * |
| * Function bta_csip_arrange_set_members_by_order |
| * |
| * Description Forms order of set members for LOCK/UNLOCK request. |
| * |
| * Returns Ordered set members in vector. |
| * |
| ******************************************************************************/ |
| std::vector<RawAddress> bta_csip_get_set_member_by_order(uint8_t set_id, |
| bool ascending) { |
| std::vector<RawAddress> ordered_members; |
| |
| tBTA_CSET_CB* cset_cb = &bta_csip_cb.csets_cb[set_id]; |
| if (!cset_cb->in_use) { |
| LOG(ERROR) << __func__ << " Invalid Set for for Set ID: " << +set_id; |
| return {}; |
| } |
| |
| if (ascending) { |
| for (auto itr: cset_cb->ordered_members) { |
| ordered_members.push_back(itr.second); |
| } |
| } else { |
| for (auto i = cset_cb->ordered_members.rbegin(); |
| i != cset_cb->ordered_members.rend(); ++i) { |
| ordered_members.push_back(i->second); |
| } |
| } |
| |
| return ordered_members; |
| } |
| |
| |
| /******************************************************************************* |
| * |
| * Function bta_csip_is_member_locked_by_app |
| * |
| * Description checks if application (app_id) has locked given set. |
| * |
| * Returns void. |
| ******************************************************************************/ |
| bool bta_csip_is_member_locked_by_app (uint8_t app_id, tBTA_CSIS_SRVC_INFO* srvc) { |
| std::vector<uint8_t>& lock_applist = srvc->lock_applist; |
| |
| auto it = std::find(lock_applist.begin(), lock_applist.end(), app_id); |
| if (it != lock_applist.end()) { |
| LOG(INFO) << __func__ << " App Id found in app list"; |
| return true; |
| } |
| |
| LOG(INFO) << __func__ << " App Id not found in app list"; |
| return false; |
| } |
| |
| /******************************************************************************* |
| * |
| * Function bta_csip_handle_unresponsive_sm_res |
| * |
| * Description sends lock response to earlier requesting app. |
| * |
| * Returns void. |
| ******************************************************************************/ |
| void bta_csip_handle_unresponsive_sm_res(tBTA_CSIS_SRVC_INFO* srvc, |
| tGATT_STATUS status) { |
| LOG(INFO) << __func__ << " Response from unresponsive remote " << srvc->bd_addr.ToString() |
| << " status: " << +status; |
| std::vector<uint8_t>& unres_applist = srvc->unrsp_applist; |
| |
| if (status == GATT_SUCCESS) { |
| srvc->lock = LOCK_VALUE; |
| for (auto& it : unres_applist) { |
| LOG(INFO) << __func__ << " Sending GATT_SUCCESS callback to app: " << +it; |
| std::vector<RawAddress> sm = {srvc->bd_addr}; |
| tBTA_LOCK_STATUS_CHANGED res = {.app_id = it, .set_id = srvc->set_id, |
| .value = 0x02, .addr = sm}; |
| bta_csip_send_lock_req_cmpl_cb(res); |
| // Add app id to the lock applist |
| srvc->lock_applist.push_back(it); |
| } |
| } |
| |
| unres_applist.clear(); |
| } |
| |
| /******************************************************************************* |
| * |
| * Function bta_csip_get_next_lock_request |
| * |
| * Description Schedules next pending lock request for the given set. |
| * |
| * Returns void. |
| ******************************************************************************/ |
| void bta_csip_get_next_lock_request(tBTA_CSET_CB* cset_cb) { |
| tBTA_SET_LOCK_PARAMS lock_req_params; |
| std::queue<tBTA_SET_LOCK_PARAMS>& lock_req_queue = cset_cb->lock_req_queue; |
| |
| if (lock_req_queue.empty()) { |
| LOG(INFO) << " No pending Lock Request for Set: " << +cset_cb->set_id; |
| cset_cb->request_in_progress = false; |
| return; |
| } |
| |
| lock_req_params = lock_req_queue.front(); |
| lock_req_queue.pop(); |
| |
| bta_csip_form_lock_request(lock_req_params, cset_cb); |
| } |
| |
| /******************************************************************************* |
| * |
| * Function bta_csip_find_dev_cb_by_bda |
| * |
| * Description Utility function find a device control block by BD address. |
| * |
| * Returns tBTA_CSIP_DEV_CB - device control block for a given remote. |
| * nullptr, if device control block is not present. |
| ******************************************************************************/ |
| tBTA_CSIP_DEV_CB* bta_csip_find_dev_cb_by_bda(const RawAddress& bda) { |
| /*auto iter = std::find_if(bta_csip_cb.dev_cb.begin(), bta_csip_cb.dev_cb.end(), |
| [&bda](const tBTA_CSIP_DEV_CB& device) { |
| return device.addr == bda; |
| }); |
| |
| return (iter == bta_csip_cb.dev_cb.end()) ? nullptr : &(*iter);*/ |
| for (tBTA_CSIP_DEV_CB& p_cb: bta_csip_cb.dev_cb) { |
| if (p_cb.addr == bda) { |
| return &p_cb; |
| } |
| } |
| |
| return NULL; |
| } |
| |
| /******************************************************************************* |
| * |
| * Function bta_csip_get_dev_cb_by_cid |
| * |
| * Description Utility function find a device control block by gatt conn id. |
| * |
| * Returns tBTA_CSIP_DEV_CB (device control block for a given remote.) |
| ******************************************************************************/ |
| tBTA_CSIP_DEV_CB* bta_csip_get_dev_cb_by_cid(uint16_t conn_id) { |
| auto iter = std::find_if(bta_csip_cb.dev_cb.begin(), bta_csip_cb.dev_cb.end(), |
| [&conn_id](const tBTA_CSIP_DEV_CB& device) { |
| return device.conn_id == conn_id; |
| }); |
| |
| return (iter == bta_csip_cb.dev_cb.end()) ? nullptr : &(*iter); |
| } |
| |
| /******************************************************************************* |
| * |
| * Function bta_csip_create_dev_cb_for_bda |
| * |
| * Description Utility function find a device control block by BD address. |
| * |
| * Returns tBTA_CSIP_DEV_CB (device control block for a given remote. |
| ******************************************************************************/ |
| tBTA_CSIP_DEV_CB* bta_csip_create_dev_cb_for_bda(const RawAddress& bda) { |
| tBTA_CSIP_DEV_CB p_dev_cb = {}; |
| p_dev_cb.addr = bda; |
| p_dev_cb.in_use = true; |
| |
| bta_csip_cb.dev_cb.push_back(p_dev_cb); |
| |
| return &bta_csip_cb.dev_cb.back(); |
| } |
| |
| /************************************************************************************ |
| * |
| * Function bta_csip_get_cccd_handle |
| * |
| * Description Utility function to fetch cccd handle of a given characteristic. |
| * |
| * Returns handle of cccd. 0 if not found. |
| ************************************************************************************/ |
| uint16_t bta_csip_get_cccd_handle(uint16_t conn_id, uint16_t char_handle) { |
| const gatt::Characteristic* p_char = |
| BTA_GATTC_GetCharacteristic(conn_id, char_handle); |
| if (!p_char) { |
| LOG(WARNING) << __func__ << ": Characteristic not found: " << char_handle; |
| return 0; |
| } |
| |
| for (const gatt::Descriptor& desc : p_char->descriptors) { |
| if (desc.uuid == CSIP_CCCD_UUID) { |
| LOG(INFO) << __func__ << " desc handle = " << +desc.handle; |
| return desc.handle; |
| } |
| } |
| |
| return 0; |
| } |
| |
| /************************************************************************************ |
| * |
| * Function bta_csip_add_app_to_applist |
| * |
| * Description Utility function adds app to connection applist of a |
| * given device control block. |
| * |
| * Returns void |
| ************************************************************************************/ |
| void bta_csip_add_app_to_applist(tBTA_CSIP_DEV_CB* p_cb, uint8_t app_id) { |
| if (p_cb && !bta_csip_is_app_from_applist(p_cb, app_id)) { |
| LOG(INFO) << __func__ << ": adding app(" << +app_id |
| << ") to connection applist of " << p_cb->addr; |
| p_cb->conn_applist.push_back(app_id); |
| } |
| } |
| |
| /************************************************************************************ |
| * |
| * Function bta_csip_is_app_from_applist |
| * |
| * Description Utility function checks if app is from connection applist of a |
| * given device control block. |
| * |
| * Returns true if app has already sent connect request for CSIP. |
| ************************************************************************************/ |
| bool bta_csip_is_app_from_applist(tBTA_CSIP_DEV_CB* p_cb, uint8_t app_id) { |
| for (auto i: p_cb->conn_applist) { |
| if (i == app_id) { |
| return (true); |
| } |
| } |
| |
| return (false); |
| } |
| |
| /************************************************************************************ |
| * |
| * Function bta_csip_remove_app_from_conn_list |
| * |
| * Description Utility function to remove application from connection applist of |
| * given device control block |
| * |
| * Returns void |
| ************************************************************************************/ |
| void bta_csip_remove_app_from_conn_list(tBTA_CSIP_DEV_CB* p_cb, uint8_t app_id) { |
| p_cb->conn_applist.erase( |
| std::remove(p_cb->conn_applist.begin(), p_cb->conn_applist.end(), app_id), |
| p_cb->conn_applist.end()); |
| } |
| |
| /************************************************************************************ |
| * |
| * Function bta_csip_send_conn_state_changed_cb |
| * |
| * Description Utility function to send connection state changed to all |
| * registered application in connection app list. |
| * |
| * Returns void |
| ************************************************************************************/ |
| void bta_csip_send_conn_state_changed_cb(tBTA_CSIP_DEV_CB* p_cb, |
| uint8_t state, uint8_t status) { |
| if (!p_cb) { |
| LOG(ERROR) << __func__ << ": Device CB for " << p_cb->addr << " not found"; |
| return; |
| } |
| |
| // send connection state change to all apps in conn_applist |
| for (auto i: p_cb->conn_applist) { |
| tBTA_CSIP_CONN_STATE_CHANGED conn_cb_params = { |
| .app_id = i, |
| .addr = p_cb->addr, |
| .state = state, |
| .status =status |
| }; |
| if (bta_csip_cb.app_rcb[i].p_cback) { |
| (*bta_csip_cb.app_rcb[i].p_cback) |
| (BTA_CSIP_CONN_STATE_CHG_EVT, (tBTA_CSIP_DATA *)&conn_cb_params); |
| } |
| } |
| } |
| |
| /************************************************************************************ |
| * |
| * Function bta_csip_send_conn_state_changed_cb |
| * |
| * Description Utility function to send connection state changed to requesting |
| * registered application from connection applist. |
| * |
| * Returns void |
| ************************************************************************************/ |
| void bta_csip_send_conn_state_changed_cb (tBTA_CSIP_DEV_CB* p_cb, uint8_t app_id, |
| uint8_t state, uint8_t status) { |
| |
| tBTA_CSIP_CONN_STATE_CHANGED conn_cb_params = { |
| .app_id = app_id, |
| .addr = p_cb->addr, |
| .state = state, |
| .status =status |
| }; |
| |
| // send connection state change to the requested App |
| if (bta_csip_cb.app_rcb[app_id].p_cback) { |
| (*bta_csip_cb.app_rcb[app_id].p_cback) |
| (BTA_CSIP_CONN_STATE_CHG_EVT, (tBTA_CSIP_DATA *)&conn_cb_params); |
| } |
| |
| } |
| |
| /************************************************************************************ |
| * |
| * Function bta_csip_process_completed_lock_req |
| * |
| * Description Utility function to send lock state changed to requesting |
| * registered application. |
| * |
| * Returns void |
| ************************************************************************************/ |
| void bta_csip_send_lock_req_cmpl_cb (tBTA_LOCK_STATUS_CHANGED response) { |
| if (response.app_id >= BTA_CSIP_MAX_SUPPORTED_APPS || |
| !bta_csip_cb.app_rcb[response.app_id].in_use) { |
| LOG(ERROR) << __func__ << "Invalid or unregistered application: " << +response.app_id; |
| return; |
| } |
| |
| if (bta_csip_cb.app_rcb[response.app_id].p_cback) { |
| (*bta_csip_cb.app_rcb[response.app_id].p_cback) |
| (BTA_CSIP_LOCK_STATUS_CHANGED_EVT, (tBTA_CSIP_DATA *)&response); |
| } |
| } |
| |
| /************************************************************************************ |
| * |
| * Function bta_csip_write_cccd |
| * |
| * Description API used to write required characteristic descriptor. |
| * |
| * Returns void |
| ************************************************************************************/ |
| void bta_csip_write_cccd (tBTA_CSIP_DEV_CB* p_cb, uint16_t char_handle, |
| uint16_t cccd_handle) { |
| LOG(INFO) << __func__; |
| // Register for LOCK |
| if (BTA_GATTC_RegisterForNotifications( |
| bta_csip_cb.gatt_if, p_cb->addr, char_handle)) { |
| LOG(ERROR) << __func__ |
| << " Notification Registration failed for char handle: " << +char_handle; |
| return; |
| } |
| |
| LOG(INFO) << __func__ << " notification registration successful. handle: " << +char_handle; |
| std::vector<uint8_t> value(2); |
| uint8_t* ptr = value.data(); |
| UINT16_TO_STREAM(ptr, GATT_CHAR_CLIENT_CONFIG_NOTIFICATION); |
| BtaGattQueue::WriteDescriptor(p_cb->conn_id, cccd_handle, value, |
| GATT_WRITE, nullptr, nullptr); |
| } |
| |
| /************************************************************************************ |
| * |
| * Function bta_csip_load_coordinated_sets_from_storage |
| * |
| * Description API used to load coordinated sets from storage on BT ON. |
| * |
| * Returns void |
| ************************************************************************************/ |
| void bta_csip_load_coordinated_sets_from_storage () { |
| LOG(INFO) << __func__; |
| |
| static const char* CONFIG_FILE_PATH = "/data/misc/bluedroid/bt_config.conf"; |
| config_t* config = config_new(CONFIG_FILE_PATH); |
| if (!config) { |
| LOG(INFO) << __func__ << " file "<< CONFIG_FILE_PATH << " not found"; |
| return; |
| } |
| |
| const config_section_node_t* snode = config_section_begin(config); |
| while (snode != config_section_end(config)) { |
| |
| const char* name = config_section_name(snode); |
| if (!RawAddress::IsValidAddress(name)) { |
| snode = config_section_next(snode); |
| continue; |
| } |
| |
| const char* key = "DGroup"; |
| const char* coordinated_sets = config_get_string(config, name, key, ""); |
| if (!strcmp(coordinated_sets, "")) { |
| LOG(INFO) << __func__ << " doesnt support cooedinated set."; |
| snode = config_section_next(snode); |
| continue; |
| } |
| |
| RawAddress bdaddr; |
| RawAddress::FromString(name, bdaddr); |
| tBTA_CSIP_DEV_CB* dev_cb = bta_csip_find_dev_cb_by_bda(bdaddr); |
| if (!dev_cb) { |
| dev_cb = bta_csip_create_dev_cb_for_bda(bdaddr); |
| } |
| |
| char *next = NULL; |
| char *csets = strdup(coordinated_sets); |
| /* Set Level parsing*/ |
| char *set_details = strtok_r(csets, " ", &next); |
| |
| do { |
| tBTA_CSIP_CSET *cset = NULL; |
| uint8_t set_id = INVALID_SET_ID, size = 0, rank = 0; |
| uint16_t srvc_handle = 0; |
| bluetooth::Uuid uuid; |
| uint8_t sirk[SIRK_SIZE] = {}; |
| bool lock_support = false; |
| |
| char *part; |
| char *posn; |
| /* separating properties of set*/ |
| part = strtok_r(set_details, "~", &posn); |
| |
| while (part != NULL) |
| { |
| char *ptr = NULL; |
| /* Decode property type and its value*/ |
| char *prop_details = strtok_r(part, ":", &ptr); |
| |
| if (prop_details != NULL) { |
| char* prop_val = strtok_r(NULL, ":", &ptr); |
| if (prop_val) { |
| if (!strcmp(prop_details, "SET_ID")) { |
| set_id = (uint8_t)atoi(prop_val); |
| cset = bta_csip_get_or_create_cset(set_id, true); |
| if (!cset) LOG(INFO) << __func__ << " got cset empty"; |
| else LOG(INFO) << "valid " << +cset->set_id; |
| } else if (!strcmp(prop_details, "SIZE")) { |
| size = (uint8_t)atoi(prop_val); |
| } else if (!strcmp(prop_details, "SIRK")) { |
| hex_string_to_byte_arr(prop_val, sirk, SIRK_SIZE * 2); |
| } else if (!strcmp(prop_details, "INCLUDING_SRVC")) { |
| uuid = Uuid::FromString(prop_val); |
| } else if (!strcmp(prop_details, "LOCK_SUPPORT")) { |
| if (!strcmp(prop_val, "true")) lock_support = true; |
| } else if (!strcmp(prop_details, "RANK")) { |
| rank = (uint8_t)atoi(prop_val); |
| } else if (!strcmp(prop_details, "SRVC_HANDLE")) { |
| srvc_handle = (uint16_t)atoi(prop_val); |
| } |
| } |
| } |
| |
| part = strtok_r(NULL, "~", &posn); |
| } |
| |
| if (set_id < BTA_MAX_SUPPORTED_SETS) { |
| if (!cset) { |
| // Create new coordinated set insatnce and device to it |
| cset = bta_csip_get_or_create_cset(set_id, false); |
| cset->set_id = set_id; |
| cset->size = size; |
| cset->p_srvc_uuid = uuid; |
| cset->total_discovered = 1; |
| cset->set_members.push_back(bdaddr); |
| |
| // create coordinated set control block |
| tBTA_CSET_CB* cset_cb = &bta_csip_cb.csets_cb[set_id]; |
| cset_cb->set_id = set_id; |
| cset_cb->in_use = true; |
| memcpy(cset_cb->sirk, sirk, SIRK_SIZE); |
| if (rank != 0) { |
| cset_cb->ordered_members.insert({rank, bdaddr}); |
| } |
| |
| } else { |
| //LOG(INFO) << "Existing set = " << +cset->set_id; |
| cset->total_discovered++; |
| cset->set_members.push_back(bdaddr); |
| |
| tBTA_CSET_CB* cset_cb = &bta_csip_cb.csets_cb[set_id]; |
| if (rank != 0) { |
| cset_cb->ordered_members.insert({rank, bdaddr}); |
| } |
| } |
| |
| // assign service properties - set_id and bd_addr |
| tBTA_CSIS_SRVC_INFO *srvc = bta_csip_get_csis_service_cb(dev_cb); |
| if (srvc) { |
| srvc->set_id = set_id; |
| srvc->bd_addr = bdaddr; |
| srvc->size = size; |
| srvc->rank = rank; |
| srvc->service_handle = srvc_handle; |
| memcpy(srvc->sirk, sirk, SIRK_SIZE); |
| } |
| } |
| } while ((set_details = strtok_r(NULL, " ", &next)) != NULL); |
| |
| snode = config_section_next(snode); |
| } |
| |
| /*LOG(INFO) << "------------------DEBUG----------------------------"; |
| LOG(INFO) << "printing all loaded coordinated sets"; |
| for (int i = 0; i < (int)bta_csip_cb.csets.size(); i++) { |
| tBTA_CSIP_CSET set = bta_csip_cb.csets[i]; |
| LOG(INFO) << " Set ID = " << +set.set_id |
| << " Size = " << +set.size |
| << " total discovered = " << +set.total_discovered; |
| for (int j = 0; j < (int)set.set_members.size(); j++) { |
| LOG(INFO) << " Member (" << +(j+1) <<") = " << set.set_members[j].ToString(); |
| } |
| }*/ |
| } |
| |
| /************************************************************************************ |
| * |
| * Function bta_csip_preserve_cset |
| * |
| * Description function used to preserve coordinated set details to storage. |
| * |
| * Returns void |
| ************************************************************************************/ |
| void bta_csip_preserve_cset (tBTA_CSIS_SRVC_INFO* srvc) { |
| tBTA_CSIP_DEV_CB* p_cb = bta_csip_find_dev_cb_by_bda(srvc->bd_addr); |
| |
| if (!p_cb) { |
| LOG(ERROR) << " Device cb record not found for " << srvc->bd_addr; |
| return; |
| } |
| |
| std::string& set_info = p_cb->set_info; |
| if (set_info.size() > 0) { |
| set_info += " "; |
| } |
| |
| set_info += "SET_ID:" + std::to_string(srvc->set_id); |
| |
| if (srvc->size_handle) { |
| set_info += "~SIZE:" + std::to_string(srvc->size); |
| } |
| |
| char sirk[SIRK_SIZE * 2 + 1] = {0}; |
| byte_arr_to_hex_string(srvc->sirk, sirk, SIRK_SIZE); |
| set_info += "~SIRK:" + std::string(sirk); |
| |
| if (!srvc->including_srvc_uuid.IsEmpty()) { |
| set_info += "~INCLUDING_SRVC:" + srvc->including_srvc_uuid.ToString(); |
| } |
| |
| if (srvc->lock_handle) { |
| set_info += "~LOCK_SUPPORT:" + std::string((srvc->lock_handle ? "true" : "false")); |
| } |
| |
| if (srvc->rank_handle) { |
| set_info += "~RANK:" + std::to_string(srvc->rank); |
| } |
| |
| set_info += "~SRVC_HANDLE:" + std::to_string(srvc->service_handle); |
| |
| LOG(INFO) << __func__ << " " << set_info; |
| |
| btif_config_set_str(p_cb->addr.ToString().c_str(), |
| "DGroup", set_info.c_str()); |
| } |
| |
| /************************************************************************************ |
| * |
| * Function bta_csip_get_salt |
| * |
| * Description function s1: Used to compute SALT. |
| * |
| * Returns Octet16 (cipher - SALT) |
| ************************************************************************************/ |
| Octet16 bta_csip_get_salt() { |
| Octet16 salt = {}; |
| Octet16 zero = {}; |
| uint8_t SIRKenc[] = {0x53, 0x49, 0x52, 0x4B, 0x65, 0x6E, 0x63}; |
| |
| salt = bta_csip_get_aes_cmac_result(zero, SIRKenc, 7); |
| |
| return salt; |
| } |
| |
| /************************************************************************************ |
| * |
| * Function bta_csip_compute_T |
| * |
| * Description First step of k1 function. Used to compute T from SALT and K. |
| * |
| * Returns Octet16 (cipher - T) |
| ************************************************************************************/ |
| Octet16 bta_csip_compute_T(Octet16 salt, Octet16 K) { |
| Octet16 T = {}; |
| |
| T = bta_csip_get_aes_cmac_result(salt, K); |
| |
| return T; |
| } |
| |
| /************************************************************************************ |
| * |
| * Function bta_csip_get_aes_cmac_result |
| * |
| * Description Second step of k1 function. Used to compute k1 from T and "csis". |
| * |
| * Returns Octet16 (cipher - k1) |
| ************************************************************************************/ |
| Octet16 bta_csip_compute_k1(Octet16 T) { |
| Octet16 k1 = {}; |
| uint8_t csis[] = {0x63,0x73,0x69,0x73}; |
| |
| k1 = bta_csip_get_aes_cmac_result(T, csis, 4); |
| |
| return k1; |
| } |
| |
| /************************************************************************************ |
| * |
| * Function bta_csip_get_aes_cmac_result |
| * |
| * Description sdf function. Used to compute SIRK from encrypted SIRK and k1. |
| * |
| * Returns Octet16 (SIRK) |
| ************************************************************************************/ |
| void bta_csip_get_decrypted_sirk(Octet16 k1, uint8_t *enc_sirk, uint8_t *sirk) { |
| for (int i = 0; i < 16; i++) { |
| sirk[i] = k1[i] ^ enc_sirk[i]; |
| } |
| } |
| |
| /************************************************************************************ |
| * |
| * Function bta_csip_get_aes_cmac_result |
| * |
| * Description Used to get aes-cmac result (for 16 byte input and output |
| * in LSB->MSB order) |
| * |
| * Returns Octet16 (cipher) |
| ************************************************************************************/ |
| Octet16 bta_csip_get_aes_cmac_result(const Octet16& key, const Octet16& message) { |
| Octet16 r_key, r_message, r_result; |
| |
| // reverse inputs as required by crypto_toolbox::aes_cmac |
| std::reverse_copy(key.begin(), key.end(), r_key.begin()); |
| std::reverse_copy(message.begin(), message.end(), r_message.begin()); |
| |
| Octet16 result = crypto_toolbox::aes_cmac(r_key, r_message.data(), r_message.size()); |
| |
| // reverse the result to get LSB->MSB order |
| std::reverse_copy(result.begin(), result.end(), r_result.begin()); |
| |
| return r_result; |
| } |
| |
| /************************************************************************************ |
| * |
| * Function bta_csip_get_aes_cmac_result |
| * |
| * Description Used to get aes-cmac result (for variable input and output |
| * in LSB->MSB order) |
| * |
| * Returns Octet16 (cipher) |
| ************************************************************************************/ |
| Octet16 bta_csip_get_aes_cmac_result(const Octet16& key, const uint8_t* input, |
| uint16_t length) { |
| Octet16 r_key, r_result; |
| |
| // reverse inputs as required by crypto_toolbox::aes_cmac |
| std::reverse_copy(key.begin(), key.end(), r_key.begin()); |
| uint8_t *input_buf = (uint8_t *)osi_malloc(length); |
| for (int i = 0; i < length; i++) { |
| input_buf[i] = input[length - 1 - i]; |
| } |
| |
| Octet16 result = crypto_toolbox::aes_cmac(r_key, input_buf, length); |
| |
| // reverse the result to get LSB->MSB order |
| std::reverse_copy(result.begin(), result.end(), r_result.begin()); |
| |
| return r_result; |
| } |
| |
| /************************************************************************************ |
| * |
| * Function byte_arr_to_hex_string |
| * |
| * Description function used to get hex representation in string format for byte[]. |
| * |
| * Returns void |
| ************************************************************************************/ |
| void byte_arr_to_hex_string(uint8_t* byte_arr, char* str, uint8_t len) { |
| int i; |
| LOG(INFO) << __func__ << " Convert byte array to hex format string"; |
| |
| for (i = 0; i < len; i++) |
| { |
| snprintf(str + (i * 2), (len * 2 + 1), "%02X", byte_arr[i]); |
| } |
| } |
| |
| /************************************************************************************ |
| * |
| * Function hex_string_to_byte_arr |
| * |
| * Description function used to get byte array from hex format string. |
| * |
| * Returns void |
| ************************************************************************************/ |
| void hex_string_to_byte_arr(char *str, uint8_t* byte_arr, uint8_t len) { |
| for (int length = 0; *str; str += 2, length++) |
| sscanf(str, "%02hhx", &byte_arr[length]); |
| } |
| |
| /************************************************************************************ |
| * |
| * Function is_key_empty |
| * |
| * Description function used to check if key is 0 intialized. |
| * |
| * Returns true, if all elements are 0. Otherwise, false. |
| ************************************************************************************/ |
| bool is_key_empty(Octet16& key) { |
| for (unsigned int i = 0; i < key.size(); i++) { |
| if (key[i] != 0) return false; |
| } |
| return true; |
| } |